NAudio Algorithm to play a sinewave whose frequenc

2019-03-17 00:00发布

So far, I have implemented the algorithm found on this blog post with limited success.

The concept of my program is to initialize the sinewave, then change the frequency according to the position of the mouse on screen - move the mouse up and the sine wave gets higher and vice versa (essentially a theremin-type instrument using the mouse).

The problem with what I've implemented so far is that when the frequency of the sine wave is updated, there is an audible click, which instead of providing the smooth frequency sweep, makes it sound like there are discrete frequency levels. I have been searching high and low on NAudio forums and on here, but it doesn't seem like there's anyone else trying to do this kind of thing using NAudio, or for that matter any other sound module - all of the similar programs that perform similarly using equipment like the Kinect use virtual midi cabling and an existing software module, but I would like to implement the same concept without relying on external software packages.

I have posted the section of my code pertaining to this issue on NAudio's forum here and as you can see, I'm following through MarkHeath's recommendation on here to attempt to find a solution to my problem.

1条回答
你好瞎i
2楼-- · 2019-03-17 00:50

You need to avoid discontinuities in the output waveform (these are the clicks you are hearing). The easiest way to do this is with a LUT-based waveform generator - this works for any periodic waveform (i.e. not just pure sine waves). Typically you use a fixed point phase accumulator, which is incremented for each new sample by a delta value which corresponds to the current output frequency. You can safely modify delta however you like and the waveform will still be continuous.

Pseudo code (for one output sample):

const int LUT_SIZE;
const int LUT[LUT_SIZE];  // waveform lookup table (typically 2^N, N >= 8)
Fixed index; // current index into LUT (integer + fraction)
Fixed delta; // delta controls output frequency

output_value = LUT[(int)index];
    // NB: for higher quality use the fractional part of index to interpolate
    //     between LUT[(int)index] and LUT[(int)index + 1], rather than just
    //     truncating the index and using LUT[(int)index] only. Depends on both
    //     LUT_SIZE and required output quality.
index = (index + delta) % LUT_SIZE;


Note: to calculate delta for a given output frequency f and a sample rate Fs:

delta = FloatToFixed(LUT_SIZE * f / Fs);
查看更多
登录 后发表回答