changeset 576:f0da2404108c

Merge
author Chris Cannam
date Tue, 20 May 2014 13:39:22 +0100
parents af8ecd7866cd (diff) f9e557d6ac2f (current diff)
children 514299fc8751
files
diffstat 6 files changed, 51 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/may/stream/audiofile.yeti	Tue May 13 18:50:27 2014 +0100
+++ b/src/may/stream/audiofile.yeti	Tue May 20 13:39:22 2014 +0100
@@ -156,6 +156,8 @@
 //!!! no, the header size is included in the return value!
     n / (channels * bitdepth));
 
+//!!! todo: io module style openWith
+
 {
     open,
     openMono,
--- a/src/may/stream/format.yeti	Tue May 13 18:50:27 2014 +0100
+++ b/src/may/stream/format.yeti	Tue May 20 13:39:22 2014 +0100
@@ -29,12 +29,12 @@
     done
    );
 
-decodeFail () = 
-    throw new UnsupportedAudioFileException("Audio format not supported. Supported formats are 8-bit unsigned PCM, 16-bit signed little-endian PCM, or IEEE float");
+decodeFail f is ~AudioFormat -> () = 
+    throw new UnsupportedAudioFileException("Audio format \"\(f#toString())\" not supported. Supported formats are 8-bit unsigned PCM, 16-bit signed little-endian PCM, or IEEE float.");
 
 decode { format is ~AudioFormat } bytes doubles n = 
    (if format#isBigEndian() then
-        decodeFail()
+        decodeFail format;
     else
         enc = format#getEncoding();
         bits = format#getSampleSizeInBits();
@@ -45,7 +45,7 @@
         elif bits == 8 and enc == AudioFormat$Encoding#PCM_UNSIGNED then
             decode8u bytes doubles n;
         else
-            decodeFail();
+            decodeFail format;
         fi
     fi);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/may/stream/readall.yeti	Tue May 20 13:39:22 2014 +0100
@@ -0,0 +1,26 @@
+
+module may.stream.readall;
+
+load may.stream.type;
+
+mat = load may.matrix;
+af = load may.stream.audiofile;
+
+readAll stream = 
+    case stream.available of
+    Known n: stream.read n;
+    _: failWith "Cannot readAll from infinite or unknown-duration stream";
+    esac;
+
+//!!! todo: use openWith (when available!)
+readAllFrom filename =
+   (str = af.open filename;
+    mat = readAll str;
+    str.close ();
+    mat);
+
+{
+    readAll is stream_t -> mat.matrix_t,
+    readAllFrom is string -> mat.matrix_t, 
+}
+
--- a/src/may/stream/syntheticstream.yeti	Tue May 13 18:50:27 2014 +0100
+++ b/src/may/stream/syntheticstream.yeti	Tue May 20 13:39:22 2014 +0100
@@ -43,8 +43,20 @@
         result);
     generated sampleRate generator);
 
+/**
+ * Generate a white noise stream with a maximum amplitude of 0.5.
+ * 
+ * This is limited to 0.5 rather than 1.0 to help avoid
+ * situations in which subsequent processing causes hard-to-spot
+ * clipping. For example, filtering noise to limit its bandwidth
+ * may increase the levels of some samples: if you do this naively
+ * and then export the result to an audio file, it will clip and
+ * the resulting noise will be neither correctly distributed nor
+ * band-limited. But because individual samples are random, it's
+ * very easy to miss what is happening.
+ */
 whiteNoise sampleRate =
-    generated sampleRate \((Math#random() * 2.0) - 1.0);
+    generated sampleRate \((Math#random() * 1.0) - 0.5);
 
 silent sampleRate =
     generated sampleRate \0;
--- a/src/may/stream/test/test_waves.yeti	Tue May 13 18:50:27 2014 +0100
+++ b/src/may/stream/test/test_waves.yeti	Tue May 20 13:39:22 2014 +0100
@@ -36,7 +36,7 @@
         compare str.sampleRate 8 and
         compare str.available (Infinite ()) and
         compare str.finished? false and
-        compareApprox epsilon (vec.list (mat.getRow 0 (str.read 9))) [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ] and
+        compareApprox epsilon (vec.list (mat.getRow 0 (str.read 9))) [ 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5 ] and
         compare str.position 9
 ),
 
@@ -49,7 +49,7 @@
         compare str.sampleRate 10 and
         compare str.available (Infinite ()) and
         compare str.finished? false and
-        compareApprox epsilon (vec.list (mat.getRow 0 (str.read 11))) [ 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 ] and
+        compareApprox epsilon (vec.list (mat.getRow 0 (str.read 11))) [ 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0 ] and
         compare str.position 11
 ),
 
@@ -66,7 +66,7 @@
         compare str.available (Infinite ()) and
         compare str.finished? false and
         compareApprox epsilon (vec.list (mat.getRow 0 (str.read 14)))
-            [ 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0 ] and
+            [ 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0 ] and
         compare str.position 14
 */
 ),
--- a/src/may/stream/waves.yeti	Tue May 13 18:50:27 2014 +0100
+++ b/src/may/stream/waves.yeti	Tue May 20 13:39:22 2014 +0100
@@ -54,7 +54,8 @@
 // Bandlimited impulse train: produce naive pulse train at a frequency
 // that is an integer fraction of the sample rate (so as to have exact
 // sample locations), then resample so as to place the impulses at the
-// requested frequency
+// requested frequency. The maximum sample is 0.5 rather than 1 to
+// avoid clipping in further manipulation.
 impulseTrain sampleRate freq =
     if freq > sampleRate/2 then
         failWith "Can't generate impulse train with frequency > half the sample rate (\(freq) > \(sampleRate)/2)"
@@ -62,7 +63,7 @@
         naiveTrain f =
            (spacing = int (sampleRate / f);
             generated sampleRate
-                do n: if n % spacing == 0 then 1 else 0 fi done);
+                do n: if n % spacing == 0 then 0.5 else 0 fi done);
         ratio = sampleRate / freq;
         if ratio == int ratio then
             naiveTrain freq