I am able to write a basic sine wave generator for audio, but I want it to be able to smoothly transition from one frequency to another. If I just stop generating one frequency and immediately switch to another there will be a discontinuity in the signal and a "click" will be heard.
My question is, what is a good algorithm to generate a wave that starts at, say 250Hz, and then transitions to 300Hz, without introducing any clicks. If the algorithm includes an optional glide/portamento time, then so much the better.
I can think of a few possible approaches such as oversampling followed by a low pass filter, or maybe using a wavetable, but I am sure this is a common enough problem that there is a standard way of tackling it.
Answer
One approach that I have used in the past is to maintain a phase accumulator which is used as an index into a waveform lookup table. A phase delta value is added to the accumulator at each sample interval:
phase_index += phase_delta
To change frequency you change the phase delta that is added to the phase accumulator at each sample, e.g.
phase_delta = N * f / Fs
where:
phase_delta is the number of LUT samples to increment
freq is the desired output frequency
Fs is the sample rate
This guarantees that the output waveform is continuous even if you change phase_delta dynamically, e.g. for frequency changes, FM, etc.
For smoother changes in frequency (portamento) you can ramp the phase_delta value between its old value and new value over a suitable number of samples intervals rather than just changing it instantaneously.
Note that phase_index
and phase_delta
both have an integer and a fractional component, i.e. they need to be floating point or fixed point. The integer part of phase_index (modulo table size) is used as an index into the waveform LUT, and the fractional part may optionally be used for interpolation between adjacent LUT values for higher quality output and/or smaller LUT size.
No comments:
Post a Comment