package assembly pc_sound is if memory_model = 0 then pragma memory_model(0); else pragma memory_model(1); end if; CSEG jmp main -- jump to initialization DSEG prevwhistle db ? a_sample_duration dw ? on_off_bytes db 256 dup(?) CSEG on_off_pattern equ $ dw 2#00000000_11111111# -- 0 nibbles are in sign+magnitude form dw 2#00000001_11111111# -- 1 dw 2#00000011_11111111# -- 2 dw 2#00000111_11111111# -- 3 dw 2#00001111_11111111# -- 4 dw 2#00011111_11111111# -- 5 dw 2#00111111_11111111# -- 6 dw 2#01111111_11111111# -- 7 dw 2#00000000_11111110# -- -1 dw 2#00000000_01111110# -- -2 dw 2#00000000_00111110# -- -3 dw 2#00000000_00011110# -- -4 dw 2#00000000_00001110# -- -5 dw 2#00000000_00000110# -- -6 dw 2#00000000_00000010# -- -7 dw 2#00000000_00000000# -- -8 get_ticks: -- return current tick count in ax xor al,al pushf -- save int enable status cli -- lock out interrupts out 43h,al -- read counter 0 jmp short gtl -- (don't go too fast) gtl: in al,40h -- get lsb of timer xchg ah,al -- jmp short gth -- (don't go too fast) gth: in al,40h -- get msb of timer xchg ah,al -- popf -- restore int enable status ret play_ax_till_dx: -- destroys ax,bx -- high nibble of al contains amplitude -- dx contains timeout value mov bx,on_off_bytes add bx,ax xchg si,bx even pbd_loop: -- output 16 speaker on/off bytes, then, push dx -- if we haven't timed out, do it again mov dx,61h lodsw out dx,al mov al,ah out dx,al lodsw out dx,al mov al,ah out dx,al lodsw out dx,al mov al,ah out dx,al lodsw out dx,al mov al,ah out dx,al lodsw out dx,al mov al,ah out dx,al lodsw out dx,al mov al,ah out dx,al lodsw out dx,al mov al,ah out dx,al lodsw out dx,al xor al,al pushf -- save int enable status cli -- lock out interrupts out 43h,al -- read counter 0 mov al,ah out dx,al in al,40h -- get lsb of timer xchg ah,al -- sub si,16 in al,40h -- get msb of timer xchg ah,al -- popf -- restore int enable status pop dx cmp ax,dx jns pbd_loop xchg si,bx ret play_it_out: -- ds:si => sound block -- cx => N of bytes in sound block -- destroys ax,bx,dx and si,cx call get_ticks mov dx,ax cld play_it_out_loop: mov al,es:[si] and ax,16#00F0#; sub dx,[a_sample_duration] call play_ax_till_dx mov al,es:[si] inc si and ax,16#000F# shl al,1 shl al,1 shl al,1 shl al,1 sub dx,[a_sample_duration] call play_ax_till_dx loop play_it_out_loop mov al,[prevwhistle] out 61h,al ret procedure set_sample_rate(samples_per_second:in sample_rates) is pop ax -- save ret address if memory_model = 1 then pop dx end if; pop cx -- cx:=sound_length if memory_model = 1 then -- restore ret address push dx end if; push ax mov ax,13532 -- dx:ax := 1193180 mov dx,18 div cx mov [a_sample_duration],ax if memory_model = 0 then ret else ret far end if; end set_sample_rate; procedure playback(sound:in system.address;sound_length:in natural) is -- clobbers ax,bx,cx,dx,si pop ax -- save ret address if memory_model = 1 then pop dx end if; pop cx -- cx:=sound_length pop si -- si:=sound(sound'first)'address mov bx,es les si,lword ptr[si] if memory_model = 1 then -- restore ret address push dx end if; push ax push bx call play_it_out pop es if memory_model = 0 then ret else ret far end if; end playback; main: mov ax,149 -- default sample rate:=8K mov [a_sample_duration],ax in al,61h mov [prevwhistle],al and al,16#FD# mov bl,al -- fill on_off_bytes with 16 lists of 16 mov di,on_off_bytes -- speaker control bytes, on and off matching mov cx,16 -- the bits in on_off_pattern cld mov si,on_off_pattern amplitude_loop: push cx seg cs lodsw mov cx,16 bit_loop: mov bh,2 -- bh:=non_speaker_bits | one bit from ax and bh,al or bh,bl mov [di],bh inc di ror ax,1 loop bit_loop pop cx loop amplitude_loop end pc_sound;