home *** CD-ROM | disk | FTP | other *** search
- ; Fargo IDE header
- ;=============================================================================
- ; Last save: Sun Jan 24 20:36:55 1999
- ; 45.8 233.32 292.0 292.0 292.0 292.0
- ;=============================================================================
- ;----------------------------------------------------------------------------------------------
- ; This is the source of a Fargo program that is intended to be executed from the TIOS
- ; command line. It plays a tune, that is specified in a QBasic-like way, through the
- ; serial port.
- ;
- ; Author: David Kⁿhling
- ; Last Modification: Jan 22 1999
- ;
- ; Thanks to:
- ; Gareth James for files.txt
- ; David Ellsworth for Fargo and the testfunc.asm example program
- ;----------------------------------------------------------------------------------------------
-
-
- ;----------------------------------------------------------------------------------------------
- INCLUDE "tios.h"
- INCLUDE "soundlib.h"
- ;----------------------------------------------------------------------------------------------
-
- ;----------------------------------------------------------------------------------------------
- XDEF _main
- XDEF _tibasic
- ;----------------------------------------------------------------------------------------------
-
- M_LEGATO EQU 128
- M_NORMAL EQU 110
- M_STACCATO EQU 80
-
- ;----------------------------------------------------------------------------------------------
- ; Implementation of switch.
- ; Input: a1.l = pointer to switch data: Value,Label,Value,Label... where Label is relative
- ; the Value zero ends the block, and the following Label is the Label of the
- ; "default" - block
- ; d0.w = Value
- ; Output: jump to the corresponding Label
- ; a2/a3 is destroyed
- ;----------------------------------------------------------------------------------------------
- Switch: movea.l a1,a2
- \Loop tst.w (a2)
- beq \Default
- cmp.w (a2)+,d0
- movea.w (a2)+,a3
- bne \Loop
- \DoJmp: jmp 0(a1,a3.w)
- \Default: movea.w 2(a2),a3
- bra \DoJmp
-
- ;----------------------------------------------------------------------------------------------
- ; Read a decimal number out of the string, pointed by a0. As result d0.w is the number and
- ; a0 points to the number's end. In case of an error d0 is set to -1.
- ; Input: a0.l = pointer to string
- ; Output: d0.w = number or -1 on error
- ; a0.l = pointer to first character behind number
- ; d1 is destroyed
- ;----------------------------------------------------------------------------------------------
- ReadNumber: moveq #-1,d0 ; initialize return number to error code
- clr.w d1 ; d1.w := current character
-
- \Loop move.b (a0),d1
- cmpi.w #'0',d1 ; check, whether the character is a number
- blt \End ; if it isn't: end the conversion
- cmpi.w #'9',d1
- bgt \End
- tst.w d0 ; character is a number -> clear error code in d0
- bpl \NoError
- clr.w d0
- \NoError: sub.w #'0',d1 ; convert character in d1 to number 0...9
- mulu #10,d0 ; make space for a new digit
- add.w d1,d0 ; add the digit
- addq.l #1,a0 ; goto next character
- bra \Loop
-
- \End: rts
-
- ;----------------------------------------------------------------------------------------------
- ; Play a tune from a QBasic like string
- ; Input: a0.l = pointer to string
- ; Output: d1.w = zero (ok) or nonzero (error)
- ; all other registers are destroyed!
- ;----------------------------------------------------------------------------------------------
- PlayStrTune: moveq #3,d2 ; d2 := Octave
- moveq #120,d3 ; d3 := Tempo (beats per minute)
- moveq #M_NORMAL,d4 ; d4 := Note fill duration (legato-staccato)
- clr.w d5 ; d5 := current character
- moveq #4,d6 ; d6 := length (1 = full note, 4 = quater note...)
-
- jsr soundlib::Init
-
- \Loop: clr.w d0
- move.b (a0)+,d0 ; d0.w := current character
- beq \End
-
- btst.b #1,$60001A ; check ON key
- beq \End ; and exit if it is pressed
-
- ; jump to the label that corresponds to the character's command
- lea \SwitchChar(PC),a1
- bra Switch ; switch(d0) {
- \SwitchChar: dc.w ' ',\Loop-\SwitchChar ; case ' ': continue;
- dc.w 13,\Loop-\SwitchChar ; case '\n': continue;
- dc.w 'A',\Tone_A-\SwitchChar ; case 'A': goto Tone_A;
- dc.w 'B',\Tone_B-\SwitchChar ; case 'B': goto Tone_B;
- dc.w 'C',\Tone_C-\SwitchChar ; case 'C': goto Tone_C;
- dc.w 'D',\Tone_D-\SwitchChar ; ...
- dc.w 'E',\Tone_E-\SwitchChar
- dc.w 'F',\Tone_F-\SwitchChar
- dc.w 'G',\Tone_G-\SwitchChar
- dc.w 'L',\ToneLength-\SwitchChar
- dc.w 'M',\FillDuration-\SwitchChar
- dc.w 'O',\SetOctave-\SwitchChar
- dc.w '>',\IncrOctave-\SwitchChar
- dc.w '<',\DecrOctave-\SwitchChar
- dc.w 'P',\Pause-\SwitchChar
- dc.w 'T',\Tempo-\SwitchChar
- dc.w 0,\Error-\SwitchChar ; default: goto Error;
- ; }
-
- ; *** Play Tones -- d0 is set to the number of the half-tone within the scale ***
- \Tone_C: moveq #0,d0
- bra \PlayTone
- \Tone_D: moveq #2,d0
- bra \PlayTone
- \Tone_E: moveq #4,d0
- bra \PlayTone
- \Tone_F: moveq #5,d0
- bra \PlayTone
- \Tone_G: moveq #7,d0
- bra \PlayTone
- \Tone_A: moveq #9,d0
- bra \PlayTone
- \Tone_B: moveq #11,d0
-
- ; check, whether there is a flat or b
- \PlayTone: cmpi.b #'#',(a0)
- bne \NoFlat
- addq.w #1,d0
- addq.l #1,a0
- \NoFlat: cmpi.b #'b',(a0)
- bne \NoB
- subq.w #1,d0
- addq.l #1,a0
- \NoB:
- ; get tone's frequency and store it in d0
- move.w d2,d7 ; d7 = octave*12
- mulu #12,d7
- add.w d7,d0 ; d0 := number of tone within 7 octave range
- bmi \Error ; tone has to be in range 0...12*7-1
- cmpi.w #12*7-1,d0
- bgt \Error
- lea soundlib::FrqTable,a1 ; a1 := pointer to frequency table
- lsl.w #1,d0
- move.w 0(a1,d0.w),d0 ; d0 := frequency
-
- ; calculate total tone duration and store it in d7
- \FromPause: move.l #60*1024*4,d7
- divu d3,d7 ; d7 := duration of one full note
- ext.l d7
- divu d6,d7 ; d7 := duration of current note type
-
- ; check, whether there are on or more dots behind the note
- \CheckDot: cmpi.b #'.',(a0)
- bne \NoDot ; if there is a dot:
- mulu #3,d7 ; increase note length by factor 1.5 (3/2)
- lsr.w #1,d7
- addq.l #1,a0
- bra \CheckDot
- \NoDot:
- ; calculate play-duration and play the tone
- move.w d7,d1 ; d1 := absolute note fill duration
- tst.w d0
- bmi \DoPause
- mulu d4,d1
- lsr.l #7,d1
- jsr soundlib::Sound
-
- ; calculate pause-duration and pause
- sub.w d1,d7 ; d1 = pause duration
- move.w d7,d1
- \DoPause: jsr soundlib::Pause
-
- bra \Loop
-
- ; *** process L<length> ***
- \ToneLength: bsr ReadNumber ; read the number that comes after 'L' 1...64
- tst.w d0 ; same as cmpi.w #0,d0
- ble \Error
- cmpi.w #64,d0
- bgt \Error
- move.w d0,d6 ; set the length
- bra \Loop
-
- ; *** Process ML MN or MS ***
- \FillDuration: move.b (a0)+,d0 ; d0.w = character behind 'M', may be L,N or S
- lea \SwitchMChar(PC),a1 ; process that character
- bra Switch ; switch(d0) {
- \SwitchMChar: dc.w 'L',\M_Legato-\SwitchMChar ; case 'L': goto M_Legato;
- dc.w 'N',\M_Normal-\SwitchMChar ; ...
- dc.w 'S',\M_Staccato-\SwitchMChar
- dc.w 0,\Error-\SwitchMChar
- \M_Legato: move.w #M_LEGATO,d4
- bra \Loop
- \M_Normal: moveq #M_NORMAL,d4
- bra \Loop
- \M_Staccato: moveq #M_STACCATO,d4
- bra \Loop
-
- ; *** process O<octave> ***
- \SetOctave: bsr ReadNumber ; read the number that comes after 'O' 0...6
- move.w d0,d2 ; set the octave number
- \CheckOctave: bmi \Error
- cmpi.w #6,d2 ; if number > 6: error
- bgt \Error
- bra \Loop
-
- ; *** process > ***
- \IncrOctave: addq.w #1,d2 ; increase octave number
- bra \CheckOctave ; and check whether it is in range 0...6
-
- ; *** process < ***
- \DecrOctave: subq.w #1,d2 ; decrease octave number
- bra \CheckOctave ; and check whether it is in range 0...6
-
- ; *** process P ***
- \Pause: moveq #-1,d0 ; frequency -1 means: pause
- bra \FromPause
-
- ; *** process T<tempo> ***
- \Tempo: bsr ReadNumber ; read the number that comes after 'T' 32...240
- cmpi.w #32,d0
- bmi \Error
- cmpi.w #240,d0
- bgt \Error
- move.w d0,d3 ; set the tempo
- bra \Loop
-
- \Error: moveq #1,d1
- rts
- \End: moveq #0,d1
- rts
-
- ;----------------------------------------------------------------------------------------------
- ; MAIN
- ;----------------------------------------------------------------------------------------------
- _main: ; get the address of the argument-string ("s")
- pea ArgName(PC) ; get address of argument's entry in temp folder
- move.w tios::DefTempHandle,-(a7)
- jsr tios::FindSymEntry ; a0.l := pointer to symbol entry of argument
- addq.l #6,a7
- move.w tios::SYM_ENTRY.hVal(a0),d0 ; d0 := handle of argument
- tios::DEREF d0,a0 ; a0 := pointer to argument
-
- ; check, whether argument is a string
- move.w (a0),d1 ; d1 = length of variable
- move.w #130,d0 ; d0 = error number ("argument must be a string")
- cmpi.b #$2D,1(a0,d1) ; verify STR tag (at end of variable)
- bne \Error
-
- addq.l #3,a0 ; a0 := pointer to string begin
- bsr PlayStrTune ; play the tune
-
- move.w #910,d0 ; if d1 != 0: display "Syntax" - error
- tst.w d1
- bne \Error
-
- rts
-
-
- ; Display the error message that correspond to the errno in d0 and exit
- \Error: move.w d0,-(a7)
- jsr tios::ERD_dialog
- addq.l #2,a7
- rts
-
-
- ;==============================================================================================
- ; Data
- ;==============================================================================================
- ArgName: dc.b "s",0 ; the name of the argument (the folder name)
-
- ;==============================================================================================
- ; Function Definition
- ;==============================================================================================
- SECTION _tibasic
- dc.b $E9
- dc.b $12,$E4 ; EndPrgm
- dc.b $00,$E8 ; :
- dc.b $19,$E4 ; Prgm
- dc.b $E5,$03 ; (s)
- dc.b $00,$00,$40,$DC
- _tibasic:
- END
-
-
-
-
-
-
-
-
-
-
-
-