Assembly Language: How to Make Sounds example

This code example provides a set of keyboard routines to control sound output while waiting for a user to enter a keyboard character. The advantage to this method is that a main routine can call these sound routines to play a sound sequence, and the sound routines will return control back to the main routine whenever the user enters keyboard data so that the main routine can continue computing while the sound plays in the background. The code example has two different code entry points for getting keyboard data. One code entry point is a standard get_keyinput call which will wait for a key and update the sound data until a key code is found. The other code entry point is the get_keyinput_to call, which will wait a set amount of time for a key code and if none is found, return with a no key code found condition. The calling routine puts a timeout counter value in register AX on entry. The counter value is based on the system clock which ticks at 18.2 times per second. The entry point start_table_sound is used to begin a background sound sequence. On entry, the register BX indexes a table of sound data. The table has a format of four byte entries and is terminated by a data word of zero. The four bytes are used as two words: the first is a duration count and the second is a tone value. There are two code entry points for turning the background sound off and on. There is also a utility to flush out the keyboard buffer that can be executed with a call to flush_keyboard.

;Set of keyboard routines with sound outputs
.MODEL small
.STACK 500
.DATA
  ;define table for sound output
;sample_sounds      dw   8,45000   ;long low sound
;              dw   2,2000         ;short high sound
;              dw   0              ;end of sample sound table

sound_table    dw   0
sound_time_m   dw   0
sound_time_l   dw   0
sound_flag     db   0
sound_on_flag  db   0,0
key_time_out_m dw   0
key_time_out_l dw   0

.CODE
;************  ^^^^^^^^^^  *************
;### code entry point #####
get_keyinput   proc near
;this routine checks for keyboard data in BIOS buffer
 ; and returns with data if there
;else it updates sound output data and loops to check for
 ; keyboard data again until keyboard data found
;on exit AX has keyboard data
     public    get_keyinput
     push bx
     push cx
     push dx
get_keyinput_loop:
          mov  ah,1   ;set AH for scan
          int  16H    ;BIOS Call
           ;branch if no keyboard data
          jz   sound_update
          mov  ah,0   ;set AH for get key
          int  16H    ;BIOS Call
     pop  dx
     pop  cx
     pop  bx
     ret
;*******  -------- *******
sound_update:
     cmp  sound_flag,0        ;check for sound on????
     jz   get_keyinput_loop   ;branch out if sound off
     mov  cx,sound_time_m     ;else check for sound update
     mov  ax,sound_time_l
     call test_current_time   ;is it time for update ??
     jc   get_keyinput_loop   ;branch if not time
     mov  bx,sound_table
     mov  ax,[bx]             ;get next sound update value
     or   ax,ax               ;?? end of sound ??
     jz   turn_sound_off      ;branch if end sound
     call get_time_plus_ax    ;reset sound duration
     mov  sound_time_m,cx
     mov  sound_time_l,ax
     inc  bx
     inc  bx
     mov  ax,[bx]
     inc  bx
     inc  bx
     mov  sound_table,bx
     call sound_out_ax       ;go set sound frequency
     jmp  get_keyinput_loop  ;branch to keyboard loop
turn_sound_off:
     call sound_off
     mov  sound_flag,0
     jmp  get_keyinput_loop  ;branch to keyboard loop
get_keyinput   endp
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;************ ########## *************
;### code entry point #####
get_keyinput_to     proc near
;get keyboard data with timeout if no data available
;on entry AX has time duration in 18 ticks per second
;on exit if carry clear then AX has keyboard data
     public    get_keyinput_to
     push bx
     push cx
     push dx
     call get_time_plus_ax     ;add duration to current time
     mov  key_time_out_m,cx    ;set timeout value
     mov  key_time_out_l,ax
get_keyinput_to_loop:
     mov  ah,1                ;ready to scan keyboard data
     int  16H                 ;BIOS Call
     jz   sound_update_to     ;branch if no keyboard data
     mov  ah,0                ;ready to get key data
     int  16H                   ;BIOS Call
     pop  dx
     pop  cx
     pop  bx
     clc                        ;set keyboard data flag
     ret
get_keyinput_to_1:
     mov  cx,key_time_out_m     ;check for timeout
     mov  ax,key_time_out_l
     call test_current_time
     jc   get_keyinput_to_loop  ;branch if no timeout
     xor  ax,ax                 ;else timeout return condition
     pop  dx
     pop  cx
     pop  bx
     stc                        ;set no keyboard data flag
     ret
