again me with a snd question

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
again me with a snd question
by on (#14302)
If we have 29829~ cpu cycles per frame and i wanna take all the cycles of the apu so i have a buffer of 29829~ bytes and when the frames pass i want to,how can i say it, shrink (is it well written?) it i mean

1789772.5~ / 44100 = 40.5~, then 29829~ / 40.5~ = 745 16 bit samples or 745 * 2 bytes.

Do i have to take the average of all the buffer and then divide it by 40.5~?

Help plz.

by on (#14308)
You can shrink ("resample") your sound buffer however you like. The simplest way is to take every 40.58th sample ("drop-sample conversion"). This won't sound good because it won't suppress frequencies above the Nyquist limit, the maximum frequency that can be represented at a given sample rate (half the sample rate). You can do a weighted average, where each output sample is the average of 40.58 input samples. This will sound better since it filters some of the frequencies. There are more complex schemes but I wouldn't recommend them at this point.

By the way, a video frame is ~29780 CPU clocks long. The APU's frame counter shouldn't be important for buffer generation as it has little overall significance.

One other thing, it would help your accuracy if you round numbers to the nearest rather than round down, as this reduces the error. 1789772.7 / 44100 = 40.5844... Rounding that to one fractional digit yields 40.6, with an error of 0.015585... Rounding down to 40.5 gives an error of -0.08441...

by on (#14309)
A few of your numbers are off by a bit:

1. The NTSC CPU speed should be 1789772.72727MHz.
2. For cleaner numbers, go with 735 samples per "frame" (simply 44100 / 60).
3. Going along with this, your effective "cycles per frame" should be 29829.54545 (CPU speed / 60).
4. As blargg said, 40.5844 CPU cycles per effective sample, and don't round it (or you'll end up with significant glitches).

Unless you're trying to synchronize your emulator to exactly 60 frames per second (which would be incorrect, since a real NTSC NES runs at 60.0988 frames per second), you should not be dealing with video frame lengths at all.

by on (#14311)
Quietust wrote:
Unless you're trying to synchronize your emulator to exactly 60 frames per second (which would be incorrect, since a real NTSC NES runs at 60.0988 frames per second), you should not be dealing with video frame lengths at all.

Others would argue that because there is no need for an accurate color subcarrier on an analog or digital RGB video path, and no common PC video card supports 60.0988 frames per second, it might be more correct to support a mode that creates a 1:1 mapping between PC frames and NES frames. Then you'd slow the CPU down to 60.00 * 341 * 262 / 3 = 1786840 Hz, and almost nobody will notice the 0.2% difference [EDIT: corrected; thanks blargg].

If you choose this route, consider that many (most?) recent sound cards use a Windows driver that processes all sound at 48000 Hz, using either software or hardware resampling from 44100 Hz. Many of these cards would handle 44671 Hz just as easily as 44100 Hz, letting you use exactly 40 NES cycles per sample.

by on (#14321)
I agree regarding frame rate, since one would prefer not to lose frames just to eliminate a speed 0.16% difference (not sure how you calculated an order of magintude less). With audio, operating systems often mix all the sound from each program in software, then feed it to the sound card, so you'd want to use a standard sample rate (or at least be prepared to in case a non-standard one isn't resampled well by the OS).

by on (#14323)
blargg wrote:
With audio, operating systems often mix all the sound from each program in software, then feed it to the sound card, so you'd want to use a standard sample rate (or at least be prepared to in case a non-standard one isn't resampled well by the OS).

Windows 2000 and Windows XP seem to resample well, and they have to in order for DirectMusic playback to work correctly. Given that Microsoft is EOLing all earlier versions of Windows this year, we have little to worry about by using "funny" sample rates if they more closely match the sample rate of the hardware that we're emulating.

by on (#14385)
thnks for the info/advice.

Another issue im facing is that 1000ms/60frames 16,6(period here), so first i used "QueryPerformanceCounter()" to calculate 16 ms passed, and each time the loop calls that api i sleep(1) so the cpu is not overheaded and dsound has time to free up 735 16-BIT samples, but i notice "distorded" sound i mean it seems is freeing up more or less samples. I mean if sleep() cannot work with fractional units. How do i do?

by on (#14386)
Call dsound's GetCurrentPosition function to see if the sound buffer's ready to receive new samples, use a sleep(1) if it's not. Or better yet, base the timing system around that function instead of QueryPerformanceCounter.

by on (#14394)
i tested dsound's method but gave me problems, so i decided to use both, i mean sleeping 16 ms and if dsound's bytes free are < than cycles in frame i stuck in a while until there are enough bytes to write.. but i still have some glitches and the emu uses 40% of the target cpu.

any idea?

by on (#14398)
i am using the sleep method. seems to work for grpahics. i do not have sound yet. but some testing awhile ago showed that sleep(16) will usually sleep more than that. so you can not always use 16. if you want to use the sleep function then you should first determine if you need to sleep and if greater than some minimum then call it, else continue emulation. also does the 16.6 include the time for your code to execute? mine gets the time and calculates when the next render frame should be, and determines the sleep time.

after i get mine working more i intend on using a call back function. but i am not there, yet

also note, this is all linux. but i would assume the sleep function would be similar on winblows.

matt

by on (#14399)
Quote:
if you want to use the sleep function then you should first determine if you need to sleep and if greater than some minimum then call it, else continue emulation


I do the same, i mean i start counting from the beginning of the code and until the nes frame ends, so if the code took 2ms it is included in that "16.6" or substracted (both ways you want to see it).

By the way.. it is written "Windows" not "Winblows" if you made a mistake i ask for your apologies, but if you wanted to mean other thing i think this is not the forum for anti-windows stuff. i use both OS but i think we talk about emulation here. :wink:

by on (#14406)
do you keep the time stamp during the whole emulation loop ? not just 16.6 every render frame or what ever frame ? mine is not exact as it doesnt need to be for early development. if i were to perfect this method, i would keep track of how many nes cycles the render frame took and add that to a running sum, then calculate how much time it should sleep if any. you need to get an exact time to do this. get time of day probably will not work. i read that it is not accurate. and i ran a test and it fluctuates, read somewhere that it was a cache read.

if you are trying to fix the sound, have you explored using the sound call back ? i was going to try this when i reach that point.

matt

by on (#14412)
yeah it seems i need something more accurate than the thing im doing, if not the sound would be hearing nice.
I will keep trying...