I encountered a problem when I tried to generate by a program an sinus audio signal. My parameters are
Sample Rate: 44100 Hz Data Bits: 16 bits Channels: 2
I need to create a WAV file that is generated on the fly in and play in real time directly to a audio out port. There are two more requirements. I need to be able to change Frequency of the sinus signal with the delay of no more than 50 ms. The last requirements are to make any periods of sound and silence with the sinus. For example 100 ms sound and 50 ms of silence or even continuous signal of sound.
I made everything and works but not for all frequencies.
I mean my signal is flawless. It's wave form displayed in audio editing software is perfect. Played through Media Player is perfect. But when I play it on the fly it is producing strange noise, strange "bump" noise at the end of every wave chunk.
The audio signal to be able to change it on the fly or with a maximum delay of 50ms I am creating wave chunks of 50 ms.
When I play it with 200Hz (sinus) and 50 ms buffer it sounds good. But when I change a freq to 201Hz (sinus) and 50 ms buffer it is producing a constant train of "BANG" sounds at the and of every chunk. "BUMP", "BUMP", "BUMP", "BUMP", ...
I think that I made a mistake in discrete domain. Some rounding of values at the end of every chunk. In addition I noticed that the problem is audible on the frequencies that are between every freq. that is not a multiple of number 20.
For example: 200Hz (good), 201, 202, ... 219 (bad), 220 Hz again good and so on.
I really do not understand what's wrong.
Mathematically the only thing about what I can think is some relation between the buffer size of 50ms, Sample Rate of the audio signal and the frequency of sinus.
the numbers:
44100 Hz => 44100 Samples/sec x 50ms (buffer) = 2205 Samples / buffer 200 Hz (sinus) => T = 1/f = 5ms period
50ms (buffer) / 5 ms (sinus period) = 10 sinus waves per buffer
if the freq. is increased: 201 Hz (sinus) => T = 1/f = 4,9751 ms period 50 ms (buffer) / 4,9751 ms = 10,05 sinus waves per buffer
The point is in the second example the last sinus does not fit entirely into a buffer.
I can say that I am filling the next buffer at the exact following point but something still happens. I think that somewhere around this point is a problem.
I need at least a mathematical solution in discrete domain. The best will be a computer code or even pseudo code is fine.
Can somebody be so kind to help me? It is very important to me. Thanks
UPDATE
I tried to use the buffer chunk size of 50 ms and the Sinus frequency of 201 Hz and then used Audacity program to record the audio in real time. Very strange things are happening. at 100 ms and 200 ms are spikes at 300 is not, at 400, 450, 500, 550, 600 ms are other spikes. 650 is good as it must be, 700 is too, 750 again not, 800 spike ... then at 1000 ms is a different spike. I rely do not understand why is this happening. Maybe some calculation... Some rounding problems.
I will put only a part of the code used. Complete code is very big. It consists of producer thread and consumer thread + the Wave out player internal thread. In between is a queue to not used to have constant flow between produce and consumer (player). So at least this is satisfied.
These are the critical parts of the code.
format.dwSamplesPerSec = 44100
format.wChannels = 2
format.wBitsPerSample = 16
int minAudioChunk = 50; // in milliseconds
data.dwChunkSize = (uint)(data.shortArray.Length * (format.wBitsPerSample / 8));
volume = (double)(Volume / 100.0f);
// Number of samples = sample rate * channels * bytes per sample
uint numSamples = (uint)(format.dwSamplesPerSec * format.wChannels * ((double)minAudioChunk / 1000));
// Initialize the 16-bit array
data.shortArray = new short[numSamples];
// Max amplitude for 16-bit audio
amplitude = (int)(MAX_AMPLITUDE_16BIT * volume);
// Create a double version of the frequency for easier math
double freq = (double)frequency;
// The "angle" used in the function, adjusted for the number of channels and sample rate.
// This value is like the period of the wave.
t = (Math.PI * 2 * freq) / (format.dwSamplesPerSec * format.wChannels);
value = amplitude * Math.Sin(t * i);
// Fill with a simple sine wave at max amplitude
for (int channel = 0; channel < format.wChannels; channel++)
{
data.shortArray[bufferIndex + channel] = (short)value;
}
bufferIndex goes from 0 ... (numSamples-1)