Original Post
What I'm trying to do something simple, and indeed I even got it to work almost, but not quite, well enough... Here's the deal: I'm filling a sample buffer of size 882 floats, and every 20 milliseconds I convert this 882 floats to a byte buffer of size 882 * 4 * 2 (2 = number of channels) and submit it to Xaudio 2 play. As you can see, the sample rate is therefore 44100 (882 * 50 {50 times in one second}). In another thread (I presume Xaudio2 is running in a different thread?), I have a render loop that needs to be executed every 20 milliseconds or so, which is incidentally the rate at which I push the buffer to audio. So theoretically, I should be able to push the 20ms worth of audio data to xaudio2, wait for it to finish playing and then render. Repeat ad infinitum. Here's the code I've come up with: In the main loop, I simply block till buffer finishes playing: while (!sm.FinishedPlaying()) { } My expectation was that for 882*4*2 samples it would take 20ms to play, then set isPlaying to false in the BufferEnd event, and then my render loop would therefore be synchronized to ~50 frames per second. Unfortunately, I find that the frame rate is much greater than 50 and both sound and video fairly whizz along! So then, could someone point out where I've gone wrong in my assumptions or in my code and how to fix it?
public class SoundManager
{
const int BUFFER_COUNT = 1;
private XAudio2 device;
private MasteringVoice masteringVoice;
private SourceVoice sourceVoice;
private WaveFormat waveFormat;
private int bytesPerSample;
private AudioBuffer buffer;
float[] sampleData = new float[882];
byte[] bData = new byte[882 * 4 * 2];
int currentBuffer = 0;
int samplePos = 0;
private bool isPlaying = false;
public SoundManager(IntPtr handle, short BitsPerSample, short Channels, int SamplesPerSecond)
{
WaveFormat format = new SlimDX.Multimedia.WaveFormat();
format.BitsPerSample = BitsPerSample; //32
format.Channels = Channels; //2
format.SamplesPerSecond = SamplesPerSecond; //44100
format.BlockAlignment = (short)(format.Channels * format.BitsPerSample / 8);
format.AverageBytesPerSecond = format.SamplesPerSecond * format.BlockAlignment;
format.FormatTag = WaveFormatTag.Pcm;
device = new XAudio2();
masteringVoice = new MasteringVoice(device);
sourceVoice = new SourceVoice(device, format);
sourceVoice.BufferEnd += new EventHandler<ContextEventArgs>(sourceVoice_BufferEnd);
sourceVoice.StreamEnd += new EventHandler(sourceVoice_StreamEnd);
sourceVoice.BufferStart += new EventHandler<ContextEventArgs>(sourceVoice_BufferStart);
//bData = new byte[sampleData.Length * 4 * Channels];
buffer = new AudioBuffer();
buffer.AudioData = new System.IO.MemoryStream();
sourceVoice.SubmitSourceBuffer(buffer);
waveFormat = format;
bytesPerSample = waveFormat.BitsPerSample / 8;
}
void sourceVoice_BufferStart(object sender, ContextEventArgs e)
{
isPlaying = true;
}
void sourceVoice_StreamEnd(object sender, EventArgs e)
{
//isPlaying = false;
}
void sourceVoice_BufferEnd(object sender, ContextEventArgs e)
{
isPlaying = false;
//buffer.Dispose();
}
public void Play() { sourceVoice.Start(); }
public void Stop() { sourceVoice.Stop(); }
//soundOut is sampled data.
public void AddSample(float soundOut)
{
if (sourceVoice.State.BuffersQueued < 1 )
{
if (samplePos < 882)
{
sampleData[samplePos++] = soundOut;
return;
}
for (int i = 0, j = 0; j < samplePos; i += 8, j++)
{
float data = (float)sampleData[j];
byte[] tmp = System.BitConverter.GetBytes(data);
bData = tmp[0];
bData[i + 1] = tmp[1];
bData[i + 2] = tmp[2];
bData[i + 3] = tmp[3];
bData[i + 4] = tmp[0];
bData[i + 5] = tmp[1];
bData[i + 6] = tmp[2];
bData[i + 7] = tmp[3];
}
buffer.AudioData.SetLength(0);
buffer.AudioData.Write(bData, 0, bData.Length);
buffer.AudioData.Position = 0;
buffer.AudioBytes = bData.Length;
buffer.Flags = BufferFlags.EndOfStream;
sourceVoice.SubmitSourceBuffer(buffer);
samplePos = 0;
sampleData[samplePos++] = soundOut;
}
}
public bool FinishedPlaying()
{
return !isPlaying;
}
}