VOGONS


First post, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

Hi all, I know a lot about computer software but sound emulation (and sound basics) is one area that I am not ashamed to admit I do not know as much. I know there are a few people here that understand way better than me how this works (like gdjacobs, Scali, Jepael, reenigne, superfury and others) so I have a few questions.

Lets take the simple PC speaker for example. The 8253 channel 2 can be set to have a certain frequency by loading the reload value with a number. So the frequency would be (1.192Mhz/number) which gives us some Hertz. Whenever the channel 2 line goes high the speaker moves in one direction and whenever it goes low the speaker moves in another dimension, therefore creating sound. Am I understanding this correctly?

Now the first part I do not understand is how do I go from that to emulating the sound using a digital sound card which wants a stream of numbers (is that PCM?)? SDL (which is what I am using) is for now set up to accept a buffer of uint8_t values (so 8bit unsigned values) to talk to my host sound card and produce sound. What is the equivalence between the speaker moving at a certain frequency (all I have is I can sample the 8253 and that can give me a count and the frequency itself, basically where in the duty cycle of the wave I am) and the 8bit values in my sound buffer? Those 8 bit values are not frequencies (I gather) but rather "loudness" right? So a value of 0 in SDL should mean silent but 255 means loudest? This is the part where I get lost...

If I set my host sound card to accept (generate) sound at say 44Khz does that mean I need to sample the 8253 at a frequency of 44Khz? If yes what do I do with the value I see in 8253 channel 2?

I feel like there is some basic sound theory that I miss here...

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 1 of 2, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie
vladstamate wrote:

Hi all, I know a lot about computer software but sound emulation (and sound basics) is one area that I am not ashamed to admit I do not know as much. I know there are a few people here that understand way better than me how this works (like gdjacobs, Scali, Jepael, reenigne, superfury and others) so I have a few questions.

Thank you, and I can help somewhat, as I know something about signal processing and theory, but in practice there are some tricks that make calculating the same output values with less CPU power than doing it exactly like theory says.

For starters you could read about PCM (https://en.wikipedia.org/wiki/Pulse-code_modu … tion#Modulation), you can think of the values you play as not the "loudness" but perhaps the speaker cone position, e.g. 0 = negative maximum, 255 = positive maximum, 128 = resting at middle.

I recommend 16-bit quality on modern systems though, and usually 16-bit audio is signed (just like CD audio) so thats from -32768 to +32767 and 0 is midpoint.

vladstamate wrote:

Lets take the simple PC speaker for example. The 8253 channel 2 can be set to have a certain frequency by loading the reload value with a number. So the frequency would be (1.192Mhz/number) which gives us some Hertz. Whenever the channel 2 line goes high the speaker moves in one direction and whenever it goes low the speaker moves in another dimension, therefore creating sound. Am I understanding this correctly?

Sure, so as an example you want to play middle A with piano, that's exactly 440 Hz tone, so you load a value of 1193180/440=2712 to the PIT, and when the PIT is in square wave mode, it generates a square wave that has a period of 2712 PIT clock cycles so it is 1356 cycles high and 1356 cycles low.

vladstamate wrote:

Now the first part I do not understand is how do I go from that to emulating the sound using a digital sound card which wants a stream of numbers (is that PCM?)? SDL (which is what I am using) is for now set up to accept a buffer of uint8_t values (so 8bit unsigned values) to talk to my host sound card and produce sound. What is the equivalence between the speaker moving at a certain frequency (all I have is I can sample the 8253 and that can give me a count and the frequency itself, basically where in the duty cycle of the wave I am) and the 8bit values in my sound buffer? Those 8 bit values are not frequencies (I gather) but rather "loudness" right? So a value of 0 in SDL should mean silent but 255 means loudest? This is the part where I get lost...

If I set my host sound card to accept (generate) sound at say 44Khz does that mean I need to sample the 8253 at a frequency of 44Khz? If yes what do I do with the value I see in 8253 channel 2?

I feel like there is some basic sound theory that I miss here...

Well, you can quite easily calculate that to generate a 440 Hz tone using 44100 Hz sampling rate, you have to generate square wave that has a period of (approx) 100 samples, so 50 samples high and 50 samples low. The values for the samples determine the amplitude, so to get maximum 8-bit volume you use values 255 for the 50 high samples and 0 for the 50 low samples. You can convert the PIT period value into tone frequency first, and then back to period in samples, or use it directly.

If you do just let the PIT emulation running at 1193180 Hz and skip enough PIT outputs so that you "sample" the PIT output at 44100 Hz. Because 1193180/44100 is almost 27, that's almost like taking one PIT sample from every 27 PIT samples for SDL playback.
Now, having said that, this would be the first and simplest way to try it, computationally efficient, although theoretically completely wrong and could sound quite horrible. Based on sampling theory, instead of skipping samples, each input sample has a contribution to output so basically you just need to resample the 1-bit 1193180 Hz stream into 16-bit 44100 Hz stream, and a resampling library could be the easiest way to achieve this.

Reply 2 of 2, by superfury

User metadata
Rank l33t++
Rank
l33t++

That's indeed correct. Although you might want to add a low-pass filter to make PWM output on the PC speaker work(8088 MPH uses this, as does the MS-DOS game Links 2(during the intro, using the PC Speaker)). You'll have to generate a correct samplestream at 1.19MHz first(with at least the PC Speaker's Single Shot mode implemented accurately in 1-bit depth), then you use the low-pass filter(I'm using 1.19MHz divided by 72(the amount of PIT sample time to make the cone move)) to convert it to a 1.19MHz PWM wave. Then you can downsample that to 44.1kHz(this is exactly what's done in UniPCemu).

Btw, Actually the numbers in the stream are actually voltages in time. So at a samplerate of 44.1kHz, each of the samples takes 1/44100th second before changing the voltage to the next sample(sample and hold).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io