home *** CD-ROM | disk | FTP | other *** search
- COMMENT ~
- SOUND.ASM -- Sound Generation Routines
-
- From `BLUEBOOK of ASSEMBLY ROUTINES for the IBM PC & XT'
- by Christopher L. Morgan
- Copyright (C) 1984 by The Waite Group, Inc.
-
- SOUND.ASM contains a collection of assembly language routines for producing
- sound in MS/PCDOS 8088 assembly language, using MASM. These routines are
- FAR PROCEDURES.
-
- Contents:
- ---------
- DELAY -- Delay for a specified time interval
- FREQ -- Convert from frequency to period
- GLISSNDO -- Make a glissando (sliding tone)
- LINSCALE -- Provide linear scaling
- PITCH -- Convert from pitch number
- PLAY -- Play music from a table
- TONE -- Make a tone
- TONE_INIT -- Initialize speaker timer
- TONE_OFF -- Turn off tone
- TONE_ON -- Turn on tone
- TONE_SET -- Set the tone on the speaker
-
- >>>>> See SOUND.DOC for complete descriptions of these routines <<<<<
-
- _____________________________ SOUND ROUTINES_________________________________
- It is best to include this data in the source code calling these routines,
- and then commenting out this next section. ~
- DATAS SEGMENT PUBLIC
- NOTES DW 4186 ;C
- DW 4435 ;C#/D-
- DW 4699 ;D
- DW 4978 ;D#/E-
- DW 5274 ;E
- DW 5588 ;F
- DW 5920 ;F#/G-
- DW 6272 ;G
- DW 6645 ;G#/A-
- DW 7040 ;A
- DW 7459 ;A#/B-
- DW 7902 ;B
- WHOLE DW 0
- F_START DW 0
- F_END DW 0
- DATAS ENDS
- ;------------------------------------------------------------------------------
- CODES SEGMENT
- PUBLIC DELAY,FREQ,GLISSANDO,LINSCALE,PITCH,PLAY
- PUBLIC TONE,TONE_INIT,TONE_OFF,TONE_ON,TONE_SET
- ASSUME CS:CODES,DS:DATAS
- ;------------------------------------------------------------------------------
- ;Routine to set tone
- ;
- TONE_INIT PROC FAR
- PUSH AX ;Save register
- ;
- ;Define control bit field parameters for the timer chip
- SC = 2 ;Use counter 2
- RL = 3 ;Mode load period 1 byte/time
- MODE = 3 ;Square wave generator
- BCD = 0 ;Not BCD, use binary values
- ;
- ;Form control word
- CNWORD = SC * 40H + RL * 10H + MODE * 2 + BCD
- ;
- ;Send control word to 8253 timer chip
- MOV AL,CNWORD ;Select the above control word
- OUT 43H,AL ;Send it to the control port
- POP AX ;Restore register
- RET
- TONE_INIT ENDP
- ;------------------------------------------------------------------------------
- ;Routine to select tone
- ;
- TONE_SET PROC FAR
- PUSH AX ;Save register
- ;
- ;Load the time period into the timer
- MOV AL,CL ;Lower byte
- OUT 42H,AL ;Out to timer
- MOV AL,CH ;Upper byte
- OUT 42H,AL ;Out to timer
- POP AX ;Restore register
- RET
- TONE_SET ENDP
- ;------------------------------------------------------------------------------
- ;Routine to turn on tone
- ;
- TONE_ON PROC FAR
- PUSH AX ;Save register
- ;
- ;Turn speaker and timer on
- IN AL,61H ;Get contents of system port B
- OR AL,3 ;Turn speaker and timer on
- OUT 61H,AL ;Send out new values to port B
- POP AX ;Restore register
- RET
- TONE_ON ENDP
- ;------------------------------------------------------------------------------
- ;Routine to turn Tone off
- ;
- TONE_OFF PROC FAR
- PUSH AX ;Save register
- ;
- ;Turn off timer 2 and speaker
- IN AL,61H ;Get port B again
- AND AL,11111100B ;Turn off timer & speaker
- OUT 61H,AL ;Now do it
- POP AX ;Restore register
- RET
- TONE_OFF ENDP
- ;------------------------------------------------------------------------------
- ;Routine to delay a specified number of milliseconds
- ;
- DELAY PROC FAR
- PUSH CX ;Save register
- DELAY1:
- PUSH CX ;Save counter
- MOV CX,260 ;Timing constant
- DELAY2:
- LOOP DELAY2 ;Small loop
- POP CX ;Restore counter
- LOOP DELAY1 ;Loop to count milliseconds
- POP CX ;Restore register
- RET
- DELAY ENDP
- ;------------------------------------------------------------------------------
- ;Routine to convert from frequency to period
- ;
- FREQ PROC FAR
- PUSH DX ;Save registers
- PUSH AX
- MOV DX,12H ;Upper part of numerator
- MOV AX,34DEH ;Lower part of numerator
- DIV CX ;Divide by frequency
- MOV CX,AX ;The quotient is the output
- POP AX ;Restore registers
- POP DX
- RET
- FREQ ENDP
- ;------------------------------------------------------------------------------
- ;Routine to make a tone
- ;
- TONE PROC FAR
- PUSH DX ;Save registers
- PUSH CX
- PUSH AX
- ;
- ;Compute the frequency and set up the tone
- CALL FREQ ;Convert the frequency
- CALL TONE_SET ;Set up the tone
- ;
- ;Turn on the tone
- CALL TONE_ON ;Turn it on
- ;
- ;Wait for proper delay
- MOV CX,DX ;Get delay length
- CALL DELAY
- ;
- ;Turn off the tone
- CALL TONE_OFF ;Turn it off
- POP AX ;Restore registers
- POP CX
- POP DX
- RET
- TONE ENDP
- ;------------------------------------------------------------------------------
- ;Routine to scale linearly
- ;
- LINSCALE PROC FAR
- PUSH DX ;Save registers
- PUSH AX
- ;
- ;Compute width
- MOV AX,F_END ;Get F_END
- SUB AX,F_START ;Subtract F_START
- ;
- ;Multiply width by input parameter
- MUL CX ;Multiply
- MOV CX,DX ;Move top part of quotient
- ; ; into CX
- ;Add lower limit
- ADD CX,F_START ;Add F_START
- POP AX ;Restore registers
- POP DX
- RET
- LINSCALE ENDP
- ;------------------------------------------------------------------------------
- ;Routine to determine pitch
- ;
- PITCH PROC FAR
- PUSH CX ;Save registers
- PUSH BX
- PUSH AX
- MOV AH,0 ;Extend pitch no. to 16 bits
- MOV CL,12 ;Divisor of 12
- DIV CL ;Divide
- MOV DL,AL ;Quotient determines the octave
- MOV AL,AH ;Remainder is the pitch within
- CBW ; 16-bit needed for look up
- SAL AX,1 ; 2 bytes/item
- MOV BX,AX ; into BX
- MOV CX,NOTES[BX] ;Look it up
- CALL FREQ ;Convert the frequency
- XCHG CX,DX ;Octave in CL, period in DX
- NEG CL ;8 - octave = shift count
- ADD CL,8
- SAL DX,CL
- POP AX ;Restore registers
- POP BX
- POP CX
- RET
- PITCH ENDP
- ;------------------------------------------------------------------------------
- ;Routine to make glissando
- ;
- GLISSANDO PROC FAR
- PUSH SI ;Save registers
- PUSH DX
- PUSH CX
- PUSH BX
- PUSH AX
- MOV F_START,BX ;FROM limit of frequencies
- MOV F_END,CX ; TO limit of frequencies
- CALL TONE_ON ;Turn on tone
- ;
- ;Set up the loop parameters
- MOV SI,1 ;Increment for loop
- CMP BX,CX ;Up or down?
- JLE GLISS1 ;Skip if up
- NEG SI ;Decrement freq in the loop
- GLISS1:
- MOV CX,BX ;Get the frequency
- CALL FREQ ;Convert to clock cycles
- CALL TONE_SET ;Set the tone
- MOV CX,DX ;Delay parameter > slows slide
- GLISS2:
- LOOP GLISS2
- CMP BX,F_END ;Check if done
- JE GLISS3 ;If so, go
- ADD BX,SI ;Else update the frequency
- JMP GLISS1
- ;
- ;Turn off the tone
- GLISS3:
- CALL TONE_OFF ;Turn it off
- POP AX ;Restore registers
- POP BX
- POP CX
- POP DX
- POP SI
- RET
- GLISSANDO ENDP
- ;------------------------------------------------------------------------------
- ;Routine to play music
- ;
- PLAY PROC FAR
- PUSH DS ;Save registers
- PUSH SI
- PUSH DX
- PUSH CX
- PUSH BX
- PUSH AX
- ;
- ;Command pointer is in SI
- MOV WHOLE,2000 ;Whole note = 2000 milliseconds
- CLD ;Forward direction
- ;
- ;Main loop starts here
- CHEK_END: ;Get command code and go
- ; through the cases
- LODSB ;Get the byte
- ;
- ;End command
- CMP AL,'X' ;Is it End command?
- JNE CHEK_TEMPO
- JMP PLAY_XIT
- ;
- ;Tempo command
- CHEK_TEMPO:
- CMP AL,'T' ;Is it Tempo command?
- JNE CHEK_NOTE
- LODSB ;Get the tempo
- MOV CL,AL ;Set in CX
- MOV CH,0
- MOV AX,60000 ;No. of milliseconds/minute
- MOV DX,0 ;Clear upper part
- DIV CX ;Divide into time
- MOV WHOLE,AX ;No. of milliseconds/whole note
- JMP CHEK_END ;Back for more
- ;
- ;Note command
- CHEK_NOTE:
- CMP AL,'N' ;Is it Note command?
- JNE CHEK_REST
- LODSB ;Get the pitch
- CALL PITCH ;Convert
- MOV CX,DX ; and move result into CX
- CALL TONE_SET ;Set the frequency
- CALL TONE_ON ;Turn on the tone
- MOV CX,WHOLE ;No. of milliseconds/whole note
- LODSB ;Get the duration
- MOV AH,AL ;Set up duration as multiplier
- MOV AL,0
- SAL CX,1 ;Scale factor 1
- MUL CX ;Multiply
- MOV CX,DX ;Total count for the note
- LODSB ;Get style
- MOV AH,AL ;Set up style as multiplier
- MOV AL,0
- MUL CX ;Multiply by style
- MOV F_START,DX ;Store count for note
- SUB CX,DX ;Count for rest
- MOV F_END,CX ;Store count for rest
- MOV CX,F_START ;Audible part of note
- CALL DELAY ;Delay
- CALL TONE_OFF ;Turn off the tone
- MOV CX,F_END ;Inaudible part of tone
- CALL DELAY ;Delay
- JMP CHEK_END ;Back for more
- ;
- ;Rest command
- CHEK_REST:
- CMP AL,'R' ;Is it Rest command?
- JNE PLAY_XIT
- MOV CX,WHOLE ;No. of milliseconds/whole note
- LODSB ;Get the duration
- MOV AH,AL ;Set up duration as multiplier
- MOV AL,0
- SAL CX,1 ;Scale factor of 1
- MUL CX ;Multiply
- MOV CX,DX ;Total count
- CALL DELAY ;Delay
- JMP CHEK_END ;Back for more
- ;
- ;Anything else end it
- PLAY_XIT:
- POP AX ;Restore registers
- POP BX
- POP CX
- POP DX
- POP SI
- POP DS
- RET
- PLAY ENDP
- ;-----------------------------------------------------------------------------
- CODES ENDS
- ;
- END
- ;_____________________________________________________________________________
- ;>>>>>Physical EOF SOUND.ASM<<<<<