sync to sound
Moderator: Moderators
sync to sound
I put this (maybe again) to ask about generated sound in the emu and how to sync it with dsound.
The thing is:
Im using 22.5KHZ, 8 bit per sample and mono for dsound output.. i mean the buffer that i create. I put it in this way in the post for simplicity since this could be 44.1 and 16 bit.
Well im using BCP (Before Cursor Position) method to fill the dsound buffer while it's looping.. i mean obtaining the playcursor every 10ms (as DS FAQ says) to avoid overhead, use a custom WriteCursor variable and obtaining the free bytes, but my problem is the following:
Im taking the output every 1789772.5 / 22050 = 81~ cpu cycles.
Taking that into accout the emulated buffer generates:
((341 * 262) / 3) / 81 = 367~ NES samples per frame.
But if the dsound playcursor increment (more or less) every 10ms and the code for runnnig an entire frame is (more or less again) < 3ms, it seems that we have to "wait" for the play cursor to advance 367 bytes so we can write to it.
In other words the NES generates samples faster than dsound play cursor advance.
What means that the emulator *must* be stopped to sync to dsound?
The thing is:
Im using 22.5KHZ, 8 bit per sample and mono for dsound output.. i mean the buffer that i create. I put it in this way in the post for simplicity since this could be 44.1 and 16 bit.
Well im using BCP (Before Cursor Position) method to fill the dsound buffer while it's looping.. i mean obtaining the playcursor every 10ms (as DS FAQ says) to avoid overhead, use a custom WriteCursor variable and obtaining the free bytes, but my problem is the following:
Im taking the output every 1789772.5 / 22050 = 81~ cpu cycles.
Taking that into accout the emulated buffer generates:
((341 * 262) / 3) / 81 = 367~ NES samples per frame.
But if the dsound playcursor increment (more or less) every 10ms and the code for runnnig an entire frame is (more or less again) < 3ms, it seems that we have to "wait" for the play cursor to advance 367 bytes so we can write to it.
In other words the NES generates samples faster than dsound play cursor advance.
What means that the emulator *must* be stopped to sync to dsound?
ANes
Re: sync to sound
Yes. If you generate your audio signal synchronized with CPU/PPU emulation and output it directly to DirectSound (with downsampling, of course), it will prevent your emulator from ever exceeding 100% speed. If you want the ability to exceed 100% speed (a 'turbo' function of some sort) without disabling sound, you'll need a more sophisticated buffer that can discard blocks instead of waiting for them to play.Anes wrote: Im taking the output every 1789772.5 / 22050 = 81~ cpu cycles.
Taking that into accout the emulated buffer generates:
((341 * 262) / 3) / 81 = 367~ NES samples per frame.
But if the dsound playcursor increment (more or less) every 10ms and the code for runnnig an entire frame is (more or less again) < 3ms, it seems that we have to "wait" for the play cursor to advance 367 bytes so we can write to it.
In other words the NES generates samples faster than dsound play cursor advance.
What means that the emulator *must* be stopped to sync to dsound?
Incidentally, you really shouldn't be dividing the audio into PPU frames, since video and audio "frames" on the NES are totally unrelated.
The problem with a 22050Hz sample rate is that it doesn't divide neatly by 60 (as well as the fact that higher frequencies will sound quite awful at that rate). These days, you shouldn't settle for anything less than 44100Hz - it divides evenly by 60 (which is a convenient number to use) and the audio will actually sound decent. 16-bit audio would also be useful, especially if you're going to be handling expansion sound.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
P.S. If you don't get this note, let me know and I'll write you another.
You're dealing with the fundamental problem of two masters: the frame rate and sample rate. You're going to have to slave one to the other (work this out on paper until you can see that there's no way around this). It's easy to make the frame rate a slave to the sample rate, and much less noticeable than changes in sample rate. A simple method is to make the frame rate slightly higher than the corresponding sample rate (i.e. 61 FPS), then have your graphics wait until there is no more than a few frames of audio waiting to play before displaying a frame (otherwise you'll have the sound playing too late).
That's pretty much exactly what I do - make the frame rate depend on the sample rate, which should actually work out to ~60.0988 frames per second (1789772.7272727 cycles per second... / 29780.5 cycles per frame) on the NTSC NES.blargg wrote:You're dealing with the fundamental problem of two masters: the frame rate and sample rate. You're going to have to slave one to the other (work this out on paper until you can see that there's no way around this).
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
P.S. If you don't get this note, let me know and I'll write you another.
I don't like the tearing you get from not using vsync, so I make sure my frame rate is locked to 60Hz (block waiting for vsync, backed by a conventional timer in the emulation loop in case vertical refresh is >60Hz). For audio, I slightly adjust the sample rate based on how close the DirectSound play cursor is to the write cursor. The adjustment is small enough that you can rarely hear it (and, for me, only if I'm listening for it), but in ensures that the video frame rate stays locked at 60Hz without causing sound problems.
My refresh rate is locked at 60Hz (LCD display), so one missed vsync tends to cause sound buffer underflows. This probably isn't as big of an issue at higher refresh rates.
James
My refresh rate is locked at 60Hz (LCD display), so one missed vsync tends to cause sound buffer underflows. This probably isn't as big of an issue at higher refresh rates.
James
get nemulator
http://nemulator.com
http://nemulator.com
I built my NES emu 'backend' so that it's able to work either way. The way I have it set up is the front supplies an audio buffer, as well as the size of that buffer, and whether or not it wants the whole buffer filled with audio, or if it just wants the audio that would be 'naturally' produced in that frame.
If the front specifies it only wants the natural audio output (like if it's syncing to sound), then the back simply runs for a frame and outputs the generated audio. Otherwise, if the back is to fill the entire buffer, once it runs for a frame, it continues to generate more audio samples until the buffer is filled. It's actually not that difficult with NES sound, since you're only dealing with simple repeating basic waveforms. When generating more audio, I just run things related to wave generation (Programmable timer, Duty Cycle Unit, Tri-Step Generator, etc) and leave all other areas (Length, Sweep, Linear, etc) untouched. That allows for sped up or slowed down sound without disrupting the pitch and will allow the game to run at any framerate without choppy sound.
The DMC complicates this, however. This doesn't work well with ROMs that use $4011... so games which stream data to it will end up sounding crackly or worse unless synced to sound. And stuff like blargg's sawtooth demo won't work right at all. I don't have a work-around for this with my method.
Also -- since running the DMC longer (or shorter) will disturb the rate of stolen cycles, and DMC IRQs, I had to actually have two seperate DMCs to emulate, each operating independently of each other -- one which actually produces the sound (which I can be lax with, and can be run more/less depending on the number of samples needed), and one which runs tied to the CPU (which is only responsible for stealing cycles and firing IRQs at the appropriate times).
If the front specifies it only wants the natural audio output (like if it's syncing to sound), then the back simply runs for a frame and outputs the generated audio. Otherwise, if the back is to fill the entire buffer, once it runs for a frame, it continues to generate more audio samples until the buffer is filled. It's actually not that difficult with NES sound, since you're only dealing with simple repeating basic waveforms. When generating more audio, I just run things related to wave generation (Programmable timer, Duty Cycle Unit, Tri-Step Generator, etc) and leave all other areas (Length, Sweep, Linear, etc) untouched. That allows for sped up or slowed down sound without disrupting the pitch and will allow the game to run at any framerate without choppy sound.
The DMC complicates this, however. This doesn't work well with ROMs that use $4011... so games which stream data to it will end up sounding crackly or worse unless synced to sound. And stuff like blargg's sawtooth demo won't work right at all. I don't have a work-around for this with my method.
Also -- since running the DMC longer (or shorter) will disturb the rate of stolen cycles, and DMC IRQs, I had to actually have two seperate DMCs to emulate, each operating independently of each other -- one which actually produces the sound (which I can be lax with, and can be run more/less depending on the number of samples needed), and one which runs tied to the CPU (which is only responsible for stealing cycles and firing IRQs at the appropriate times).
Re: sync to sound
Excellent! What your discussed is just the problem I am thinking about.
-
unregistered
- Posts: 1193
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: sync to sound
That's a mistake that a lot of English speaking people make. Well, your instead of you're they both sound the same. You've is you have.Boolean wrote:Excellent! Whatyouryou've discussed is just the problem I am thinking about.
Re: sync to sound
Thank you, my friend.unregistered wrote:That's a mistake that a lot of English speaking people make. Well, your instead of you're they both sound the same. You've is you have.Boolean wrote:Excellent! Whatyouryou've discussed is just the problem I am thinking about.
I know what you mean. A have+done stands for the Present Perfect Tense.
What your discussed is short for What your discussed thing.
Discuss is a verb. In most cases, a verb can be formatted with ed to become a adjective.
A adjective can stand for related things(equals a noun). I find I lost a verb.
I think a second way to correct it is
What you discussed ...(the Past Tense only)
-
unregistered
- Posts: 1193
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: sync to sound
My friend, your extensive knowledge of all the ins and outs of English astounds me!Boolean wrote:In most cases, a verb can be formatted with ed to become an adjective.
An adjective can stand for related things(equals a noun). I find I lost a verb.![]()
I think a second way to correct it is
What you discussed ...(the Past Tense only)
Re: sync to sound
Thank you
I think the quoted text is the most important thing.unregistered wrote:In my head it just sounds more correct so I put that...
- mikejmoffitt
- Posts: 1352
- Joined: Sun May 27, 2012 8:43 pm
Re:
I have an odd solution to this. At the start of my game (though you could do this for an emulator I suppose) I run 15 frames locked to vsync, and divide the amount of time that takes by fifteen. If I find that the duration of a frame wasn't ~16.67ms, I then enable a timer. If it was 16.67ms, though, I determine that syncing to vsync is fine and just do that. This also solves the issue of terrible drivers like nouveau not properly implementing vsync.James wrote:I don't like the tearing you get from not using vsync, so I make sure my frame rate is locked to 60Hz (block waiting for vsync, backed by a conventional timer in the emulation loop in case vertical refresh is >60Hz). For audio, I slightly adjust the sample rate based on how close the DirectSound play cursor is to the write cursor. The adjustment is small enough that you can rarely hear it (and, for me, only if I'm listening for it), but in ensures that the video frame rate stays locked at 60Hz without causing sound problems.
My refresh rate is locked at 60Hz (LCD display), so one missed vsync tends to cause sound buffer underflows. This probably isn't as big of an issue at higher refresh rates.
James