How to gradually increase or decrease an FMSound frequency over time?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

How to gradually increase or decrease an FMSound frequency over time?

Rob Rothwell
Maybe someone can point me in the right direction...

I am trying to figure out how to gradually change the frequency of an FMSound over time, for example a gradual slide from, say, 99.12Hz to 109.56Hz over a given amount of time (sort of like a very slow Doppler shift in a way, I guess).  The actual function governing the frequency change could in theory be just about anything, but for now I am probably just looking at linear slides, and the length of time the slide could take could be seconds to minutes.

I still consider myself a Smalltalk beginner, and my first instinct is always to "do it myself" because I have a hard time reading the existing code to figure out what has already been done.  Thus, my first idea was to try to output small segments (say 1 sec each) of a fixed frequency into a SequentialSound, and increase the frequency [of each segment] over time.   This  "works," but with the fractional cycles inherent in non-integral frequencies and/or times it results in a sharp transient at the junction of each new frequency segment--resulting in unwanted audible clicks.

Is there a way to "manually" adjust the phase of each subsequent SequentialSound so I can "line them up," or will the PitchEnvelope class completely take care of this for me and I just can't figure it out?!

Overall, though, I have to say I am impressed with the depth of the classes in the Sound-Synthesis category, I just don't know how to use them!  However, I am guessing  that Squeak knows how to do exactly what I want to do!

Thanks in advance for any help;  I still have a hard time knowing if I am even looking in the right direction.  I hope I explained the problem well enough--a picture would have been easier in this case!

Thanks again,

Rob Rothwell

P.S.  If the answer is at all related to how I would fade the volume of a sound in or out over 15 to 30 seconds, could you let me know?


Reply | Threaded
Open this post in threaded view
|

Re: How to gradually increase or decrease an FMSound frequency over time?

ccrraaiigg

        Just send >>pitch: to the FMSound at the appropriate times, sweeping
between your two values?


-C

--
Craig Latta
improvisational musical informaticist
www.netjam.org
Smalltalkers do: [:it | All with: Class, (And love: it)]



Reply | Threaded
Open this post in threaded view
|

Re: How to gradually increase or decrease an FMSound frequency over time?

Rob Rothwell
In reply to this post by Rob Rothwell
Craig,

Thanks for your reply:

>       Just send >>pitch: to the FMSound at the appropriate times, sweeping
>between your two values?

 I had thought of doing that, but I was hoping that I could end up at a specific frequency at a specific time.  However, for my purposes, the frequencies are more important to me than the times, so that may be what I end up doing.

Basically, I am trying to use Squeak to generate Binaural Beat Sequences for brainwave entrainment.  A Binaural Beat basically consists of a beat@carrier frequency pair, so I want to be able to write something like:

     sequence := BinauralSequence new.
     sequence to: [hidden email] for: 2.75 minutes.
     sequence to: [hidden email] over: 15 seconds for: 2.75 minutes.
     etc...
    
...and have it produce the desired effect, which in this case would be produce a beat frequency of 10.00Hz around a center carrier frequency of 109.65Hz (104.65 Left pan and 114.65 Right pan) for 2.75 minutes, then slide the beat and carrier frequency to [hidden email] over 15 seconds, hold for another 2.75 minutes, etc...

The BinauralSequence would just be a part of a BinauralProgram, which would basically create a MixedSound with background sounds (rain, babbling brook, etc...) mixed in as desired, fade in and out as necessary, etc...

While there are available tools to do this, it is either difficult or time consuming to tell the tool what you want it to do, and the natural message format of Smalltalk would just be perfect for this!

However, for the time being, maybe I'll have the times in the above example be more of a request than a command, and fudge the time to keep the frequencies in phase and avoid any clicks or pops...

I still think it would be fun to know how to phase shift a wave form in Squeak, though, and I still have to figure out how to fade in and out, but other than that, it's really pretty straightforward in Squeak once you start getting used to the classes!

Thanks again,

Rob


Reply | Threaded
Open this post in threaded view
|

Re: How to gradually increase or decrease an FMSound frequency over time?

Hans-Martin Mosner
Rob Rothwell wrote:

> Craig,
>
> Thanks for your reply:
>
> >       Just send >>pitch: to the FMSound at the appropriate times,
> sweeping
> >between your two values?
>
>  I had thought of doing that, but I was hoping that I could end up at
> a specific frequency at a specific time.  However, for my purposes,
> the frequencies are more important to me than the times, so that may
> be what I end up doing.
>
> Basically, I am trying to use Squeak to generate Binaural Beat
> Sequences for brainwave entrainment.  A Binaural Beat basically
> consists of a beat@carrier frequency pair, so I want to be able to
> write something like:

Have you looked at the PitchEnvelope class? It allows you to sweep a
sound between frequencies.
You would need to take into account that it's working on a logarithmic
scale, so it does not interpolate frequencies linearly, but musical
notes. In many cases this would be the desired behaviour, I don't know
enough about your application to say whether it is acceptable here as well.

Cheers,
Hans-Martin

