# HG changeset patch # User Chris Cannam # Date 1398940574 -3600 # Node ID 3b07478932a12411d9f0e2ffc5c31f5122048f8a # Parent c5afeb185539aed7d4205e7157435f42be5c51b3 Add sweeps and time-varying sinusoids diff -r c5afeb185539 -r 3b07478932a1 src/may/mathmisc.yeti --- 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, } diff -r c5afeb185539 -r 3b07478932a1 src/may/stream/syntheticstream.yeti --- 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, diff -r c5afeb185539 -r 3b07478932a1 src/may/stream/waves.yeti --- 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, }