First, you need your OS (I assume 32bit, but it may work on 16-bit too) to have IDT functional, because you need to work with the timer interrupt. You also need to know the .WAV file size and it's sampling rate, and it must be loaded at ESI. Before continuing, unmask the IRQ0 if you have it disabled. You also need a function to change the PIT's IRQ0 frequency (if you have PIT running on e.g. 100hz, you already have one). Also, the WAV file must be uncompressed PCM!
Declare these variables as global:
Code: Select all
WAVSamplingRate dw 0
WAVFileSize dd 0
EnableDigitized db 0
Insert this into your IRQ 0 routine:
Code: Select all
irq0_int:
...
cmp [EnableDigitized],1 ;If it's set to 1, process next lines of code
jne NoDigitizedSound ;If not, do the standard irq0 routine
cmp al,0x80 ;If the byte taken from the memory is less than 80h,
;turn off the speaker to prevent "unwanted" sounds,
jb TurnOffBeeper ;like: ASCII strings (e.g. "WAVEfmt" signature etc).
mov bx,[WAVSamplingRate] ;Turn on the speaker with the WAV's sampling rate.
call Sound_On
jmp Sound_Done
TurnOffBeeper:
call Sound_Off
Sound_Done:
inc esi ;Increment ESI to load the next byte
NoDigitizedSound:
...
;;;; BE SURE TO SEND THE EOI SIGNAL TO THE PIC AT THE END OF THE IRQ!! ;;;;;
;;;; Here's how it can be done: ;;;;;
...
mov al,0x20
out 0x20,al
iret
Code: Select all
;; PC speaker wave player PCSPEAKR.ASM
Sound_On: ; A routine to make sounds with BX = frequency in Hz
mov ax,0x34dd ; The sound lasts until NoSound is called
mov dx,0x0012
cmp dx,bx
jnc Done1
div bx
mov bx,ax
in al,0x61
test al,3
jnz A99
or al,3 ;Turn on the speaker itself
out 0x61,al
mov al,0xb6
out 0x43,al
A99:
mov al,bl
out 0x42,al
mov al,bh
out 0x42,al
Done1:
ret
Sound_Off:
in al,0x61
and al,11111100b ;Turn off the speaker
out 0x61,al
ret
PlayWAV:
mov [WAVSamplingRate],;;;;;;;;;;;Your sampling rate;;;;;;;;;;;;
mov [WAVFileSize],;;;;;;;;;;;; Size of your WAV file ;;;;;;;;;;;;;
mov esi,FileLoaded ;;;;;;;;;;;;;; ESI = offset where the file is ;;;;;;;;;;;;;
mov cx,[WAVSamplingRate] ;IRQ0 fires e.g. 6000 times a second
call ProgramPIT ;when a 6000Hz WAV file is played. This is how
;the speaker can play the digitized sound:
;it turns on and off very fast with the specified
;wave sample rate.
mov ecx,[WAVFileSize] ;Sets the loop point
mov [EnableDigitized],1 ;Tells the irq0 handler to process the routines
Play_Repeat:
lodsb ;Loads a byte from ESI to AL
hlt ;Wait for IRQ to fire
loop Play_Repeat ;and the whole procedure is looped ECX times
mov [EnableDigitized],0 ;Tells the irq0 handler to disable the digitized functions
mov cx,0x12
call ProgramPIT ;Return to 18.2 kHz IRQ0
call Sound_Off ;Turn the speaker off just in case
ret
-EDIT: Corrections made here and there
-EDIT 2: Added comments.
-EDIT 3: Fixed the bracket opcodes. (19:41 CET)
Regards
inflater