Reply | Threaded
Open this post in threaded view
|

Re: How to gradually increase or decrease an FMSound frequency over time?

Rob Rothwell
Here is essentially what I want to do, which gives a "smooth" (stepped) progression from f1 to f2.  stepsPerSecond sort of controls the "smoothness" of the progression.

    f1 := 330.50.
    f2 := 440.90.
    f := f1.
    t := 0.
    sec := 15.
    stepsPerSecond := 10.0.    
    df := (f2-f1) / (sec*stepsPerSecond).
    ss := SequentialSound new.
    f := f-df.

"   Sweep smoothly from f1 to just shy of f2 over the specified time, re-calculating the amount of time for each step
    based on the integral number of frequencies that can be completed within the estimated step size.
    We should end up just shy of the target frequency, at the end of a complete cycle..."

    1 to: (sec*stepsPerSecond) do: [
        :i |
        dt := (((i asFloat)/stepsPerSecond)-(t asFloat)).
        f := (f + df).
        cycles := (f*dt) roundTo: 1.0.
        dt := cycles / f.
        Transcript show: f; tab; show: dt; cr.
        ss add: (FMSound new setPitch: f dur: dt loudness: 0.5).
        t := t + dt.
    ].       

"   Add the the final frequency and play it briefly..."
    Transcript show: f2; cr.
     ss add: (FMSound new setPitch: f2 dur: 1.0 loudness: 0.5).

    ss storeWAVOnFileNamed: 'test.wav'.   
    ss play.

I would do something similar with the times if I wanted to "step" sharply from one frequency to another without the slide, but without introducing an audible "click."  Basically I just need to make sure that the transition from one frequency to another happens on an integral number of wave cycles.

However, this seems somewhat inelegant given the apparent richness of the sound classes.  It *feels* like I am doing something "by hand" that is probably already built into the system.  It seems like the PitchEnvelope class *should* work, if I understood it better!  Furthermore, without understanding the VolumeEnvelope class, I would do something like the above to fade-in and fade-out, changing volume levels instead of frequencies.

Thanks,
Rob

On 4/20/06, Hans-Martin Mosner <[hidden email]> wrote:

>Have you looked at the PitchEnvelope class? It allows you to sweep a
>sound between frequencies.
>You would need to take into account that it's working on a logarithmic
>scale, so it does not interpolate frequencies linearly, but musical
>notes. In many cases this would be the desired behaviour, I don't know
>enough about your application to say whether it is acceptable here as well.
>
>Cheers,
>Hans-Martin



Reply | Threaded
Open this post in threaded view
|

Re: How to gradually increase or decrease an FMSound frequency over time?

Hans-Martin Mosner
Rob Rothwell wrote:

> Here is essentially what I want to do, which gives a "smooth"
> (stepped) progression from f1 to f2.  stepsPerSecond sort of controls
> the "smoothness" of the progression.
>
>     f1 := 330.50.
>     f2 := 440.90.
>     f := f1.
>     t := 0.
>     sec := 15.

...
Here's a version with PitchEnvelope, which is really smooth and much
less complicated:
    f1 := 330.50.
    f2 := 440.90.
    sec := 15.
    envelope := (PitchEnvelope
            points: (Array
                with: 0 @ 1
                with: sec*1000 @ ((f2*2 / f1) log / 2 log))
            loopStart: 2 loopEnd: 2)
            centerPitch: f1.
    (FMSound new setPitch: f1 dur: sec loudness: 0.5)
        addEnvelope: envelope;
        play

Note that due to the logarithmic pitch slope, the frequency at t=7.5 is
381.73 and not 385.70.
You should really experiment with PitchEnvelope a little more (and
VolumeEnvelope for fade-in/fade-out).
I'm certain that you can achieve your goals with it.
When adding more slope points to the envelope, always remember to set
loopStart and loopEnd to the size of the points array, as you don't want
to have a looping part.

Cheers,
Hans-Martin

Reply | Threaded
Open this post in threaded view
|

Re: How to gradually increase or decrease an FMSound frequency over time?

Rob Rothwell
On 4/21/06, Hans-Martin Mosner <[hidden email]> wrote:

>You should really experiment with PitchEnvelope a little more (and
>VolumeEnvelope for fade-in/fade-out).
>I'm certain that you can achieve your goals with it.
>When adding more slope points to the envelope, always remember to set
>loopStart and loopEnd to the size of the points array, as you don't want
>to have a looping part.

>Cheers,
>Hans-Martin

Thanks for the great example.  With very low frequencies, you can edit the WAV file and really see how well it works.  I knew Squeak could do this!  Now I'm going to try to understand what it is actually doing.  As you suggested, I am definitely going to try to understand the Envelope classes.  From your explanation of loopStart and loopEnd, I guess you just add more slope points to the envelope, and then you can create a "series" of constant and/or changing frequencies.

Thanks again for all your help.  Maybe someday I'll understand something enough to help somebody else out!

Rob


Reply | Threaded
Open this post in threaded view
|

Re: How to gradually increase or decrease an FMSound frequency over time?

Simon Michael