changeset 562:3b07478932a1

Add sweeps and time-varying sinusoids
author Chris Cannam
date Thu, 01 May 2014 11:36:14 +0100
parents c5afeb185539
children 8c1b62eb33c7
files src/may/mathmisc.yeti src/may/stream/syntheticstream.yeti src/may/stream/waves.yeti
diffstat 3 files changed, 43 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/may/mathmisc.yeti	Wed Apr 30 13:32:14 2014 +0100
+++ b/src/may/mathmisc.yeti	Thu May 01 11:36:14 2014 +0100
@@ -80,5 +80,6 @@
     isPowerOfTwo,
     nextPowerOfTwo,
     random,
+    eps = 1e-15,
 }
 
--- a/src/may/stream/syntheticstream.yeti	Wed Apr 30 13:32:14 2014 +0100
+++ b/src/may/stream/syntheticstream.yeti	Thu May 01 11:36:14 2014 +0100
@@ -7,9 +7,14 @@
 
 load may.stream.type;
 
+/**
+ * Generate a stream using a generator function. The generator takes
+ * a sample index and returns a number in the range -1,+1. The
+ * generator is guaranteed to be called with sample indices in order
+ * 0,1,2,... so it may maintain state between calls if desired.
+ */   
 generated sampleRate generator =
-   (// generator takes sample number as arg, returns number in -1,+1 range
-    var position = 0;
+   (var position = 0;
     {
         get position () = position,
         get channels () = 1, 
@@ -29,6 +34,15 @@
 sinusoid sampleRate freq =
     generated sampleRate (sin . (* (2 * pi * freq / sampleRate)));
 
+varyingSinusoid sampleRate freqGenerator =
+   (var phase = 0;
+    generator i =
+       (ifreq = freqGenerator i;
+        result = sin phase;
+        phase := phase + 2 * pi * ifreq / sampleRate;
+        result);
+    generated sampleRate generator);
+
 whiteNoise sampleRate =
     generated sampleRate \((Math#random() * 2.0) - 1.0);
 
@@ -113,6 +127,7 @@
     precalculatedMono is number -> vec.vector_t -> stream_t,
     precalculatedRepeated is number -> mat.matrix_t -> stream_t,
     sinusoid is number -> number -> stream_t, 
+    varyingSinusoid is number -> (number -> number) -> stream_t,
     whiteNoise is number -> stream_t,
     silent is number -> stream_t,
     empty is number -> number -> stream_t,
--- a/src/may/stream/waves.yeti	Wed Apr 30 13:32:14 2014 +0100
+++ b/src/may/stream/waves.yeti	Thu May 01 11:36:14 2014 +0100
@@ -5,10 +5,10 @@
 module may.stream.waves;
 
 { sinusoid, generated } = load may.stream.syntheticstream;
-{ sum, scaledBy } = load may.stream.manipulate;
-{ precalculatedRepeated } = load may.stream.syntheticstream;
+{ sum, scaledBy, withDuration } = load may.stream.manipulate;
+{ precalculatedRepeated, varyingSinusoid } = load may.stream.syntheticstream;
 { resampledTo } = load may.stream.resample;
-{ gcd, floor, ceil } = load may.mathmisc;
+{ gcd, floor, ceil, log10, pow, eps } = load may.mathmisc;
 
 load may.stream.type;
 
@@ -75,6 +75,27 @@
         fi;
     fi;
 
+//!!! todo: test. How?
+sineSweep sampleRate { startFrequency, endFrequency, duration, logarithmic } =
+   (forward = 
+        if logarithmic then
+            do x: log10 if x < eps then eps else x fi done
+        else id
+        fi;
+    inverse =
+        if logarithmic then pow 10
+        else id
+        fi;
+    a = forward startFrequency;
+    b = forward endFrequency;
+    withDuration duration
+       (varyingSinusoid sampleRate
+            do i:
+                dist = i / duration;
+                inverse (a + (b - a) * dist);
+            done)
+    );
+
 cached f sampleRate freq =
    (n = cycleLengthFor sampleRate freq;
     if n == 0 then
@@ -96,6 +117,7 @@
     saw is number -> number -> stream_t, 
     triangle is number -> number -> stream_t,
     impulseTrain is number -> number -> stream_t,
+    sineSweep is number -> { startFrequency is number, endFrequency is number, duration is number, logarithmic is boolean } -> stream_t,
     cycleLengthFor is number -> number -> number,
 }