; ********  %%%%%%%  ********
sound_update_to:
     cmp  sound_flag,0        ;check for sound on????
     jz   get_keyinput_to_1   ;branch if sound off
     mov  cx,sound_time_m     ;else check for sound update
     mov  ax,sound_time_l
     call test_current_time
     jc   get_keyinput_to_1   ;branch if not ready for update
     mov  bx,sound_table
     mov  ax,[bx]
     or   ax,ax               ;test for end of table
     jz   turn_sound_off_to   ;branch if end of table data
     call get_time_plus_ax
     mov  sound_time_m,cx
     mov  sound_time_l,ax
     inc  bx
     inc  bx
     mov  ax,[bx]
     inc  bx
     inc  bx
     mov  sound_table,bx
     call sound_out_ax
     jmp  get_keyinput_to_1
turn_sound_off_to:
     call sound_off
     mov  sound_flag,0
     jmp  get_keyinput_to_1
get_keyinput_to     endp
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;************  @@@@@@@@@@  ************
;### code entry point #####
start_table_sound   proc near
 ;subroutine to start background sound output
 ;on entry BX indexes sound data table
     public    start_table_sound
     push ax
     push bx
     mov  ax,[bx]
     call get_time_plus_ax
     mov  sound_time_m,cx
     mov  sound_time_l,ax
     inc  bx
     inc  bx
     mov  ax,[bx]
     inc  bx
     inc  bx
     mov  sound_table,bx
     call sound_out_ax
     mov  sound_flag,0FFH
     pop  bx
     pop  ax
     ret
start_table_sound   endp

;************  ==========  *************
;### code entry point #####
flush_keyboard proc near
  ;utility to flush contents of keyboard buffer
     public    flush_keyboard
     mov  ah,1
     int  16H       ;BIOS Call  ;scan for keyboard data
     jz   flush_keyboard_x      ;branch if no keyboard data
     mov  ah,0                  ;else get keyboard data
     int  16H       ;BIOS Call
     jmp  flush_keyboard
flush_keyboard_x:
     ret
flush_keyboard endp

;*************  -----------  **************
sound_out_ax   proc near
  ;set sound out frequency to data value in AX
     push ax
     push ax
     cmp  sound_on_flag,0
     jne  sound_out_1
     in   al,61H         ;input port 61h
     or   al,3
     out  61H,al         ;output port 61h
sound_out_1:
     mov  al,0B6H
     out  43H,al         ;output port 43h
     pop  ax
     out  42H,al         ;output port 42h
     xchg al,ah
     out  42H,al         ;output port 42h
     mov  sound_on_flag,0FFH
     pop  ax
     ret
sound_out_ax   endp

;***********  $$$$$$$$$$  ************
;###### code entry point #######
sound_off proc near
   ;turn sound port off
     public    sound_off
     push ax
     cmp  sound_on_flag,0
     je   sound_off_exit
     in   al,61H         ;input port 61h
     and  al,0FCH
     out  61H,al         ;output port 61h
     mov  sound_on_flag,0
sound_off_exit:
     pop  ax
     ret
sound_off endp

;**************  %%%%%%%%%%  ***************
;with all CX:AX time values, CX is most significant
 ; and AX is least significant
get_current_time    proc near
;on exit CX:AX has 32 bit day clock value
 ; in 18.2 ticks per second
     push dx
          xor  ax,ax     ;set AH to zero
          int  1AH       ;BIOS Call get time
          mov  ax,dx
     pop  dx
     ret
get_current_time    endp

;****************************
get_time_plus_ax    proc near
;on entry AX has 16 bit value to add to current clock time
;on exit CX:AX has new 32 bit clock value
     push dx
     push ax
     xor  ax,ax
     int  1AH            ;BIOS Call
     pop  ax
     add  ax,dx
     adc  cx,0
     pop  dx
     ret
get_time_plus_ax    endp

;************  ########  ************
test_current_time   proc near
;on entry CX:AX has time value
 ; to be subtracted from the current time
;on exit if carry set then current time
 ; is less than CX:AX time
     push dx
     push cx
     push ax
     xor  ax,ax
     int  1AH            ;BIOS Call
     cmp  dx,18
     jb   test_current_time_2
test_current_time_1:
     pop  ax
     sub  dx,ax
     pop  dx
     sbb  cx,dx
     mov  cx,dx
     pop  dx
     ret
test_current_time_2:
     or   cx,cx
     jnz  test_current_time_1
     pop  ax      ;this is fix code for midnight factor
     pop  dx
     pop  dx
     clc          ;clear carry condition
     ret
test_current_time   endp
;*****************************************
     end

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s