Author Topic: C# Generating tones almost workst, but creates strange 'clicks'  (Read 2179 times)

Koen

  • Guest
First of all I want to make a huge compliment to the BASS project and its .NET port! Great work :)!

My question is about generating tones. My code almost works. It generates the requested tone, but the tone is not 'clear', it contains lots of 'clicks' and 'ticks' (hard to describe) but it just doesn't sounds good.

My code is (inspired by several examples on this forum):
Code: [Select]
private STREAMPROC _toneStreamCreator;  // declare it as a global member, so that the Garbage Collector can not steal it
private short[] _data; // local data buffer
int _toneStream;
int _toneFreq = 440;

// implementing a callback for BASS_StreamCreate...
private int MyStreamCreator(int handle, IntPtr buffer, int length, int user)
{
if (length == 0 || buffer == IntPtr.Zero)
return length;

// length is in bytes, so the number of floats to process is length / 4 (byte = 8-bit, float = 32-bit)
int l2 = length/2;

// increase the data buffer as needed (assumes that the variable _data is declared outside)
if (_data == null || _data.Length < l2)
_data = new short[l2];

// copy from unmanaged to managed memory
Marshal.Copy(buffer, _data, 0, l2);

double sin = 0;
//Marshal.Copy(buffer, _data, 0, length);

for (int c = 0; c < l2; c++)
{
_data[c] = (short) Math.Round(30000 * Math.Sin(sin));
//_data[2*c + 1] = _data[c];

sin += _toneFreq * 2 * Math.PI / 44100;
sin = sin % (2 * Math.PI);
}

// copy data from managed to unmanaged memory
Marshal.Copy(_data, 0, buffer, l2);

return length;
}

void PlayTone(int freq)
{
_toneFreq = freq;
_toneStreamCreator = new STREAMPROC(MyStreamCreator);
_toneStream = Bass.BASS_StreamCreate(44100, 2, BASSStream.BASS_SAMPLE_LOOP, _toneStreamCreator, 0);

//Bass.BASS_ChannelSetAttributes(_toneStream, 0, -1, -100);
Bass.BASS_ChannelPlay(_toneStream, false); // play the sample

return;

}

Maybe it is an error in rounding the sine wave? Does anyone has a suggestion?

radio42

  • Posts: 4839
I am not really into tone generation...but just a few side notes...

a) the first call to "Marshal.Copy(buffer, _data, 0, l2);" seems to be not needed, since in you callback you just need to fill the buffer for BASS, so you don't need to copy the data from bass first...

b) In your for-loop you set different values for the left and the right channel
(each short value in the buffer will alter left, richt, left, right, since you setup 2 channels)
So may be this would help:
Code: [Select]
for (int c = 0; c < l2/2; c++)
{
    _data[2*c] = (short) Math.Round(30000 * Math.Sin(sin));
    _data[2*c + 1] = _data[2*c];
    ...
}

Koen

  • Guest
radio42: you are correct, however, that was not the only problem.

The problem was the 'sin' variable. It should be declared private within the class, and not as a local variable. Changing this solved the problem.

So: add
Code: [Select]
private double _sin = 0;To the class and set _sin back to zero before the tone is being generated. NOT in the callback!!