home *** CD-ROM | disk | FTP | other *** search
/ ticalc.org / ticalc_org_rev_b.iso / archives / 92 / asm / source / fargo / play.asm < prev    next >
Encoding:
Assembly Source File  |  2001-07-01  |  9.8 KB  |  308 lines

  1. ; Fargo IDE header
  2. ;=============================================================================
  3. ; Last save: Sun Jan 24 20:36:55  1999
  4. ; 45.8 233.32 292.0 292.0 292.0 292.0
  5. ;=============================================================================
  6. ;----------------------------------------------------------------------------------------------
  7. ; This is the source of a Fargo program that is intended to be executed from the TIOS
  8. ; command line. It plays a tune, that is specified in a QBasic-like way, through the 
  9. ; serial port.
  10. ;
  11. ; Author: David Kⁿhling
  12. ; Last Modification: Jan 22 1999
  13. ;
  14. ; Thanks to:
  15. ;    Gareth James for files.txt 
  16. ;    David Ellsworth for Fargo and the testfunc.asm example program
  17. ;----------------------------------------------------------------------------------------------
  18.  
  19.  
  20. ;----------------------------------------------------------------------------------------------
  21.         INCLUDE    "tios.h"
  22.         INCLUDE "soundlib.h"
  23. ;----------------------------------------------------------------------------------------------
  24.  
  25. ;----------------------------------------------------------------------------------------------
  26.         XDEF    _main
  27.         XDEF    _tibasic
  28. ;----------------------------------------------------------------------------------------------
  29.  
  30. M_LEGATO    EQU    128
  31. M_NORMAL    EQU    110
  32. M_STACCATO    EQU    80
  33.  
  34. ;----------------------------------------------------------------------------------------------
  35. ; Implementation of switch.
  36. ; Input:  a1.l = pointer to switch data: Value,Label,Value,Label... where Label is relative
  37. ;                the Value zero ends the block, and the following Label is the Label of the
  38. ;                "default" - block
  39. ;         d0.w = Value
  40. ; Output: jump to the corresponding Label
  41. ;         a2/a3 is destroyed
  42. ;----------------------------------------------------------------------------------------------
  43. Switch:        movea.l    a1,a2
  44. \Loop        tst.w    (a2)
  45.         beq    \Default
  46.         cmp.w    (a2)+,d0
  47.         movea.w    (a2)+,a3
  48.         bne    \Loop
  49. \DoJmp:        jmp    0(a1,a3.w)
  50. \Default:    movea.w    2(a2),a3
  51.         bra    \DoJmp
  52.  
  53. ;----------------------------------------------------------------------------------------------
  54. ; Read a decimal number out of the string, pointed by a0. As result d0.w is the number and
  55. ; a0 points to the number's end. In case of an error d0 is set to -1.
  56. ; Input:  a0.l = pointer to string
  57. ; Output: d0.w = number or -1 on error
  58. ;       a0.l = pointer to first character behind number
  59. ;         d1 is destroyed
  60. ;----------------------------------------------------------------------------------------------
  61. ReadNumber:    moveq    #-1,d0            ; initialize return number to error code
  62.         clr.w    d1            ; d1.w := current character
  63.  
  64. \Loop        move.b    (a0),d1            
  65.         cmpi.w    #'0',d1            ; check, whether the character is a number
  66.         blt    \End            ; if it isn't: end the conversion
  67.         cmpi.w    #'9',d1
  68.         bgt    \End
  69.         tst.w    d0            ; character is a number -> clear error code in d0
  70.         bpl    \NoError
  71.         clr.w    d0
  72. \NoError:    sub.w    #'0',d1            ; convert character in d1 to number 0...9
  73.         mulu    #10,d0            ; make space for a new digit
  74.         add.w    d1,d0            ; add the digit
  75.         addq.l    #1,a0            ; goto next character
  76.         bra    \Loop
  77.         
  78. \End:        rts
  79.  
  80. ;----------------------------------------------------------------------------------------------
  81. ; Play a tune from a QBasic like string
  82. ; Input:  a0.l = pointer to string
  83. ; Output: d1.w = zero (ok) or nonzero (error)
  84. ;      all other registers are destroyed!
  85. ;----------------------------------------------------------------------------------------------
  86. PlayStrTune:    moveq    #3,d2            ; d2 := Octave
  87.         moveq    #120,d3            ; d3 := Tempo (beats per minute)
  88.         moveq    #M_NORMAL,d4        ; d4 := Note fill duration (legato-staccato)
  89.         clr.w    d5            ; d5 := current character
  90.         moveq    #4,d6            ; d6 := length (1 = full note, 4 = quater note...)
  91.         
  92.         jsr    soundlib::Init
  93.  
  94. \Loop:        clr.w    d0
  95.         move.b    (a0)+,d0        ; d0.w := current character
  96.         beq    \End
  97.  
  98.         btst.b    #1,$60001A        ; check ON key
  99.         beq    \End            ; and exit if it is pressed
  100.  
  101.         ; jump to the label that corresponds to the character's command
  102.         lea    \SwitchChar(PC),a1
  103.         bra    Switch                ; switch(d0) {
  104. \SwitchChar:    dc.w    ' ',\Loop-\SwitchChar        ;    case ' ': continue;
  105.         dc.w    13,\Loop-\SwitchChar        ;    case '\n': continue;
  106.         dc.w    'A',\Tone_A-\SwitchChar        ;    case 'A': goto Tone_A;
  107.         dc.w    'B',\Tone_B-\SwitchChar        ;    case 'B': goto Tone_B;
  108.         dc.w    'C',\Tone_C-\SwitchChar        ;    case 'C': goto Tone_C;
  109.         dc.w    'D',\Tone_D-\SwitchChar        ;    ...
  110.         dc.w    'E',\Tone_E-\SwitchChar
  111.         dc.w    'F',\Tone_F-\SwitchChar
  112.         dc.w    'G',\Tone_G-\SwitchChar
  113.         dc.w    'L',\ToneLength-\SwitchChar
  114.         dc.w    'M',\FillDuration-\SwitchChar
  115.         dc.w    'O',\SetOctave-\SwitchChar
  116.         dc.w    '>',\IncrOctave-\SwitchChar
  117.         dc.w    '<',\DecrOctave-\SwitchChar
  118.         dc.w    'P',\Pause-\SwitchChar
  119.         dc.w    'T',\Tempo-\SwitchChar
  120.         dc.w    0,\Error-\SwitchChar        ;    default: goto Error;
  121.                             ; }
  122.  
  123.     ; *** Play Tones -- d0 is set to the number of the half-tone within the scale ***
  124. \Tone_C:    moveq    #0,d0
  125.         bra    \PlayTone
  126. \Tone_D:    moveq    #2,d0
  127.         bra    \PlayTone
  128. \Tone_E:    moveq    #4,d0
  129.         bra    \PlayTone
  130. \Tone_F:    moveq    #5,d0
  131.         bra    \PlayTone
  132. \Tone_G:    moveq    #7,d0
  133.         bra    \PlayTone
  134. \Tone_A:    moveq    #9,d0
  135.         bra    \PlayTone
  136. \Tone_B:    moveq    #11,d0
  137.  
  138.         ; check, whether there is a flat or b
  139. \PlayTone:    cmpi.b    #'#',(a0)
  140.         bne    \NoFlat
  141.         addq.w    #1,d0
  142.         addq.l    #1,a0
  143. \NoFlat:    cmpi.b    #'b',(a0)
  144.         bne    \NoB
  145.         subq.w    #1,d0
  146.         addq.l    #1,a0
  147. \NoB:        
  148.         ; get tone's frequency and store it in d0
  149.         move.w    d2,d7            ; d7 = octave*12
  150.         mulu    #12,d7
  151.         add.w    d7,d0            ; d0 := number of tone within 7 octave range
  152.         bmi    \Error            ; tone has to be in range 0...12*7-1
  153.         cmpi.w    #12*7-1,d0
  154.         bgt    \Error
  155.         lea    soundlib::FrqTable,a1    ; a1 := pointer to frequency table
  156.         lsl.w    #1,d0
  157.         move.w    0(a1,d0.w),d0        ; d0 := frequency
  158.  
  159.         ; calculate total tone duration and store it in d7
  160. \FromPause:    move.l    #60*1024*4,d7
  161.         divu    d3,d7            ; d7 := duration of one full note
  162.         ext.l    d7
  163.         divu    d6,d7            ; d7 := duration of current note type
  164.  
  165.         ; check, whether there are on or more dots behind the note
  166. \CheckDot:    cmpi.b    #'.',(a0)
  167.         bne    \NoDot            ; if there is a dot:
  168.         mulu    #3,d7            ; increase note length by factor 1.5 (3/2)
  169.         lsr.w    #1,d7
  170.         addq.l    #1,a0
  171.         bra    \CheckDot
  172. \NoDot:    
  173.         ; calculate play-duration and play the tone
  174.         move.w    d7,d1            ; d1 := absolute note fill duration
  175.         tst.w    d0
  176.         bmi    \DoPause
  177.         mulu    d4,d1
  178.         lsr.l    #7,d1
  179.         jsr    soundlib::Sound
  180.  
  181.         ; calculate pause-duration and pause
  182.         sub.w    d1,d7            ; d1 = pause duration
  183.         move.w    d7,d1
  184. \DoPause:    jsr    soundlib::Pause
  185.  
  186.         bra    \Loop    
  187.  
  188.     ; *** process L<length> ***
  189. \ToneLength:    bsr    ReadNumber        ; read the number that comes after 'L' 1...64
  190.         tst.w    d0            ; same as cmpi.w #0,d0
  191.         ble    \Error
  192.         cmpi.w    #64,d0
  193.         bgt    \Error
  194.         move.w    d0,d6            ; set the length
  195.         bra    \Loop    
  196.  
  197.     ; *** Process ML MN or MS ***
  198. \FillDuration:    move.b    (a0)+,d0        ; d0.w = character behind 'M', may be L,N or S
  199.         lea    \SwitchMChar(PC),a1    ; process that character
  200.         bra    Switch                ; switch(d0) {
  201. \SwitchMChar:    dc.w    'L',\M_Legato-\SwitchMChar    ;   case 'L': goto M_Legato;
  202.         dc.w    'N',\M_Normal-\SwitchMChar    ;   ...
  203.         dc.w    'S',\M_Staccato-\SwitchMChar
  204.         dc.w    0,\Error-\SwitchMChar
  205. \M_Legato:    move.w    #M_LEGATO,d4
  206.         bra    \Loop
  207. \M_Normal:    moveq    #M_NORMAL,d4
  208.         bra    \Loop
  209. \M_Staccato:    moveq    #M_STACCATO,d4
  210.         bra    \Loop
  211.  
  212.     ; *** process O<octave> ***
  213. \SetOctave:    bsr    ReadNumber        ; read the number that comes after 'O' 0...6
  214.         move.w    d0,d2            ; set the octave number
  215. \CheckOctave:    bmi    \Error
  216.         cmpi.w    #6,d2            ; if number > 6: error
  217.         bgt    \Error
  218.         bra    \Loop
  219.  
  220.     ; *** process > ***
  221. \IncrOctave:    addq.w    #1,d2            ; increase octave number
  222.         bra    \CheckOctave        ; and check whether it is in range 0...6
  223.  
  224.     ; *** process < ***
  225. \DecrOctave:    subq.w    #1,d2            ; decrease octave number
  226.         bra    \CheckOctave        ; and check whether it is in range 0...6
  227.  
  228.     ; *** process P ***
  229. \Pause:        moveq    #-1,d0            ; frequency -1 means: pause
  230.         bra    \FromPause
  231.  
  232.     ; *** process T<tempo> ***
  233. \Tempo:        bsr    ReadNumber        ; read the number that comes after 'T' 32...240
  234.         cmpi.w    #32,d0
  235.         bmi    \Error
  236.         cmpi.w    #240,d0
  237.         bgt    \Error
  238.         move.w    d0,d3            ; set the tempo
  239.         bra    \Loop    
  240.  
  241. \Error:        moveq    #1,d1
  242.         rts
  243. \End:        moveq    #0,d1
  244.         rts
  245.  
  246. ;----------------------------------------------------------------------------------------------
  247. ; MAIN
  248. ;----------------------------------------------------------------------------------------------
  249. _main:        ; get the address of the argument-string ("s")
  250.         pea    ArgName(PC)        ; get address of argument's entry in temp folder
  251.         move.w    tios::DefTempHandle,-(a7)        
  252.         jsr    tios::FindSymEntry    ; a0.l := pointer to symbol entry of argument
  253.         addq.l    #6,a7
  254.         move.w    tios::SYM_ENTRY.hVal(a0),d0    ; d0 := handle of argument
  255.         tios::DEREF    d0,a0            ; a0 := pointer to argument
  256.  
  257.         ; check, whether argument is a string
  258.         move.w    (a0),d1            ; d1 = length of variable
  259.         move.w    #130,d0            ; d0 = error number ("argument must be a string")
  260.         cmpi.b    #$2D,1(a0,d1)        ; verify STR tag (at end of variable)
  261.         bne    \Error
  262.  
  263.         addq.l    #3,a0            ; a0 := pointer to string begin
  264.         bsr    PlayStrTune        ; play the tune
  265.  
  266.         move.w    #910,d0            ; if d1 != 0: display "Syntax" - error
  267.         tst.w    d1
  268.         bne    \Error
  269.  
  270.         rts
  271.  
  272.  
  273.         ; Display the error message that correspond to the errno in d0 and exit
  274. \Error:        move.w    d0,-(a7)
  275.         jsr    tios::ERD_dialog
  276.         addq.l    #2,a7
  277.         rts
  278.         
  279.  
  280. ;==============================================================================================
  281. ; Data
  282. ;==============================================================================================
  283. ArgName:    dc.b     "s",0            ; the name of the argument (the folder name)
  284.  
  285. ;==============================================================================================
  286. ; Function Definition
  287. ;==============================================================================================
  288.         SECTION _tibasic
  289.         dc.b    $E9        
  290.         dc.b    $12,$E4            ; EndPrgm
  291.         dc.b    $00,$E8            ; :
  292.         dc.b    $19,$E4            ; Prgm
  293.         dc.b    $E5,$03            ; (s)
  294.         dc.b    $00,$00,$40,$DC 
  295. _tibasic:
  296.         END
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308.