 Sound, at long last. |
Posted - 3/7/2008 8:25:31 AM | I have finally got around to adding sound to Cogwheel using Ianier Munoz's waveOut API wrapper.

The technique used is fairly simple. I start with a sound buffer that is a multiple a number of video frames in length (1/60th of a second is one frame) - four seems a good number. This buffer needs to be periodically topped up with sound samples (every four frames in the above example).
I run the emulator for one frame, then generate a frame's worth of audio. I add these samples to a queue. The sound callback then periodically dequeues these samples and appends them to its buffer.
this.Emulator.RunFrame();
short[] Buffer = new short[735 * 2];
this.Emulator.Sound.CreateSamples(Buffer);
this.GeneratedSoundSamples.Enqueue(Buffer);
The important thing is that the sound is always generated after the video frame (and thus after any hardware writes). I log writes to the sound hardware over the period of a frame (along with the number of CPU cycles that have elapsed), then space them out when generating the sound samples so that they play in synch. My previous problems were caused by the sound emulation trying to "look ahead" past what had already been generated.
However, there is a potential problem with this - as the video and sound emulation are not locked in synch with eachother, there are two cases that could crop up:
- The emulator runs faster than 60Hz, generating too many sound samples.
- The emulator runs slower than 60Hz, not generating enough sound samples.
The first is the easiest to deal with. In most instances you'd want a couple of extra frames of sound data left in the queue after topping up the sound buffer, in case in the next period not enough are generated. However, if I notice that the queue is longer than entire sound buffer after topping it up, I clear it completely. This would make the sound a little choppy, but so far this hasn't happened in my tests.
The latter is a little more complex. If I just left it the sound buffer would have gaps in it, causing noticable pops (this I have noticed in some of the more processor-intensive games). To cover up the gaps, I generate enough extra frames of sound data to fill the gap. As no sound hardware writes are made, this has the effect of extending any tones that were currently playing, so the sound will play back slightly out of time. However, slightly out of time by a few 60ths of a second is a better solution than a pop.
private void SoundBufferFiller(IntPtr data, int size) {
short[] Generated = new short[size / 2];
for (int i = 0; i < Generated.Length; i += 735 * 2) {
if (this.GeneratedSoundSamples.Count > 0) {
Array.Copy(this.GeneratedSoundSamples.Dequeue(), 0, Generated, i, 735 * 2);
} else {
short[] Temp = new short[735 * 2];
this.Emulator.Sound.CreateSamples(Temp);
Array.Copy(Temp, 0, Generated, i, 735 * 2);
}
}
Marshal.Copy(Generated, 0, data, size / 2);
while (this.GeneratedSoundSamples.Count > this.SoundBufferSizeInFrames) this.GeneratedSoundSamples.Dequeue();
}
| |
Comments
 |  Scet GDNet+
Member since: 8/3/2002 From: Mississauga, Ontario |
Posted - 3/7/2008 12:13:33 PM | Looks good. I'm in the midst of adding sound and will have to give that API a try, better than waiting for stable DirectSound support in SlimDX. My emulator is time based though, not frame based. All the processors update based on the same time interval.
| |
|
| S | M | T | W | T | F | S | | | | 1 | 2 | 3 | 4 | | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | | |
OPTIONS
Track this Journal
ARCHIVES
September, 2010
August, 2010
July, 2010
June, 2010
April, 2010
March, 2010
February, 2010
January, 2010
December, 2009
November, 2009
October, 2009
August, 2009
June, 2009
May, 2009
March, 2009
February, 2009
January, 2009
December, 2008
November, 2008
October, 2008
September, 2008
August, 2008
July, 2008
June, 2008
May, 2008
April, 2008
March, 2008
February, 2008
November, 2007
October, 2007
September, 2007
August, 2007
July, 2007
May, 2007
April, 2007
February, 2007
January, 2007
December, 2006
November, 2006
October, 2006
September, 2006
August, 2006
July, 2006
June, 2006
May, 2006
April, 2006
March, 2006
February, 2006
January, 2006
December, 2005
November, 2005
October, 2005
September, 2005
August, 2005
April, 2005
February, 2005
January, 2005
|