PDA

View Full Version : PC Speak Technical Question



chjmartin2
August 31st, 2014, 01:24 PM
Hi,

I'd like to play with the PC Speaker a bit, and have enjoyed seeing how one can use the PIT to play PWM. Here is what I understand:

You can use the following Basic Command to get the PC Speaker in standard mode and not latched to the PIT:


OUT &H43, &HB6
R = INP(&H61) AND &HFC
OUT &H61, R

I know that the PC Speaker port is available to me via OUT &H61,value. When I work on the Mattel Aquarius, the speaker port is on or off, now, I send over an 8 bit value, but the first seven bits aren't used, the speaker state is solely determined by the least significant bit.

Can somebody explain to me if that is how I can bit-wise operate the PC Speaker. Now before you tell me that I don't want to - I promise you that I do. :)

Anyway, I see from this website (https://courses.engr.illinois.edu/ece390/resources/sound/speaker.txt.html) that when he bit-wise operates the speaker, he reads the value from the port first, and then sends back the last TWO bits. Why the last two????

Would appreciate some basic nuts and bolts help here. I can't find an easy PC system block diagram or port guide to explain the specifics of the &H61 port and what it does and does not do.

Thanks,

Chris

modem7
September 1st, 2014, 01:49 AM
Anyway, I see from this website (https://courses.engr.illinois.edu/ece390/resources/sound/speaker.txt.html) that when he bit-wise operates the speaker, he reads the value from the port first, and then sends back the last TWO bits. Why the last two????
The diagram at [here (http://www.minuszerodegrees.net/5150/misc/5150_speaker_circuit.jpg)] will explain why.


I can't find an easy PC system block diagram or port guide to explain the specifics of the &H61 port and what it does and does not do
They are in the IBM 5150 and 5160 Technical References ([here (http://www.minuszerodegrees.net/manuals.htm#IBM)]).

chjmartin2
September 1st, 2014, 04:08 AM
The diagram at [here (http://www.minuszerodegrees.net/5150/misc/5150_speaker_circuit.jpg)] will explain why.


They are in the IBM 5150 and 5160 Technical References ([here (http://www.minuszerodegrees.net/manuals.htm#IBM)]).

Wow these are great thank you!

chjmartin2
September 1st, 2014, 06:58 AM
Wow these are great thank you!

And I am still dumb...

reenigne
September 1st, 2014, 08:39 AM
Bit 0 controls the PIT's "gate" input (which does various things depending on the PIT mode) and bit 1 is ANDed with the PIT output so that timer 2 can be used without actually making sound. The other bits in port 0x61 are for things other than the speaker, so programmers generally just change the lower two bits to avoid messing up anything else.

In modes 2 and 3, the PIT output will always be high when the gate is low. So you can output directly to the PC speaker by putting PIT channel 2 in one of these modes (3 in your example), setting bit 0 of port 0x61 to 0 and putting your speaker data in bit 1 of port 0x61. So it's not the least significant bit you want to twiddle, it's bit 1.

Trixter
September 1st, 2014, 08:29 PM
Speaking a little more high-level, there are three basic methods of driving the speaker:


You can gate timer 2 so that it drives the speaker (this is the square wave "BEEP" you're familiar with)
You can directly set the speaker voltage on or off, as reenigne described above (this is directly bit-banging the speaker, as you've done on the Aquarius)
You can gate timer 2 and set it to "one-shot" mode so that a value will set the speaker on, then off when the timer elapses (this is the PWM method used to output sampled sound, aka "RealSound")


#1 sounds the worst and is limited to square wave tones, but it has the least CPU utilization. #2 can be used for very loud digitized speech output, but the distortion prevents more serious use; you can probably wire up a ZX Spectrum-like music engine driving it manually. #3 can produce very clear audio (effectively a 6-bit DAC) but has a very low volume.

chjmartin2
September 2nd, 2014, 07:06 PM
Speaking a little more high-level, there are three basic methods of driving the speaker:


You can gate timer 2 so that it drives the speaker (this is the square wave "BEEP" you're familiar with)
You can directly set the speaker voltage on or off, as reenigne described above (this is directly bit-banging the speaker, as you've done on the Aquarius)
You can gate timer 2 and set it to "one-shot" mode so that a value will set the speaker on, then off when the timer elapses (this is the PWM method used to output sampled sound, aka "RealSound")


#1 sounds the worst and is limited to square wave tones, but it has the least CPU utilization. #2 can be used for very loud digitized speech output, but the distortion prevents more serious use; you can probably wire up a ZX Spectrum-like music engine driving it manually. #3 can produce very clear audio (effectively a 6-bit DAC) but has a very low volume.

I had noise on the Aquarius due to the rising and falling imperfections of the signal. My question is if I can bit-bang at more than 100k Hz. If so, I think I can beat the 6 bit PWM playback. I also am thinking that there might be a way to use the PIT in a different way to create a Sigma Delta Modulated signal. SDM on the Aquarius was WAY better than PWM at the equivalent bit rate....

reenigne
September 2nd, 2014, 10:48 PM
WAY better than PWM at the equivalent bit rate

What do you mean by "the equivalent bit rate"? If you mean the rate at which bits are sent to the speaker then I'm sure that would be better quality, but you'd have to store about 8 times as much data, which means you can store only about 4 seconds of audio instead of 35 in 640kB.

If you're talking about equivalent bitrates from a storage point of view, I'm not convinced that SDM would be better because that would correspond to about 3 bits of dynamic range per byte stored, instead of 6.


My question is if I can bit-bang at more than 100k Hz.

100kHz would be pretty difficult to achieve on a 4.77MHz machine. That's about 11 bus cycles per bit. You could do it with a loop of:


lodsb
out dx,al

but that would increase the storage requirements by another factor of 8, since you only get one output bit per storage byte.

To play back a bit-packed SDM signal you'd need to do something like:


lodsb
xchg ax,bx
mov al,bl
and al,~2
or al,xx
out dx,al

which is 11 bus cycles by itself, and doesn't include a loop instruction, segment changes or DRAM refresh overhead. And if you want to dynamically generate the audio instead of just streaming it that's another order of magnitude of complexity (though this kind of thing has been done on the ZX spectrum so should be possible on the PC too).

A machine faster than 4.77MHz would be able to achieve better output bitrates though.

nestor
September 3rd, 2014, 01:14 AM
#3 can produce very clear audio (effectively a 6-bit DAC) but has a very low volume.

And sometimes a high pitch whine in the background if I'm not mistaken.

chjmartin2
September 3rd, 2014, 05:56 AM
What do you mean by "the equivalent bit rate"? If you mean the rate at which bits are sent to the speaker then I'm sure that would be better quality, but you'd have to store about 8 times as much data, which means you can store only about 4 seconds of audio instead of 35 in 640kB.

What I mean is this. When I did PWM on the Aquarius at 100 KHz and when I did SDM at the same 100 KHz, the SDM quality was MUCH MUCH better. It could be that I didn't implement the PWM properly, or it could be the noisey square waves. Both outputs had noise, but the fidelity was much closer to 16 bit using SDM. Quality was shocking to me... Real SDM is typically at


A machine faster than 4.77MHz would be able to achieve better output bitrates though.

On the 3.5 MHz Z80 Mattel Aquarius I got up to over 100 KHz bit-banging. The benefit there is that I had an EPROM with 1 meg and bank switching.

Let's think about the data rate for an 8-bit packed signal. (On the Z80 I used RRLD to cycle through the packed bits.) So, if we want 100 KHz, then that is 100,000 bits per second / 8 = 12,500 bytes per second or 12.2K per second. So, if we use 350k of memory for the sound then we get almost 30 seconds, which is plenty for a high quality loop and to prove the concept. (Just imagine how we will do this when I ask you to figure out how to bit-bang and 60 Hz flicker.)

So the question I really have is, can we do file i/o at 12.2Kbytes per second AND bit-bang the speaker at 12.2Kbytes per second simultaneously using a memory buffer or some other creative means. http://en.wikipedia.org/wiki/Delta-sigma_modulation Typically SDM is a much, much higher frequency, but it works at 100 KHz. Invnut over at Atariage actually helped me a lot (did it for me) on the conversion.

Lastly, because SDM is mostly a 1/0/1/0/1/0 signal, I am also thinking about how to use the PIT to do an SDM encoded signal. I'm not sure what the cut-off is for the Low pass filter on the speaker, so, at some point the over-oscillation may get filtered out. I'm not sure because of course my scope is broken. Anyway, if we could use the PIT for SDM somehow, we could use ANY frequency we want and let the PIT generate the rising or falling SDM signal... So, if we bit bang to 100 KHz then you get a 50 KHz buzz which only the dog can hear. Even 50KHz sounds great because most people can't hear a 25 KHz buzz either.

Chris

Trixter
September 3rd, 2014, 07:11 AM
And sometimes a high pitch whine in the background if I'm not mistaken.

Correct; this is the audible carrier frequency that is created as a byproduct of the PWM (http://en.wikipedia.org/wiki/Pulse-width_modulation) method of audio generation through the PC speaker.

The (sneaky) workaround is to generate audio at rates so high that the carrier is beyond the range of human hearing. In my own work, I favor 16572Hz which is just barely at the edge of my own range of hearing, but also uses the same divisor as the DRAM refresh circuitry which avoids audible interference generated from that interrupt. John Ratcliff was fond of using 18KHz playback with 9KHz source material, with each sample output twice during playback.

Trixter
September 3rd, 2014, 07:49 AM
So the question I really have is, can we do file i/o at 12.2Kbytes per second AND bit-bang the speaker at 12.2Kbytes per second simultaneously using a memory buffer or some other creative means.


LOL, no. Your entire system will be dedicated to generating audio (don't think of it as sending 12.2KB/s but rather 100Kbit/s), so no file I/O at all. Plus, you have to maneuver your single bit into bit 1 in the byte you output to the port, so you'll either have to pre-massage the data as Andrew suggested before, or do it runtime. You'll have either high-speed output of large data (short length), or slower output of small data. You can't have your cake and eat it too.

While it's not 100KHz, there is an example of doing what you want at 16KHz; grab ftp://ftp.oldskool.org/pub/misc/xtfiles.rar and look at apputils\SOUND\SPEAKER\1-BIT in that archive. It has a playback routine that bit-bangs the speaker, clocked by timer 0 @ 16KHz. You can't make that much faster via the timer, but if you just send data as fast as possible using the methods Andrew suggested earlier, you might hit 100Hz.

This assumes you have real hardware to test on. Emulators such as DOSBox, PCEM, or PCE will only properly reproduce audio using timer-clocked methods; if you decide to spam the speaker port, you had better do it on real hardware.



Lastly, because SDM is mostly a 1/0/1/0/1/0 signal, I am also thinking about how to use the PIT to do an SDM encoded signal.

I am probably misunderstanding how SDM differs from PWM (http://en.wikipedia.org/wiki/Pulse-width_modulation), but there's always method #3 that I mentioned previously: You set up timer 2 in one-shot mode and then connect it to the speaker; the byte output to the timer starts the one-shot and sets the speaker HIGH, then when the timer runs out, sets it to LOW. You repeat this process at the target samplerate, which is typically maintained by timer 0 interrupts, but at the speeds you want to achieve, you'd have to do it yourself as fast as possible. Sample source code is available. (http://www.drdobbs.com/architecture-and-design/examining-pc-audio/184408962?pgno=3) State of the art in this area is 29KHz output using the hardware to clock everything (my own code), and Andrew has theorized that 44.1KHz and higher is possible using carefully-crafted software timing loops. Both approaches completely take over the system.

PS: Can someone tell me how SDM differs from PWM?

reenigne
September 3rd, 2014, 09:20 AM
PS: Can someone tell me how SDM differs from PWM?

SDM is essentially just a 1-bit signal played back at a high sample rate (though it also refers a specific system for generating such signals). It's what's used on SACDs and is also known as DSD (Direct Stream Digital) or pulse-density modulation encoding.

PWM is a subset of SDM in that you have 1 bits and 0 bits, but they appear in runs of 0s and 1s, with the transition from 0 to 1 occurring at a regular interval. With SDM your 50% level is represented by the stream 0101010101 whereas in PWM it might be (for example) 0000111100001111. So the "carrier frequency" can be much higher with SDM. You can also think of it as being a tradeoff between dynamic range and sample rate which is fixed at encoding time for PWM and happens optimally for SDM.

The PIT would not be useful for SDM as it can't generate the full range of bit patterns. Modes available are: 1 followed by N zeros (useful for interrupt generation but not really for audio), N 1s followed by zeros until reloaded (useful for PWM) and square waves (which always have 50% duty cycle, so would always correspond to 50% level SDM patterns). What you really want is a parallel-in-serial-out shift register rather than a PIT, but the PC doesn't have one of those connected to the speaker.


On the 3.5 MHz Z80 Mattel Aquarius I got up to over 100 KHz bit-banging.

I'd be interested to see the inner loop code for that - perhaps there's a trick that I haven't thought of, but I think it's more likely that the audio hardware of the Aquarius is just easier to bit-bang (e.g. it's a lot easier of the speaker is connected to bit 0 of some port and bits 1-7 are ignored).

chjmartin2
September 3rd, 2014, 10:30 AM
PS: Can someone tell me how SDM differs from PWM?

It was on this thread (http://atariage.com/forums/topic/180604-digitized-sound-on-aquarius/page-3) that Intvnut "taught" me about SDM. Here is the best part:



If it were me, I'd consider implementing a high-rate sigma-delta modulator (also called delta-sigma modulator). More info here: https://en.wikipedia...igma_modulation Sigma-delta is nice because the math is super simple, and the results are actually very good. A sigma-delta conversion loop looks something like this:


foreach sample:
if sample > error then
output = max
error = error + max - sample
else
output = min
error = error + min - sample
endif


I've attached some sample C code that shows how to do an SDM. Edit: Apparently I can't upload C files. I'll put it on my webserver here: http://spatula-city....m14u2c/dl/sdm.c

chjmartin2
September 3rd, 2014, 10:43 AM
I'd be interested to see the inner loop code for that - perhaps there's a trick that I haven't thought of, but I think it's more likely that the audio hardware of the Aquarius is just easier to bit-bang (e.g. it's a lot easier of the speaker is connected to bit 0 of some port and bits 1-7 are ignored).

No inner loop. Looking back now I am proud of myself having t-state balanced the code. I watched a guy on you-tube talk about writing demos and how unrolling the loop is a way to speed up code. I needed to do it to get the cycle-counting exactly timed right. I'm afraid to have you look at it because you may find a mistake OR figure out my 100 KHz is wrong!



main:

ld bc, 8191 ; (10) number of bytes of samples
ld hl, $C000 ; (10) Memory Location to ROM Sample

ld a, (hl) ; (7) load first sample set into A
rlc b ; (8) set up b to be rotated

replay:
out ($fc), a ; (11) send out the sample
rlca ; (4) rotate the PWM model left

inc hl ; (6) Move up the Rom sample location

nop ; (4) waste cycles
nop ; (4) waste cycles
nop ; (4) waste cycles

out ($fc), a ; (11) send out the sample
rlca ; (4) rotate the PWM model left

rrc b ; (8) unrotate b from previous rotate

jp wastetenone ; (10) waste 10 t-states
wastetenone:

out ($fc), a ; (11) send out the sample
rlca ; (4) rotate the PWM model left

dec bc ; (6) Reduce the byte counter

nop ; (4) waste cycles
nop ; (4) waste cycles
nop ; (4) waste cycles

out ($fc), a ; (11) send out the sample
rlca ; (4) rotate the PWM model left

nop ; (4) waste cycles
nop ; (4) waste cycles

jp wastetentwo ; (10) waste 10 t-states
wastetentwo:

out ($fc), a ; (11) send out the sample
rlca ; (4) rotate the PWM model left

ld d, (hl) ; (7) next first sample set into A

ld e, (hl) ; (7) load (hl) into e to waste cycles

nop ; (4) waste cycles

out ($fc), a ; (11) send out the sample
rlca ; (4) rotate the PWM model left

rlc b ; (8) see if loop counter went negative

jp wastetenthr ; (10) waste 10 t-states
wastetenthr:

out ($fc), a ; (11) send out the sample
rlca ; (4) rotate the PWM model left

nop ; (4) waste cycles
nop ; (4) waste cycles

jp wastetenfou ; (10) waste 10 t-states
wastetenfou:

out ($fc), a ; (11) send out the sample

ld a, d ; (4) copy new sample to a

nop ; (4) waste cycles
nop ; (4) waste cycles

jp p, replay ; (10) do it again until we are done!

chjmartin2
September 3rd, 2014, 10:53 AM
PWM is a subset of SDM in that you have 1 bits and 0 bits, but they appear in runs of 0s and 1s, with the transition from 0 to 1 occurring at a regular interval. With SDM your 50% level is represented by the stream 0101010101 whereas in PWM it might be (for example) 0000111100001111. So the "carrier frequency" can be much higher with SDM. You can also think of it as being a tradeoff between dynamic range and sample rate which is fixed at encoding time for PWM and happens optimally for SDM.

The PIT would not be useful for SDM as it can't generate the full range of bit patterns. Modes available are: 1 followed by N zeros (useful for interrupt generation but not really for audio), N 1s followed by zeros until reloaded (useful for PWM) and square waves (which always have 50% duty cycle, so would always correspond to 50% level SDM patterns). What you really want is a parallel-in-serial-out shift register rather than a PIT, but the PC doesn't have one of those connected to the speaker.


Can't believe I am going to say this to you of all people, but.... Not so fast. So if we program the PIT for 100 KHz and send 1 followed by 1 zero, do we get a perfect 100 KHz sine wave? Now can't we latch the speaker to the PIT AND control the on-off state but not change the frequency? Ok, so, we do the best we can and minimize error by controlling the on-off state relative to the target SDM signal?

reenigne
September 3rd, 2014, 11:40 AM
Looking back now I am proud of myself having t-state balanced the code.

Looks great! But I'm afraid it's as I thought. The heart of your routine is the two instructions:


out ($fc), a ; (11) send out the sample
rlca ; (4) rotate the PWM model left

That's 15 cycles at 3.5MHz or 4.3 microseconds, leaving 5.7 microseconds for loading new bytes, looping and DRAM refresh. The fastest equivalent code for PC speaker I can spot is:

[CODE]rol bx,1
mov al,bl
and al,~2
or al,xx
out dx,al[CODE]

which is at least 40 cycles at 4.77MHz (8.4 microseconds), leaving only 1.6 microseconds for loading new bytes, looping and DRAM refresh.

I suppose if you find a PIT mode/counter setting that (to a suitable approximation) gives you a high signal with gate low and a low signal with gate high, you could do something like:

[CODE]rcl bx,1
mov al,xx
adc al,0
out dx,al[CODE]

which shaves off a couple of cycles but those 4 instructions will still take at least 6.7 microseconds, so you've still got to do the rest at twice the speed of the Aquarius.

reenigne
September 3rd, 2014, 11:47 AM
Can't believe I am going to say this to you of all people, but.... Not so fast. So if we program the PIT for 100 KHz and send 1 followed by 1 zero, do we get a perfect 100 KHz sine wave?

You'll get a 100kHz signal, but it won't be a sine wave (and by the time it gets through the RC filter to the speaker it'll be flat for all practical purposes anyway. I'm not sure what the significance of this 100kHz signal is, though.


Now can't we latch the speaker to the PIT AND control the on-off state but not change the frequency? Ok, so, we do the best we can and minimize error by controlling the on-off state relative to the target SDM signal?

I'm not really sure what you're suggesting here, but it sounds like a "hardware accelerated (by the PIT) approximation to the desired SDM signal". Well, that's exactly what PWM is. PWM has the advantage of having states which cover the entire dynamic range. I don't see how any other combination of poking the PIT and port 0x61 bits would have that property.

reenigne
September 3rd, 2014, 11:56 AM
When I did PWM on the Aquarius at 100 KHz and when I did SDM at the same 100 KHz, the SDM quality was MUCH MUCH better.

This may be the heart of the matter. Even if you can do bit-banging at 100kHz on the PC speaker (which I'm still not totally convinced is possible) you're not comparing like with like because the PIT hardware-accelerates PWM on the PC speaker to an effective corresponding bitrate of 1.193MHz!

It sounds like the Aquarius does not have the equivalent of a PIT connected to its speaker, so the PWMing has be done in software and will go ~12 times slower than PWM on the PC speaker. So to get the corresponding improvement of "Aquarius 100kHz PWM -> Aquarius 100kHz SDM" on the PC, "PC Speaker 1.193MHz PWM -> PC Speaker 100kHz SDM" would not suffice - you'd need to do "PC Speaker 1.193MHz PWM -> PC Speaker 1.193MHz SDM", which is even more impossible.

chjmartin2
September 3rd, 2014, 12:20 PM
This may be the heart of the matter. Even if you can do bit-banging at 100kHz on the PC speaker (which I'm still not totally convinced is possible) you're not comparing like with like because the PIT hardware-accelerates PWM on the PC speaker to an effective corresponding bitrate of 1.193MHz!

It sounds like the Aquarius does not have the equivalent of a PIT connected to its speaker, so the PWMing has be done in software and will go ~12 times slower than PWM on the PC speaker. So to get the corresponding improvement of "Aquarius 100kHz PWM -> Aquarius 100kHz SDM" on the PC, "PC Speaker 1.193MHz PWM -> PC Speaker 100kHz SDM" would not suffice - you'd need to do "PC Speaker 1.193MHz PWM -> PC Speaker 1.193MHz SDM", which is even more impossible.

Nope. Still not sold. I get what you mean about PWM now, it is an effective 1.193 MHz signal. I would replicate, and modulate the PIT at the 22k, but keep the Oscillation at 1.193 MHz. SDM is a moving average PWM - not exactly the same I don't think by the way...

reenigne
September 3rd, 2014, 12:33 PM
I would replicate, and modulate the PIT at the 22k, but keep the Oscillation at 1.193 MHz.

I understand all the words in that sentence, but I'm afraid I have no idea what you mean by it!

per
September 3rd, 2014, 03:08 PM
As of I understand, DSM adjusts the frequency of pulses in a signal where all the pulses has the same width, while PWM adjusts the duty cycle of a squarewave that's oscillating a fixed frequency. On the practical side, they're almost the same. PWM updates timer CH2 per interrupt where CH0 is constant, while DSM updates timer CH0 per interrupt where CH2 is constant. In both cases CH2 is in one-shot mode, while CH0 is in repeating pulse mode for PWM and one-shot for DSM.

DSM might be slightly problematic in that sense, as CH0 can't run free all by itself. There will be some delay for every update of CH0, especially at waveform top peaks (high frequency DSM signal). In addition (as mentioned), the frequency filter before the speaker might have some impact as well on a variable frequency signal.

Trixter
September 3rd, 2014, 07:59 PM
the PIT hardware-accelerates PWM on the PC speaker to an effective corresponding bitrate of 1.193MHz!

This. (Which also explains why the PWM timer method sounds so good.)

Just for giggles I attempted some SDM stuff tonight @ 96KHz and the results were hilariously terrible -- worse than just taking the most significant bit of a sample and outputting that instead (ie. simple 1-bit samples). I can post examples for the curious, but honestly it's not worth it. The only thing that sounded close to normal was 8x oversampling of the source, which limited the source to 12KHz sampling frequency. PWM can already do better than that.

reenigne
September 3rd, 2014, 10:12 PM
As of I understand, DSM adjusts the frequency of pulses in a signal where all the pulses has the same width, while PWM adjusts the duty cycle of a squarewave that's oscillating a fixed frequency. On the practical side, they're almost the same. PWM updates timer CH2 per interrupt where CH0 is constant, while DSM updates timer CH0 per interrupt where CH2 is constant. In both cases CH2 is in one-shot mode, while CH0 is in repeating pulse mode for PWM and one-shot for DSM.

DSM might be slightly problematic in that sense, as CH0 can't run free all by itself. There will be some delay for every update of CH0, especially at waveform top peaks (high frequency DSM signal). In addition (as mentioned), the frequency filter before the speaker might have some impact as well on a variable frequency signal.

I guess that's one way to think about it. The effective bitrate there would be whatever the fastest channel 0 rate is that the routine can run at - maybe 20kHz at most on a 4.77MHz machine (hardware interrupts have a lot of overhead). It would also be a very "weird" sort of compression as you'd burn through data much faster when the speaker is in the high position than when it is the low position (essentially only runs of N lots of "0" bits would be optimized).

deathshadow
September 3rd, 2014, 11:47 PM
maybe 20kHz at most on a 4.77MHz machine
Real-world more like 6khz if you're lucky...

chjmartin2
September 4th, 2014, 07:30 PM
This. (Which also explains why the PWM timer method sounds so good.)

Just for giggles I attempted some SDM stuff tonight @ 96KHz and the results were hilariously terrible -- worse than just taking the most significant bit of a sample and outputting that instead (ie. simple 1-bit samples). I can post examples for the curious, but honestly it's not worth it. The only thing that sounded close to normal was 8x oversampling of the source, which limited the source to 12KHz sampling frequency. PWM can already do better than that.

I would still like to see (hear) it.

chjmartin2
September 4th, 2014, 07:55 PM
I understand all the words in that sentence, but I'm afraid I have no idea what you mean by it!

Ok... so we have 6 modes (http://en.wikipedia.org/wiki/Intel_8253) for the PIT right?

There has to be a way to process a 22 KHz audio signal (or some other frequency) and creatively use the PIT to generate a true SDM (PDM) signal. This (http://www.cs.tut.fi/sgn/arg/rosti/1-bit/) is a great page on DM and SDM by the way... There are 6 different ways to manipulate the PIT. If you look at the picture below, it shows that there are long stretches of high and low. I realize that PWM and SDM are close - but not the same, using the PIT to implement SDM should sound much better. And when I look at having 6 different ways to adjust the bit pattern I am more convinced there is a way to do it. Like, send some type of signal to the PIT and have it be the oversampler in some way. Does that makes sense to you?

20291

I am sad to hear that Jim's SDM experiment at 9X Khz was bad, because, that is the frequency I used for the Aquarius. (Trix - did you use a 16 bit input signal? If you start with 8 bit the SDM encoding really suffers, at a 16 bit starting point it is DRAMATICALLY better. Did you take the output of your SDM encoder, make it a raw audio output file and bring it into Cooledit or similar to test it?)

chjmartin2
September 4th, 2014, 07:57 PM
In addition (as mentioned), the frequency filter before the speaker might have some impact as well on a variable frequency signal.

As was explained to me by Intvnut (over at Atariage) the Low Pass filter is exactly what you want on the output side of an SDM.

chjmartin2
September 4th, 2014, 08:01 PM
Effective bit rate or actual bit-rate? Meaning - you are saying only 20,000 high and low's to the speaker per second? That would have a horrible 10 KHz buzz... Now, if it is 20 KHz input but over sampled output, then that would sound great - no idea how it would be versus PWM, but would be great...

Trixter
September 4th, 2014, 09:24 PM
I would still like to see (hear) it.

I warned you:


http://youtu.be/J5_KhQ-eLJA

It is possible my conversion code was wrong, but I still don't think it's worth pursuing. (So what is worth pursuing? I've been working on compression schemes that are simple enough to decompress realtime as part of the PWM playback routine. 4:1 compression of 8-bit PCM is my target, and I have two schemes that achieve that although both have their drawbacks. I have two more ideas I'd like to try, and then someday I'll put all of this on the web in a series of articles.)

reenigne
September 4th, 2014, 10:02 PM
Ok... so we have 6 modes (http://en.wikipedia.org/wiki/Intel_8253) for the PIT right?

Yes, and none of them are particularly useful for SDM.


If you look at the picture below, it shows that there are long stretches of high and low.

Long stretches of high and low == PWM, essentially. It's the parts where the signal changes rapidly (and at precisely the right times) that give SDM its advantage over PWM, and the PIT won't help you - none of its modes have more than one run of 0 output bits or more than one run of 1 output bits per full countdown cycle.


And when I look at having 6 different ways to adjust the bit pattern I am more convinced there is a way to do it. Like, send some type of signal to the PIT and have it be the oversampler in some way.

I don't understand how the PIT could be an oversampler (or, really, what an oversampler is in this context).

chjmartin2
September 5th, 2014, 03:45 AM
Yes, and none of them are particularly useful for SDM.

You would understand better than me how each mode works. What I have as a nagging feeling is that we can get the right number of 1's and 0's to the speaker, at the right timing, we just can't get the precise order that we want.

reenigne
September 5th, 2014, 03:51 AM
What I have as a nagging feeling is that we can get the right number of 1's and 0's to the speaker, at the right timing, we just can't get the precise order that we want.

Yes! That is something we can definitely do, and that is exactly what PWM is.

chjmartin2
September 5th, 2014, 03:52 AM
It is possible my conversion code was wrong, but I still don't think it's worth pursuing. (So what is worth pursuing? I've been working on compression schemes that are simple enough to decompress realtime as part of the PWM playback routine. 4:1 compression of 8-bit PCM is my target, and I have two schemes that achieve that although both have their drawbacks. I have two more ideas I'd like to try, and then someday I'll put all of this on the web in a series of articles.)

The other pursuits you have laid out are much more practical certainly. I would also tell you that there is DEFINITELY something wrong with your converter. Can you post the PLAY100 executable? I assume the one bit file is just a packed sample or is it a custom bit packing scheme? This (http://atariage.com/forums/index.php?app=core&module=attach&section=attach&attach_id=235812) is what 100KHz and 1 bit SDM sounds like from the Aquarius. It is noisy no doubt, which is likely do the difference between the rising square versus the falling, in addition to the system noise on the speaker line. But you can see that it certainly sounds better than your posted sample albeit with noise.

Let me have a shot at using your player. :)

per
September 5th, 2014, 03:59 AM
What I have as a nagging feeling is that we can get the right number of 1's and 0's to the speaker, at the right timing, we just can't get the precise order that we want.
Exactly; timing is the keyword.

The only way for these old PCs to properly keep track of timing is by using timer channel CH0 to interrupt the CPU at fixed time intervals. During the interrupt, the CPU can trigger CH2 to send a pulse to the speaker. This is great for PWM, but for SDM the timer simply lacks the flexibility you need. Updating CH0 would be a posibility, but it screws up the timing due to delays, and the CPU is still too slow for the highest frequencies. If the CPU was fast enough, you should be able to bit-bang the speaker with SDM data at a very high frequency, but you'll at least need a 386 for that.

reenigne
September 5th, 2014, 04:09 AM
It is noisy no doubt, which is likely do the difference between the rising square versus the falling, in addition to the system noise on the speaker line.

It would be an interesting experiment to write an "ideal 100kHz SDM decoder" and see what the theoretical top quality you could get from this scheme is (i.e. with no system noise or rise/fall time). It would be trivially easy to do - just output it as raw 8-bit PCM data (i.e. 0s and 255s) with a 100kHz sample rate. Cool Edit Pro (and probably other similar audio software) can open such files and resample them to a suitable rate for playback so you can see what it should sound like.

I haven't tried it, but I suspect you'll find that the high-pitched noise is fundamental to the technique (at least at a 100kHz bitrate) and that removing system noise and rise/fall time will make less difference than you think.

Trixter
September 5th, 2014, 07:42 AM
Yes! That is something we can definitely do, and that is exactly what PWM is.

And with that statement, I fully understand both schemes now, LOL.


I would also tell you that there is DEFINITELY something wrong with your converter

That is likely. I will try to convert the posted C code earlier, which was tested and verified by its author on the previously-referenced thread.


Can you post the PLAY100 executable? I assume the one bit file is just a packed sample or is it a custom bit packing scheme?

It is just a stream of bits that are sent to the speaker. Playback interrupt routine is:
(code by Alan D. Jones, comments are mine)



;packed bits are in CH
;maneuver bit into position 1, set other bits required for port, output to speaker
SUB AL,AL
RCL CH,1
RCL AL,1
RCL AL,1
OR AL,NORMPPI
OUT DX,AL

;housekeeping to determine if we need to load another byte
INC AH
CMP AH,8
JNE TMRINT1
SUB AH,AH

INC BX
MOV CH,[BX]
CMP BX,FILELEN
JNZ TMRINT1
INC BP

;acknowledge timer interrupt
TMRINT1:
MOV AL,20H
OUT 20H,AL
IRET


Andrew is probably trying to figure out how this works at 100KHz on a 4.77MHz 8088 when it is timer-clocked. The obvious answer: It doesn't! I tested it in DOSBox and on a Pentium system I have hooked up at my desk. (It does work at 16KHz, despite the extra junk in the interrupt handler.) For an attempt at 100KHz you would do this in a tight loop, not in an interrupt.


Let me have a shot at using your player. :)

Grab xtfiles.rar from ftp://ftp.oldskool.org/pub/misc/ , unpack it and go to apputils/sound/speaker/1-bit, copy play.asm to play100.asm, and change the COUNTR line to 12. I compiled it with TASM+TLINK but MASM or NASM should work too.

Trixter
September 5th, 2014, 10:50 AM
I would also tell you that there is DEFINITELY something wrong with your converter

I found the bug in the converter (it's not a bug, but rather my misunderstanding of the method). A converter that oversamples is mandatory, so I'll try this again tonight.

Because oversampling is mandatory, I have to ask: In your Aquarius examples, what was the source sampling rate, and what was your oversampling factor? (Based on this thread, I'm guessing you used a 12.5KHz 16-bit file as the source, with 8x oversampling -- am I right?)

chjmartin2
September 5th, 2014, 05:12 PM
I found the bug in the converter (it's not a bug, but rather my misunderstanding of the method). A converter that oversamples is mandatory, so I'll try this again tonight.

Because oversampling is mandatory, I have to ask: In your Aquarius examples, what was the source sampling rate, and what was your oversampling factor? (Based on this thread, I'm guessing you used a 12.5KHz 16-bit file as the source, with 8x oversampling -- am I right?)

No. I up-converted to the target sample rate. The oversampling is not needed. When I took at look at your code, you were using "high" as 1 and low as a 0, but because you are forward distributing the error, if you were using a 16 bit input then it would be 32767 as high and -32768 as low. But I am not sure. I plan on playing with your player this evening/this weekend so we'll see what happens when I take the output of my SDM converter and play. Will post results as soon as done!

chjmartin2
September 5th, 2014, 07:22 PM
Grab xtfiles.rar from ftp://ftp.oldskool.org/pub/misc/ , unpack it and go to apputils/sound/speaker/1-bit, copy play.asm to play100.asm, and change the COUNTR line to 12. I compiled it with TASM+TLINK but MASM or NASM should work too.

SAB2.COM (.EXE?) hit my Avast for a Trojan... thought you should know.

Trixter
September 5th, 2014, 08:03 PM
When I took at look at your code, you were using "high" as 1 and low as a 0, but because you are forward distributing the error, if you were using a 16 bit input then it would be 32767 as high and -32768 as low.

You're absolutely right, that was a screwup on my part. I fixed it and got much better results.


But I am not sure. I plan on playing with your player this evening/this weekend so we'll see what happens when I take the output of my SDM converter and play. Will post results as soon as done!

Don't bother -- here are the results, including what the PWM method sounds like:


http://youtu.be/J-Hgu7fOCeU

Obviously the PWM method sounds best, so I see no need to pursue this further. Since the PIT can never generate exactly the sequence of bits we need, PWM is the best we can achieve.

The above was DOSBox output, but it sounds nearly identical on real hardware, with one exception. The PWM method, while producing the clearest sound, is also quite low in volume on real hardware. For clones with a volume control (like the Tandy 1000 series) this is not an issue, but for a real IBM PC, it is harder to hear. On any clone that used a piezo speaker attached to the motherboard, it is nearly inaudible.

While the raw MSB-type 1-bit output (the first example) sounds really scratchy, it has the advantage of being incredibly loud, which could be useful for speech (and, indeed was used for that with a few games in the 1980s).

chjmartin2
September 6th, 2014, 11:48 AM
It would be an interesting experiment to write an "ideal 100kHz SDM decoder" and see what the theoretical top quality you could get from this scheme is (i.e. with no system noise or rise/fall time). It would be trivially easy to do - just output it as raw 8-bit PCM data (i.e. 0s and 255s) with a 100kHz sample rate. Cool Edit Pro (and probably other similar audio software) can open such files and resample them to a suitable rate for playback so you can see what it should sound like.

I haven't tried it, but I suspect you'll find that the high-pitched noise is fundamental to the technique (at least at a 100kHz bitrate) and that removing system noise and rise/fall time will make less difference than you think.

When I made the encoder for the Aquarius I had wanted to be able to preview, so I had my player output PCM data reflective of the 1's and 0's for SDM. Here is the wave file. As you say, there is certainly still considerable noise, and far more noise than PWM at the max PIT clock.

20306

chjmartin2
September 6th, 2014, 05:28 PM
Obviously the PWM method sounds best, so I see no need to pursue this further. Since the PIT can never generate exactly the sequence of bits we need, PWM is the best we can achieve.
.

I agree that the PWM sounds by far the best. I listened to the output today and decided to move on, but it was nagging at me because 100 KHz SDM should sound better. Yes, it'll have noise, but it won't sound so "empty" the way it did. At first I decided to blame your converter, and then I went ahead and compiled Play100 and used my converter - but here's the kicker - I got the same "empty" sound. Of course I started scratching my head, and then decided I needed to see what was going on. What I figured out is that you didn't actually implement a 100 KHz SDM player because there is a really effective low pass filter on the PC Speaker output and the Aquarius doesn't have one. The over modulation is a key component for useful SDM. I agree with your conclusion that PWM is what we have, and can only agree with Reeng on the PIT not having anything useful because I know he forgot more about that stuff than me. Having said that, I wonder if the Parallel port would let us do a real SDM player.

Here's some visual evidence of my conclusion. (theory)

20307

You can see that the spectrum has noise all the way up there...

20308

And here is the output from an Aquarius playing back a 100K SDM signal consisting of 10101010101010101

Which brings us to this. I don't have a Pentium on my desk, nor could I use Jim's youtube file because that is likely to be all kinds of compressed. So, since I have my trust Tandy next to me, I used that. I wrote this program in QuickBasic:



for g=40 to 32767 step 5

sound g,.1

next g


Then I went ahead and captured the output. Soon as I saw it I knew that there was a Low Pass filter. My favorite part about this video is that no matter what you can see the 18.2 KHz signal out there throughout the entire frequency spectrum. Anyway, you can even see that the noise fall off at 22K is VERY pronounced. So, it would appear to me that if you oscillate the Speaker at anything about 22 KHz, there is some kind of RC circuit removing that part of signal.


http://youtu.be/6NQMUvNX1xA

chjmartin2
September 6th, 2014, 05:38 PM
I also forgot. For those that would ask me why PWM works even with the cut-off. I would remind them that in fact, there is a limitation. You don't have as many levels as you want, you can only get to the point where the low pass filter doesn't cut-off the signal, if the period were too short, like 110011001100, then the output gets cut off. If we could somehow bypass the RC component, I bet you could make a much higher quality PWM as well...

(not looking forward to the pies headed my way...)

Trixter
September 6th, 2014, 09:44 PM
I wonder if the Parallel port would let us do a real SDM player

Meaning, if we wired up a pin to speaker voltage and toggled it? Maybe... but if you're going to go through the trouble of hooking up something to the parallel port, why not just make an LPT DAC (http://en.wikipedia.org/wiki/Covox_Speech_Thing) and have better output quality at smaller data rates? Alternately, you can hook up a Disney Sound Source -- it's also an LPT DAC, but with three differences:


Has an actual low pass filter (that works; the output quality is very nice)
Has a 16-byte FIFO (ie. can send 16 bytes at a time, then return control back to the host)
Output rate fixed at 7KHz


#3 is a real doozy; it limits the usefulness of the device to speech and sound effects. But the upside is that the CPU PIT 0 interrupt rate only needs to be ~450 Hz which is quite doable on an 8088.

All this talk has been interesting, but it's also proven to me that SDM is the kind of thing you use when you have extremely high output rates (way, way higher than 100KHz). In researching hardware that uses this technique, I saw things like "64x oversampling" which would imply that a 48KHz source signal was outputting bits at a rate slightly over 3MHz (!).


Soon as I saw it I knew that there was a Low Pass filter

...on a Tandy. I'll be cracking my 5155 open this weekend and I'll try to remember to attach alligator clips to the speaker leads and capture the same sweep just to see what I get.

reenigne
September 6th, 2014, 11:20 PM
What I figured out is that you didn't actually implement a 100 KHz SDM player because there is a really effective low pass filter on the PC Speaker output and the Aquarius doesn't have one.

That won't make any difference to how it sounds. The human ear can't hear sounds above 22kHz anyway, so it doesn't matter whether those frequencies are attenuated in the RC filter, the speaker or the ear. Again you can verify this in Cool Edit Pro by applying a filter yourself.

I'm sure the difference you're hearing is due to other differences of the sound hardware (i.e. different frequency response, resonances etc) or differences in the playback routine. Both Aquarius and PC speaker playback routines will have some jitter in exactly when each bit is output due to the DRAM refresh timing - this is likely to cause audible interference that will be different on the two machines.

In your example of outputting a PWM signal with a very high frequency carrier like 0011001100110011... the effect of the filter will be that the speaker cone position averages out to the 50% level. Similarly for 00010001... and 01110111... it'll move to the 25% and 75% levels respectively - which is exactly what you want. So you get a dynamic range of 5 positions (log 5/log 2 bits). The carrier signal (being over 22kHz) will be cut off (which is what you want) but the actual audio data that you do want to keep is still below the cutoff frequency and will be kept intact.

With PWM, you can always improve sound quality by increasing sample rate at the expensive of dynamic range (keeping the speaker bit rate the same). The limit of this process (for PC speaker, if it were possible) would be a dynamic range of 1 bit at a sample rate of 1.193MHz - i.e. SDM (but at a much faster rate than the 100kHz you've been playing about with).

chjmartin2
September 7th, 2014, 06:53 AM
That won't make any difference to how it sounds. The human ear can't hear sounds above 22kHz anyway, so it doesn't matter whether those frequencies are attenuated in the RC filter, the speaker or the ear. Again you can verify this in Cool Edit Pro by applying a filter yourself.

Are you sure? What I mean is, if the faster switching voltage is filtered out doesn't that impact the cone position? I tried to apply the filter in Cool Edit myself, but we don't end up with the square wave anymore, now, I guess that is the point of sending a square wave through a LPF. My brain hurts because last night I was convinced we were losing signal not noise from the LPF...

Trix - you are right, SDM is made for much much higher frequencies. And, if we were to go through the trouble of using the LPT port, then we might as well install a Sound Blaster or build a resistor bridge DAC. I will add that for me this has not been throwaway work - I have something else I am cooking up. Nothing earth shattering, but somewhat novel. You'll see...

chjmartin2
September 7th, 2014, 06:56 AM
...on a Tandy. I'll be cracking my 5155 open this weekend and I'll try to remember to attach alligator clips to the speaker leads and capture the same sweep just to see what I get.


Even worse is that I am using the headphone jack, so who KNOWS what kind of RC they have on that versus even the speaker leads. After I wrote this I stood up and look at the MB near the connectors, and it is like cap/resistor heaven down in there...

reenigne
September 7th, 2014, 09:58 AM
Are you sure? What I mean is, if the faster switching voltage is filtered out doesn't that impact the cone position?

No, the cone can't move that fast anyway. A speaker cone essentially has its own intrinsic low-pass filter caused by its own inertia and the limit of the magnetic force that can be applied to it.


I tried to apply the filter in Cool Edit myself, but we don't end up with the square wave anymore, now, I guess that is the point of sending a square wave through a LPF. My brain hurts because last night I was convinced we were losing signal not noise from the LPF...

In digital signal processing theory, there is no such thing as a square wave anyway because we only ever deal with band-limited signals. In other words, if we have a waveform sampled at N samples per second, we assume that it's a sum of sine waves with frequencies up to N/2 Hz (the Nyquist limit), and that all of the frequencies above that are zero (if such frequencies were present, they would alias with frequencies less than N/2 and create unwanted noise). A true square wave would have infinitely high frequencies to get sharp high<->low transitions, so would require an infinitely high sample rate to represent.

So if you zoom in to a waveform down to the level of individual samples and see a graph with horizontal steps for each sample and vertical lines connecting adjacent samples, that's the wrong way to think about it. Instead you should think of a smooth curve that passes through the sample points and which doesn't wiggle more often than once in two samples.

So applying a low-pass filter to a sampled signal is essentially just the same thing as reducing the sample rate (cutting off frequencies higher than N/2) and then increasing it again (to the original sample rate, while keeping it sounding the same as in the reduced waveform). So the high frequency wiggles are removed, but the average position remains the same.

Trixter
September 21st, 2015, 12:19 PM
I'll be cracking my 5155 open this weekend and I'll try to remember to attach alligator clips to the speaker leads and capture the same sweep just to see what I get.

I believe I forgot to respond to this. I performed a linear sweep from 20 to 65535 HZ using an impromptu BASIC program on an IBM 5155 (essentially a portable 5160 with the same speaker) and recorded the output using a USB microphone capable of 16/96 recording. I've misplaced the results, but they clearly showed a frequency range above 22KHz. In fact, I think the entire 20-65535Hz sweep was visible on the FFT graph. It was really cool watching the FFT display continue to show a rising frequency long after I couldn't hear anything!

commodorejohn
September 21st, 2015, 03:19 PM
#1 sounds the worst and is limited to square wave tones, but it has the least CPU utilization.
While this is technically true, I think it's fair to note that you can do a lot more with it than just static beeps. Provided you can do suitably fast note changes or some form of algorithmic frequency modulation, you can create some interesting musical cues or really pretty wild tones just with rapidly-modulated square waves. (Listen to Jill of the Jungle with Sound Blaster FX off for some good examples of the kinds of weird noises you can make with it.)

Trixter
September 21st, 2015, 08:06 PM
Oh, I'm well aware of what the PC speaker is capable of (http://trixter.oldskool.org/2015/04/07/8088-mph-we-break-all-your-emulators/) ;-)