Larry Osterman's WebLog

Confessions of an Old Fogey
Blog - Title

Beep Beep

Beep Beep

Rate This
  • Comments 44
What's the deal with the Beep() API anyway?

It's one of the oldest Windows API, dating back to Windows 1.0.  It's also one of the few audio APIs that my team doesn't own.  The Beep API actually has its own dedicated driver (beep.sys).  The reason for this is that the Beep() API works totally differently from any other audio API in the system.

Back when IBM built the first IBM PCs, they realized that they needed to have the ability to do SOME level of audio, even if it wasn't particularly high quality.  So they built a speaker into the original PC hardware.

But how do you drive the speaker?  It turns out that the original PC hardware used an 8253 programmable interval timer to control the system hardware timer.  The 8253 was a pretty cool little chip - it would operate in 5 different modes - one shot timer, interrupt on terminal count, rate generator, square wave generator, software strobe or hardware strobe.  It also contained three independent counters - counter 0 was used by the operating system, counter 1 was reserved for the hardware.  The third counter, counter 2 was special.  The IBM hardware engineers tied the OUT2 line from the 8253 to the speaker line, and they programmed the timer to operate in square wave generation mode.

What that means is that whenever the 2nd counter of the 8253 counted to 0, it would toggle the output of the OUT2 line from the 8253.  This gave the PC a primitive way of generating very simple tones.

The original Windows Beep() API simply fiddled the controls on the 8253 to cause it to generate a square wave with the appropriate frequency, and that's what Beep.sys continues to do.  Legacy APIs can be hard to remove sometimes :)

Nowadays, the internal PC speaker is often also connected to the PCs audio solution, that allows the PC to have sound even when there are no external speakers connected to the machine.

In addition to the simple beep, some very clever people figured out how they could use the 8253 to generate honest to goodness audio, I'm not sure how they succeeded in doing it but I remember someone had a PC speaker based sound driver for DOS available at one point - it totally killed your PCs performance but it DID play something better than BEEEEEEP.

Edit: s/interrupt conroller/interval timer/

Edit2: fixed description of channel 1 (in case someone comes along later and decides to depend on my error).

  • Actually, port 1 was not available for applications. It was used for driving RAM refreshing cycles. By increasing the divider in channel 0x1 the memory could be "overclocked" by the virtue of decreasing the chances of the memory bus being busy with refreshing. The downside was -- you guessed it right -- risk of loosing data.

    This channel was not used in PS/2 and later models, and there was no access to it's output (not documented, at least)
  • Does printf("\7") work the same way as Beep()

    -Jeu George
  • I get "translation" of beeps by Virtual PC (and VMWare) from the virtual machine out to the audio card of the host machine. It is phenominally annoying, as I habitually use my audio player to control the volume... so every now and then I get a violently loud beep from the client. I can't disable this by disabling/uninstalling the system.speaker either!
  • One of my first applications written when I was very young was in the QBasic interpreter that shipped with MSDos.

    Played different tones over the PC Speaker in a loop. At the time I found it fairly interesting :-)

    Interesting enough, up until a few days ago, the .NET framework only had a single Beep() API via the one of the VB assemblies. I spent today ripping out my Interop calls to the wav-based 'system beeps' and moving them to .net 2.0.

    Thanks for the great post!
  • in CMD, type "echo ^g" (^g mean you click CTRL-G, not Shift-6 G) - you'll get a beep, presumably a Beep(). I use it all the time to get notified when some log command finishes:

    xcopy bla & echo ^g
  • "net stop beep" will silence the beeper.

    Ideal for when you've just accidentally listed several pages of 0x07 rich binary to the console.
  • for the guy sitting next to the beeping girl - net stop beep should solve your problem :-)
  • I remember a DOS driver that used i386’s protected mode to emulate a Sound Blaster on either PC Speaker or Covox. Covox was a simple 8-bit DAC which was plugged into an LPT port, and gave much better sound than 1-bit PC Speaker. Performance-wise, yes, it was a nightmare.
  • I remember stumbling accross the beep command while porting a DOS app to Windows (an emulator for an old computer. The PC speaker was to emulate its sound). On 9x one could still use the ports to control the speaker, but on NT beep was the only way. Back then the MSDN docs said "if passed 0 for duration, the call will immediatelly return while the beep keeps playing" or something like that. Perfect! Exactly what I needed! Except, it didn't work. The disassembly showed that value 0 is handled specially, but the jump went directly to the "kill beep" code sequence...

    Somewhat later it was fixed. Not the buggy driver, of course, the doc just didn't mention the 0 value anymore. :-/ That's why my app stayed silent on NT until years later I finally mustered the courage to write some fairly complex DirectSound code to fix it.
  • thanks for "net stop beep", it saved my night!
    but why doesn't "beep" appear as a service when I do "net start"?
  • "beep" is a driver (beep.sys). The "Net stop" command can be used to stop both drivers and services (loosely speaking, the service controller is responsible for starting drivers)
  • The way programs generated high-quality audio was to kick timer 2 into one-shot mode instead of the regular square-wave mode, then drive it from IRQ0 at sampling rate, varying the width of the output pulses based on the sound samples. The result was a reasonably good ~6-bit reproduction of the sound, along with the sampling rate frequency. Raising the timer rate high enough (22KHz+), along with the inertia of the speaker, made the latter inaudible. If you were unlucky enough to have a piezoelectric speaker, through, the scheme didn't work.

    One really nice feature of this scheme was that the sound ran in the background like real sound hardware, and the interrupt routine was fast enough to still allow foreground tasks. You could set up a "DMA buffer" along with read/write pointers and soft interrupts back to the main code, and treat it much like any other sound card. I once wrote a video player for DOS this way. It became very clear if other drivers were spending too much time with interrupts disabled, however. It also didn't work on most DOS emulation environments due to interrupt handling latency, although impressively it _almost_ worked in an OS/2 DOS box.
  • Hey, does that mean that if my video card / network card drivers have gone weird that I can "net stop"/"net start" them to reset them without rebooting?
  • Miral, you can try, but I'm willing to bet that it won't work.

    The video card driver is loaded by win32k.sys, the only way to unload/reload that is by rebooting the machine.

    The network stack can be unloaded but that assumes that every app that uses it knows how to deal with PnP notifications - most don't
  • The correct way to generate computer music in the old days was to put an AM radio next to the CPU. And yes there were programs for some machines that execute various loops the right number of times to cause some transistor somewhere to send out the right kind of EMI to do it.

    The correct way to turn off sound on such a machine was to rotate the AM radio's volume control all the way to the left.

    On a more modern machine, if it's a desktop machine then you can open the case and pull the speaker off of its jumpers. If it's a notebook machine then you can open the case and use some diagonal cutters.
Page 2 of 3 (44 items) 123