问题
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:
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);
来源:https://stackoverflow.com/questions/7008561/naudio-algorithm-to-play-a-sinewave-whose-frequency-can-be-changed-smoothly-in-r