1

I'm trying to write a program in TASM that plays music notes. I couldn't find any documentation online and the closest thing I found was this stackoverflow question, which is able to produce a "beep" sound.
What I don't know is:

  1. How this code works

  2. What the sound mapping is

  3. How I can play specific notes (do re mi...)

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
Ariel Yael
  • 361
  • 2
  • 10

1 Answers1

3

Playing a single tone with PC speaker may use method mentioned in the quoted question. It uses square-wave generator from system timer, activated by setting mode of operation 0xB6 to I/O port 0x43. See Timer Ports. The value 182=0xB6=0y10110110 written to port 0x43 specifies

  • selection of timer counter Nr.2 (bits 6-7)
  • endianess: LowByte first, HighByte second (bits 4-5)
  • mode 3: square-ware generation (bits 1-3)
  • format 0: binary mode (bit 0). Then you are expected to specify the required frequency with OUT 0x42,LowByte and OUT 0x42,HighByte. This 16bit binary integer number actually specifies period of the square wave, i.e. the number of ticks that must elapse to flip the wave from 0 to 1 and vice versa.

When you have programmed the frequency, ask the Programmable Peripheral Interface to connect speaker to the square-wave generator. This is done by setting the two least significat bits if PPI port 0x61, see PPI Ports.

   IN AL,0x61   ; Get the previous value of PPI port B.
   OR AL,0x03   ; Set the two least significant bits.
   OUT 0x61,AL  ; Write it back to PPI port B.

Now you should wait some time to let the tone play and then reset the two bits back to 0 at PPI port B.

Mapping of musical tones to frequencies you can find here. You will need a table to convert the frequency of do, re, mi etc tones to 16bit integer numbers which you will put to the system timer as LowByte and HighByte.

See sample code how to get LowByte and HighByte. PC timer ticks at 1193180 Hz. When you want to play the tone do (note C4=261.63 Hz), calculate 1193180/261.63=4560=0x11D0. LowByte=0xD0 and HighByte=0x11.

vitsoft
  • 5,515
  • 1
  • 18
  • 31
  • Thanks for the answer! So I need to take the wavelength (cm) from your table, and round it to the nearest integer? – Ariel Yael Feb 22 '22 at 19:45
  • @ArielYael Not exactly, the wavelength needs to be scaled by a coefficient which depends on the timer clock frequency. I updated my asnwer with an example. – vitsoft Feb 22 '22 at 21:11
  • I understand now, but something in the code is still unclear.. why do we use `mov al, 182`? doens't it overwrite the input frequency we store in ax? – Ariel Yael Feb 23 '22 at 15:11
  • @ArielYael Yes, it does., it's a mistake in MathAsker's code. He obviously didn't care of the exact frequency. – vitsoft Feb 23 '22 at 15:36
  • could you also explain please why we specifically use 182(=0xb6)? – Ariel Yael Feb 23 '22 at 15:40