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.

  • 2
    $\begingroup$ Why didn't you just used the linear frequency transition over the transition period. For example, you need to transit from frequency f0 at time t0 to frequency f1 at time t1, then why not just introduce a transition frequency f(t)=f0*(1-q)+f1*q, where q=(t-t0)/(t1-t0), then produce a signal A(t)=sin(2*Pi*f(t)*t)? $\endgroup$ – mbaitoff Jan 9 '12 at 7:53

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


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.

  • $\begingroup$ thanks, I was expecting that the answer might involve LUTs. I was thinking of going with a LUT that contains one waveform at 1Hz (i.e. Fs entries). Is there a rule of thumb governing the optimal size of the LUT? $\endgroup$ – Mark Heath Dec 16 '11 at 10:13
  • 4
    $\begingroup$ It depends on various factors: what SNR you are looking for, whether it's a pure sine wave or a more complex waveform, whether you plan to interpolate between adjacent LUT entries or just truncate, etc. It also depends on whether you are just going to have a single quadrant table and handle the indexing arithmetic and sign inversion yourself, or have a full four quadrant table. Personally I would start with a 1024 point (NB: 2^N is good for modulo indexing) four quadrant table with no interpolation as this is very simple and should give good results for e.g. 16 bit "consumer" audio. $\endgroup$ – Paul R Dec 16 '11 at 10:42
  • 1
    $\begingroup$ Good answer, Paul. There's also a similar question on the topic that was posted a while back; more info always helps. $\endgroup$ – Jason R Dec 16 '11 at 15:01
  • 4
    $\begingroup$ Another way of looking at this approach is an emulation of a voltage-controlled oscillator (VCO). The output frequency of a VCO depends on the input voltage (usually a linear function of input voltage) but the output signal has continuous phase even if the input voltage switches instantaneously. The output is $$\sin(\phi(t)) = \sin\left(\int_0^{t}\omega_0 + k\cdot x(\tau)\mathrm d\tau \right)$$ where $\phi(t)$ is a continuous function of time, while the output frequency is the derivative of the phase, and equals $$\omega_0 + k\cdot x(t)$$ where $\omega_0$ is the quiescent frequency. $\endgroup$ – Dilip Sarwate Dec 16 '11 at 16:54
  • 1
    $\begingroup$ I had the same problem, thanks for the accumulator idea (I was using direct calculation, which didn't work because of approximations) : jsfiddle.net/sebpiq/p3ND5/12 $\endgroup$ – sebpiq Mar 31 '12 at 18:36

One of the best ways to create a sine wave is to use a complex phasor with recursive updating. I.e.

$$z[n+1] = z[n]\Omega$$

where z[n] is the phasor, $\Omega = \exp(j\omega)$, with $\omega$ being the angular frequency of the oscillator in radians and $n$ the sample index. Both real and imaginary part of $z[n]$ are sine waves, they are 90 degrees out of phase. Very convenient if you need both sine and cosine. A single sample calculation only requires 4 multiples and 4 adds and is MUCH cheaper than anything containing sin() cos() or lookup tables. The potential problem is that the amplitude may drift over time due to numerical precision issues. However there is a fairly straight forward to repair that. Let's say that $z[n] = a + jb$. We know that $z[n]$ should have unity magnitude, i.e.

$$a\cdot a + b\cdot b = 1$$

So we can check every once in a while if that is still the case and correct accordingly. The exact correction would be

$$z'[n] = \frac{z[n]}{\sqrt{a\cdot a + b\cdot b}}$$

That is an awkward calculation but since $a\cdot a + b\cdot b$ is very close to unity you can approximate the $1/\sqrt{x}$ terms with a Taylor expansion around $x = 1$ and we get

$$\frac{1}{\sqrt{x}} \cong \frac{3-x}{2}$$

so the correction simplifies to

$$z'[n] = z[n]\frac{3-a^2-b^2}{2}$$

Applying this simple correction every few hundred samples will keep the oscillator stable forever.

To vary the frequency continuously the multiplier W needs to be updated accordingly. Even a non-continuous change in the multiplier will maintain a continuous oscillator function. If frequency ramping is required the update can either be broken down into a few steps or you can use the same oscillator algorithm to update the multiplier itself (since it's also a unity gain complex phasor).

  • $\begingroup$ thanks for this answer, will probably take me a little while to understand well enough to turn into some real world code, but it looks like an interesting alternative to try. $\endgroup$ – Mark Heath Jan 6 '12 at 18:54
  • 2
    $\begingroup$ I implemented this solution in golang for reference: github.com/rmichela/Acoustico/blob/… $\endgroup$ – Ryan Michela Mar 12 '17 at 8:12
  • $\begingroup$ This is a beautiful solution that, unfortunately, only works well if using a constant time base. If not, you need to compute a sin and a cos to compute the correct complex rotation. $\endgroup$ – Cameron Tacklind Nov 16 '19 at 21:51
  • $\begingroup$ A beautiful solution and explanation that surely deserves many more upvotes. I wonder if anybody knows of any C/C++ libraries that implement this oscillator? All library's that I've found use wavetables or other direct sine approximations. $\endgroup$ – sircolinton Dec 9 '19 at 19:38

From this site:

In order to create a smooth transition from one frequency to another or one amplitude to another, an incomplete sine wave must be modified with an appended section so that the resulting wave after each iteration of the while loop ends at the x-axis.

Sounds like it should work.

(Actually, if they are both synchronized at the x-axis upon transition, I suppose a gradual transition isn't necessary.)

  • 1
    $\begingroup$ This says, wait for the current sinusoid at frequency $\omega_0$ to complete one cycle and arrive at $0$ and then switch to the other sinusoid at frequency $\omega_1$. This effectively maintains the continuity of phase and is likely to be OK for audio applications in which the few milliseconds or microseconds delay between the desired switch time (now) and the implemented switch time (when my sinusoid completes a cycle) is inconsequential. However, the difference might give trouble in other applications. Just remember a sinusoid is $0$ twice in one cycle and be sure to pick the right one! $\endgroup$ – Dilip Sarwate Dec 17 '11 at 2:48

I agree with the previous suggestions of using a phase accumulator. Essentially the control input is the amount of phase advance per step or per clock period (or per interrupt or whatever), so that changing that value changes the frequency without a discontinuity in the phase. The wave amplitude is then determined from the accumulated phase value either via a LUT or just computation of sin(theta) or cos(theta).

This is essentially what is commonly known as a Numerically Controlled Oscillator (NCO) or a Direct Digital Synthesizer (DDS). Doing a web search on those terms will probably yield more than you want to know on the theory and practice of making them work well.

Adding an additional accumulator can allow seamless transitions between frequencies, as you suggested, if that's desired as well, by controlling the rate of change of the phase advance value. This is sometimes called a Digital Differential Analyzer, or DDA.

  • $\begingroup$ Good additional information. Glad to see you around here, Eric; we could use a Minister of Algorithms. $\endgroup$ – Jason R Dec 31 '11 at 1:29

1st order, you should adjust the starting phase of the new frequency sinusoid so that it is the same as what would be the phase of the previous sinusoid at the 1st transition sample point. Compute the first frequency and use its phase for the second frequency.

2nd option might be to ramp d_phase from that of one frequency to the next over several samples. This will clean up the continuity of the 1st derivative and provide a glide.

3rd option might be to use a smoothing window, such as a raised-cosine, on the d_phase ramping rate.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.