home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / music / musgfa / musedt.lst < prev    next >
Encoding:
File List  |  1993-08-22  |  52.5 KB  |  2,046 lines

  1. ' musedt.gfa  6 June 1991: graphics envelope added 3 may 92
  2. ' music scoring software
  3. ' programmed by Seymour Shlien in GFA Basic 3.5 on my 1040STE
  4. ' 624 Courtenay Avenue / Ottawa, Ontario, Canada  K2A 3B5
  5. ' The program is public domain and not for commercial use.
  6. DIM note_yposition%(52) ! vertical of natural notes on staff
  7. DIM flat_yposition%(22),sharp_yposition%(22) ! vertical position of other notes
  8. DIM length_sprite%(12) !mapping of note time value with its sprite number
  9. DIM rest_sprite%(12) !mapping of rest time value with its sprite number
  10. DIM sharp_key_to_letter$(13) !mapping of pitch code (1 to 12) to letter code
  11. DIM flat_key_to_letter$(13) ! mapping of pitch code to letter code (c,d,e...g)
  12. DIM duration_to_text$(17) !duration code (0 to 12) to symbol (eg HN.)
  13. DIM keysig_to_text$(15) !key signature code (1 to 12) to text
  14. DIM assumed_accidental%(12) ! indicates whether note must be preceded by #,b
  15. DIM nat_keys%(15) !keys to be printed as natural as function of key signature
  16. DIM shrp_keys%(15) !keys assumed to be accidentals as function of keysig
  17. DIM sharp_sig_ypos%(7),flat_sig_ypos%(7)  ! treble and bass sharp sequence
  18. DIM notes_to_microbeats%(12) ! duration code (1 - 12) to microbeat value
  19. DIM elapsed_microbeats%(3) !number of microbeats for each voice (bar lines)
  20. DIM sprite$(30)
  21. DIM seq%(3) !note sequence number in each voice during play
  22. DIM micro_beat%(3) ! accumulated microbeats for voice (for play)
  23. DIM next_event%(3) ! time for next note to sound for voice (for play)
  24. DIM play_stop%(3) ! kounter for stop playing -used in cue
  25. DIM note_tick%(3) ! time a note was sounded. Used for envelope
  26. DIM tone_envel%(300) ! loudness envelope 1 to 100 for each voice
  27. DIM volum(3),decay(3)
  28. DIM voice_end_flag%(3) ! flag to signal end of voice
  29. DIM note%(3),duration%(3),draw_flag%(3) !last notes sounded
  30. DIM black_keys%(5) ! position of black keys on keyboard
  31. REM white key - black key to pitch code converter
  32. DIM white_keycod%(7),black_keycod%(7),white_key_decoder%(32),black_key_decoder%(21)
  33. DIM x1%(50),x2%(50),y1%(50),y2%(50) ! for mouse sensitive zones
  34. DIM kount%(2),vclen%(2),repeat_sign%(2),repeat_count%(2)
  35. REM memory for storing music
  36. DIM tnote&(2,1000),mubeat%(3)
  37. DIM last_note_duration%(3) !need it if we correct an error with right button
  38. REM if USESHARPS = 1 then sharps are used instead of flats
  39. usesharps%=0
  40. DEFMOUSE 0
  41. CLS
  42. rez%=XBIOS(4)
  43. IF rez%<>1
  44.   ALERT 3," Please switch to | medium resolution! ",1,"Oops",b%
  45.   STOP
  46. ENDIF
  47. CLS
  48. IF usesharps%<>1
  49.   usesharps%=1
  50. ELSE
  51.   usesharps%=0
  52. ENDIF
  53. key_sig%=8 ! key signature for c major (a minor)
  54. beats_per_bar%=4
  55. beat_size%=4
  56. bar_length%=beats_per_bar%*notes_to_microbeats%(beat_size%)
  57. next_bar_line%=bar_length%
  58. next_key_sig%=8
  59. tnt%=11 ! assume quarter note sprite
  60. staff_yshift%=-25 !vertical position to draw treble and bass staff
  61. voic%=1
  62. voic1%=voic%-1
  63. speed%=50
  64. @read_music_data
  65. @load_note_sprites
  66. @initialize_note_table
  67. volum(0)=11
  68. volum(1)=10
  69. volum(2)=10
  70. decay(0)=0.08
  71. decay(1)=0.09
  72. decay(2)=0.13
  73. FOR i%=0 TO 2
  74.   offset=volum(i%)
  75.   attenuation=decay(i%)
  76.   @make_tone_envelope(i%,offset,attenuation)
  77. NEXT i%
  78. @draw_musedt_screen
  79. @reset
  80. tlen%=4
  81. @switch_note_duration
  82. note_xcoor%=40
  83. ' run till infinity
  84. FOR i%=1 TO 500000
  85.   @decode_mouse_key
  86.   PAUSE 10
  87.   IF write%=1
  88.     IF klick%=1 !appending or overwriting next note
  89.       kount%(voic1%)=kount%(voic1%)+1
  90.       tnote&(voic1%,kount%(voic1%))=nte%+tlen%*256
  91.       last_note_duration%(voic1%)=tlen%
  92.       IF tlen%<13
  93.         elapsed_microbeats%(voic1%)=elapsed_microbeats%(voic1%)+notes_to_microbeats%(tlen%)
  94.       ENDIF
  95.       IF (elapsed_microbeats%(voic1%)>next_bar_line%)
  96.         @new_bar_line
  97.         note_xposition%=next_note_xposition%
  98.       ENDIF
  99.       IF next_note_xposition%>595 THEN
  100.         @show
  101.       ELSE
  102.         @draw_note_on_staff(next_note_xposition%,1)
  103.       ENDIF
  104.       @sound_note
  105.       @update_editor_windows
  106.       IF kount%(voic1%)>vclen%(voic1%)
  107.         vclen%(voic1%)=kount%(voic1%)
  108.         '  @show
  109.       ENDIF
  110.     ENDIF
  111.     IF klick%=2 !   right button for correcting the last note keyed in
  112.       tnote&(voic1%,kount%(voic1%))=nte%+tlen%*256
  113.       IF tlen%<>last_note_duration%(voic1%)
  114.         elapsed_microbeats%(voic1%)=elapsed_microbeats%(voic1%)-notes_to_microbeats%(last_note_duration%(voic1%))
  115.         elapsed_microbeats%(voic1%)=elapsed_microbeats%(voic1%)+notes_to_microbeats%(tlen%)
  116.         last_note_duration%(voic1%)=tlen%
  117.       ENDIF
  118.       @show
  119.       @sound_note
  120.       @update_editor_windows
  121.     ENDIF
  122.   ENDIF
  123.   IF klick%=0
  124.     @ascii_code_dispatcher
  125.   ENDIF
  126.   IF ky%=38
  127.     @execute_menu_command
  128.   ENDIF
  129.   IF ky%>33 AND ky%<37 !process repeat signs
  130.     draw_marker(ky%-32,next_note_xposition%)
  131.     INC kount%(voic1%)
  132.     IF kount%(voic1%)>vclen%(voic1%)
  133.       vclen%(voic1%)=kount%(voic1%)
  134.     ENDIF
  135.     tnote&(voic1%,kount%(voic1%))=256*(ky%-21)
  136.   ENDIF
  137. NEXT i%
  138. > PROCEDURE tnote_structure_doc
  139.   ' tnote array stores the pitch and duration value of every note
  140.   ' to be played for the three voices (tracks). The high byte contains
  141.   ' the duration code and other special codes. The low byte contains
  142.   ' the pitch code. The pitch code modulo 12 maps into the note letter
  143.   ' c,c#,d,d#,... b. If the pitch code is zero then a rest is assumed.
  144.   ' The duration code 0 to 12 map to note duration in the order that
  145.   ' the note duration sprites appear in the menu. Other codes 13 to 15
  146.   ' control repeats. Codes 16 and 17 are not fully implemented but allow
  147.   ' the inclusion of long rests in a particular voice. Other codes are
  148.   ' only used for the input /output files *.TUN for specifying key signature,
  149.   ' time signature, and tempo.
  150. RETURN
  151. > PROCEDURE note_sprites_doc
  152.   ' order of sprites in the sprite array is: 1 c-cleff, 2 bass-cleff
  153.   ' 3 flat symbol for tail up note, 4 flat symbol for tail down, 5,6 sharp
  154.   ' symbol (tail up and down), 7,8 whole note symbol, 9,10 half note symbol
  155.   ' 11,12 quarter note symbol, 13,14 eighth note symbol, 15,16 sixteenth note
  156.   ' 17,18 32nd node, 19-25 rest symbols, 26,27 natural symbol.
  157. RETURN
  158. > PROCEDURE load_note_sprites
  159.   LOCAL loop%
  160.   OPEN "i",#1,"notes2.put"
  161.   FOR loop%=1 TO 29
  162.     sprite$(loop%)=INPUT$(CVI(INPUT$(2,#1)),#1)
  163.   NEXT loop%
  164.   CLOSE #1
  165. RETURN
  166. > PROCEDURE read_music_data
  167.   @read_note_positions
  168.   @read_note_duration_sprite_numbers
  169.   @read_rest_duration_sprite_numbers
  170.   @read_key_to_letter_converter
  171.   @read_note_duration_code
  172.   @read_key_signature_representation
  173.   @read_order_of_flats_and_sharps
  174.   @read_signature_sharp_sequence
  175.   @read_timconv_array
  176.   @read_key_decoders
  177. RETURN
  178. > PROCEDURE read_note_positions
  179.   LOCAL i%
  180.   REM read the vertical position to display the note sprites on
  181.   REM the treble or bass staff.
  182.   REM negative numbers are pointers to sharp or flat notes.
  183.   FOR i%=1 TO 49
  184.     READ note_yposition%(i%)
  185.   NEXT i%
  186.   FOR i%=1 TO 21
  187.     READ flat_yposition%(i%)
  188.   NEXT i%
  189.   FOR i%=1 TO 20
  190.     READ sharp_yposition%(i%)
  191.   NEXT i%
  192.   DATA 67,-1,65,-2,62,-3,60,58,-4,55
  193.   DATA -5,63,61,-6,59,-7,56,-8,54,52
  194.   DATA -9,32,-10,30,28,-11,25,-12,23,-13
  195.   DATA 20,28,-14,26,-15,23,21,-16,19,-17
  196.   DATA 17,-18,15,13,-19,11,-20,9,-21
  197.   REM
  198.   DATA 65,62,60,55,63,59,57,54,32,30
  199.   DATA 25,23,20,26,23,19,17,15,11,9
  200.   DATA 7
  201.   REM
  202.   DATA 67,65,62,58,55,61,59,56,52,32
  203.   DATA 28,25,23,28,26,21,19,17,13,11
  204. RETURN
  205. > PROCEDURE read_note_duration_sprite_numbers
  206.   LOCAL i%
  207.   FOR i%=0 TO 12
  208.     READ length_sprite%(i%)
  209.   NEXT i%
  210.   DATA 17,15,13,13,11,11,9,9,7,7,17,15,13
  211.   ltlen%=4
  212. RETURN
  213. > PROCEDURE read_rest_duration_sprite_numbers
  214.   LOCAL i%
  215.   FOR i%=0 TO 12
  216.     READ rest_sprite%(i%)
  217.   NEXT i%
  218.   DATA 24,23,22,22,21,21,20,20,19,19,24,23,22
  219. RETURN
  220. > PROCEDURE read_key_to_letter_converter
  221.   LOCAL i%
  222.   FOR i%=1 TO 12
  223.     READ sharp_key_to_letter$(i%)
  224.   NEXT i%
  225.   FOR i%=1 TO 12
  226.     READ flat_key_to_letter$(i%)
  227.   NEXT i%
  228.   DATA "C","C#","D","D#","E","F","F#","G","G#","A","A#","B"
  229.   DATA "C","Db","D","Eb","E","F","Gb","G","Ab","A","Bb","B"
  230. RETURN
  231. > PROCEDURE read_note_duration_code
  232.   LOCAL i%
  233.   FOR i%=0 TO 17
  234.     READ duration_to_text$(i%)
  235.   NEXT i%
  236.   DATA "TN","SN","EN","EN.","QN","QN.","HN","HN.","WN","WN.","TN3","SN3","EN3"
  237.   DATA "SGN","REP","HID","RST1","RST2"
  238. RETURN
  239. > PROCEDURE read_key_signature_representation
  240.   LOCAL i%
  241.   FOR i%=1 TO 15
  242.     READ keysig_to_text$(i%)
  243.   NEXT i%
  244.   DATA "Cb+ Ab-","Gb+ Eb-","Db+ Bb-","Ab+ F-","Eb+ C-"
  245.   DATA "Bb+ G-","F+ D-","C+ A-","G+ E-","D+ B-"
  246.   DATA "A+ F#-","E+ C#-","B+ Cb-","F#+ Gb-","C#+ Db-"
  247. RETURN
  248. > PROCEDURE read_order_of_flats_and_sharps
  249.   ' order of flats and sharps when changing key signature.
  250.   ' order is given in pitch codes
  251.   LOCAL i%
  252.   FOR i%=2 TO 15
  253.     READ nat_keys%(i%)
  254.   NEXT i%
  255.   FOR i%=2 TO 15
  256.     READ shrp_keys%(i%)
  257.   NEXT i%
  258.   DATA 6,1,8,3,10,5,12,6,1,8,3,10,5,12
  259.   DATA 5,12,7,2,9,4,11,7,2,9,4,11,6,1
  260.   FOR i%=1 TO 12
  261.     assumed_accidental%(i%)=0
  262.   NEXT i%
  263. RETURN
  264. > PROCEDURE read_signature_sharp_sequence
  265.   LOCAL i%
  266.   FOR i%=1 TO 7
  267.     READ sharp_sig_ypos%(i%)
  268.   NEXT i%
  269.   FOR i%=1 TO 7
  270.     READ flat_sig_ypos%(i%)
  271.   NEXT i%
  272.   DATA 21,28,19,26,32,24,30
  273.   DATA 61,68,59,66,72,64,70
  274. RETURN
  275. > PROCEDURE read_timconv_array
  276.   LOCAL i%
  277.   REM for converting notes to microbeats
  278.   FOR i%=0 TO 12
  279.     READ notes_to_microbeats%(i%)
  280.   NEXT i%
  281.   DATA 3,6,12,18,24,36,48,72,96,144,2,4,8
  282.   ' whole note = 96 microbeats
  283. RETURN
  284. > PROCEDURE read_key_decoders
  285.   LOCAL i%
  286.   REM The decoders convert the key press to the note to be sounded.
  287.   FOR i%=1 TO 7
  288.     READ white_keycod%(i%)
  289.   NEXT i%
  290.   FOR i%=1 TO 5
  291.     READ black_keycod%(i%)
  292.   NEXT i%
  293.   k%=0
  294.   FOR j%=0 TO 3
  295.     FOR i%=1 TO 7
  296.       white_key_decoder%(k%)=white_keycod%(i%)+30+j%*12
  297.       k%=k%+1
  298.     NEXT i%
  299.   NEXT j%
  300.   white_key_decoder%(28)=0 !for rest note
  301.   white_key_decoder%(29)=0 ! for rest note
  302.   white_key_decoder%(30)=0 ! for rest note
  303.   white_key_decoder%(31)=0
  304.   k%=1
  305.   FOR j%=0 TO 3
  306.     FOR i%=1 TO 5
  307.       black_key_decoder%(k%)=black_keycod%(i%)+30+12*j%
  308.       k%=k%+1
  309.     NEXT i%
  310.   NEXT j%
  311.   DATA 0,2,4,6,7,9,11
  312.   DATA 1,3,5,8,10
  313. RETURN
  314. > PROCEDURE read_black_keys
  315.   LOCAL i%
  316.   RESTORE black_keys_data
  317.   FOR i%=1 TO 5
  318.     READ black_keys%(i%)
  319.   NEXT i%
  320. black_keys_data:
  321.   DATA 13,35,57,93,117
  322. RETURN
  323. '
  324. '
  325. > PROCEDURE decode_mouse_key
  326.   ' the program spends most of its time here waiting for input
  327.   ' from the mouse or keyboard. ky% contains the key (black or white)
  328.   ' on the keyboard or other function buttons. eky% contains the
  329.   ' ascii code of key pressed on computer keyboard.
  330.   ' if a piano keyboard key is pressed, the pitch code is put in nte%
  331.   ' flags like write%, klick%, indicate what action is needed later
  332.   ky%=0
  333.   write%=0
  334.   SHOWM
  335.   REPEAT
  336.     k$=INKEY$
  337.     klick%=MOUSEK
  338.   UNTIL klick%<>0 OR k$<>""
  339.   IF k$<>"" THEN
  340.     eky%=ASC(k$)
  341.     GOTO mouse_key_exit
  342.   ENDIF
  343.   ky%=@get_zone
  344.   IF ky%=0
  345.     ypos%=MOUSEY
  346.     IF ypos%<wb% AND ypos%>wt%
  347.       ky%=(MOUSEX) DIV 20
  348.       write%=1
  349.       nte%=white_key_decoder%(ky%)
  350.       IF ky%>28 !so we don't have conflict with function keys
  351.         ky%=28
  352.       ENDIF
  353.       GOTO mouse_key_exit
  354.     ENDIF
  355.   ENDIF
  356.   IF ky%<21 AND ky%>0 THEN
  357.     nte%=black_key_decoder%(ky%)
  358.     write%=1
  359.     GOTO mouse_key_exit
  360.   ENDIF
  361.   IF ky%>33
  362.     GOTO mouse_key_exit
  363.   ENDIF
  364.   IF ky%>20
  365.     tlen%=ky%-21
  366.     write%=0
  367.     @switch_note_duration
  368.   ENDIF
  369. mouse_key_exit:
  370. RETURN
  371. > PROCEDURE ascii_code_dispatcher
  372.   ' the ascii code dispatcher provides a sometimes more convenient
  373.   ' way of calling a function. i.e type l or L gets the load file
  374.   ' function. The F1 to F10 map into note durations. This feature
  375.   ' is not documented in the help file.
  376.   IF eky%=0
  377.     scancode%=CVI(k$)
  378.     IF scancode%>58 AND scancode%<68
  379.       tlen%=scancode%-58
  380.       @switch_note_duration
  381.       GOTO exit_dispatcher
  382.     ENDIF
  383.     SELECT scancode%
  384.     CASE 82
  385.       @insert_note
  386.     DEFAULT
  387.     ENDSELECT
  388.   ELSE
  389.     SELECT eky%
  390.     CASE 76,108
  391.       @read_tune_file
  392.     CASE 83,115
  393.       @write_tune_file
  394.     CASE 65,97
  395.       @append_tune_file
  396.     CASE 67,99
  397.       @clear_one_voice
  398.     CASE 74,106
  399.       '     @jump
  400.     CASE 113
  401.       @cue
  402.     CASE 127
  403.       @delete_note
  404.     DEFAULT
  405.       LOCATE 1,1
  406.       PRINT eky%
  407.     ENDSELECT
  408.   ENDIF
  409. exit_dispatcher:
  410.   k$=""
  411. RETURN
  412. '
  413. > PROCEDURE draw_sharp_key_signature
  414.   LOCAL i%
  415.   next_note_xposition%=50
  416.   FOR i%=1 TO key_sig%-8
  417.     yp%=sharp_sig_ypos%(i%)
  418.     PUT next_note_xposition%,yp%+staff_yshift%+40,sprite$(6),7
  419.     yp%=flat_sig_ypos%(i%)
  420.     PUT next_note_xposition%,yp%+staff_yshift%+40,sprite$(6),7
  421.     next_note_xposition%=next_note_xposition%+10
  422.   NEXT i%
  423. RETURN
  424. > PROCEDURE draw_flat_key_signature
  425.   LOCAL i%
  426.   next_note_xposition%=50
  427.   FOR i%=1 TO 8-key_sig%
  428.     yp%=sharp_sig_ypos%(8-i%)
  429.     PUT next_note_xposition%,yp%+staff_yshift%+40,sprite$(5),7
  430.     yp%=flat_sig_ypos%(8-i%)
  431.     PUT next_note_xposition%,yp%+staff_yshift%+40,sprite$(5),7
  432.     next_note_xposition%=next_note_xposition%+10
  433.   NEXT i%
  434. RETURN
  435. > PROCEDURE draw_treble_bass_staff
  436.   DEFFILL 0
  437.   PBOX 5,48+staff_yshift%,639,124+staff_yshift%
  438.   DEFFILL 1
  439.   COLOR 1
  440.   FOR i=1 TO 5
  441.     LINE 5,60+staff_yshift%+i*5,639,60+i*5+staff_yshift%
  442.     LINE 5,95+i*5+staff_yshift%,639,95+i*5+staff_yshift%
  443.   NEXT i
  444.   PUT 10,65+staff_yshift%,sprite$(1),7
  445.   PUT 10,100+staff_yshift%,sprite$(2),7
  446.   next_note_xposition%=55
  447.   @display_key_signature
  448.   GET 0,60+staff_yshift%,620,121+staff_yshift%,staff$ !save for refresh
  449. RETURN
  450. > PROCEDURE draw_musedt_screen
  451.   CLS
  452.   @draw_keyboard
  453.   @draw_black_keys
  454.   @display_note_duration_menu
  455.   @display_menu
  456.   @display_top_menu
  457.   @display_tempo
  458.   @display_editor_key_sig
  459.   @display_number_of_beats
  460.   @display_beat_size
  461.   @draw_treble_bass_staff
  462. RETURN
  463. > PROCEDURE display_key_signature
  464.   IF key_sig%<8
  465.     draw_flat_key_signature
  466.     usesharps%=0
  467.   ENDIF
  468.   IF key_sig%>8
  469.     draw_sharp_key_signature
  470.     usesharps%=1
  471.   ENDIF
  472.   next_note_xposition%=next_note_xposition%+10
  473.   new_staff_xposition%=next_note_xposition%
  474. RETURN
  475. > PROCEDURE new_key_signature
  476.   ' if assumed_accidental = 0 --> usual for action drawing note
  477.   ' if assumed_accidental = 1 or -1 --> suppress accidental
  478.   ' if assumed_accidental = 2 or -2 --> must precede note with natural sign
  479.   ' when changing key signature we update this table
  480.   IF next_key_sig%=key_sig%
  481.     GOTO new_key_sig_return
  482.   ENDIF
  483.   IF next_key_sig%>key_sig%
  484.     WHILE key_sig%<next_key_sig%
  485.       key_sig%=key_sig%+1
  486.       assumed_accidental%(nat_keys%(key_sig%))=assumed_accidental%(nat_keys%(key_sig%))+2
  487.       assumed_accidental%(shrp_keys%(key_sig%))=assumed_accidental%(shrp_keys%(key_sig%))+1
  488.     WEND
  489.     GOTO new_key_sig_return
  490.   ELSE
  491.     WHILE key_sig%>next_key_sig%
  492.       assumed_accidental%(nat_keys%(key_sig%))=assumed_accidental%(nat_keys%(key_sig%))-2
  493.       assumed_accidental%(shrp_keys%(key_sig%))=assumed_accidental%(shrp_keys%(key_sig%))-1
  494.       key_sig%=key_sig%-1
  495.     WEND
  496.   ENDIF
  497. new_key_sig_return:
  498. RETURN
  499. > PROCEDURE new_bar_line
  500.   next_bar_line%=next_bar_line%+bar_length%
  501.   next_note_xposition%=next_note_xposition%+5
  502.   LINE next_note_xposition%,65+staff_yshift%,next_note_xposition%,85+staff_yshift%
  503.   LINE next_note_xposition%,100+staff_yshift%,next_note_xposition%,120+staff_yshift%
  504.   next_note_xposition%=next_note_xposition%+5
  505. RETURN
  506. > PROCEDURE draw_note_documentation
  507.   ' Drawing a note on the musical staff, is quite complex. This
  508.   ' is a first attempt. First we must intercept rests, repeat signs etc.
  509.   ' We must put preceding sharp, flat, natural symbols if necessary.
  510.   ' We display the note tail up or down depending on where it is on the
  511.   ' staff. A dot or numeral 3 must be placed for dotted notes or triplets.
  512.   ' Extra leger lines may be needed for some notes. Notes in other voices
  513.   ' should be vertically aligned if they occur at the same time or
  514.   ' otherwise offset.
  515. RETURN
  516. > PROCEDURE draw_note_on_staff(xp%,voice%)
  517.   REM intercept nte=0 for rests
  518.   REM need voice% number to decide which staff to put rests
  519.   '
  520.   ' is it a rest note or a repeat sign
  521.   IF nte%=0
  522.     yp%=0
  523.     IF voice%>1
  524.       yp%=35
  525.     ENDIF
  526.     IF tlen%<13
  527.       PUT xp%,67+yp%+staff_yshift%,sprite$(rest_sprite%(tlen%)),7
  528.       IF tlen%>2
  529.         IF ((tlen% MOD 2)=1)
  530.           PBOX xp%+20,70+yp%+staff_yshift%,xp%+21,71+yp%+staff_yshift%
  531.         ENDIF
  532.       ENDIF
  533.       xp%=xp%+25
  534.     ELSE
  535.       draw_marker(tlen%-11,xp%)
  536.     ENDIF
  537.     GOTO draw_note_return
  538.   ENDIF
  539.   '
  540.   ' not a rest note
  541.   yp%=note_yposition%(nte%-29)
  542.   ltr%=(nte% MOD 12)
  543.   IF ltr%=0 THEN
  544.     ltr%=12
  545.   ENDIF
  546.   '
  547.   ' do we draw any accidentals
  548.   accid%=0
  549.   IF yp%<0 AND usesharps%=0
  550.     yp%=flat_yposition%(-yp%)
  551.     accid%=1
  552.   ENDIF
  553.   IF yp%<0 AND usesharps%=1
  554.     yp%=sharp_yposition%(-yp%)
  555.     accid%=2
  556.   ENDIF
  557.   yp%=yp%+40
  558.   tnt%=length_sprite%(tlen%) !sprite number ignoring tail up/down
  559.   qnt%=tnt%
  560.   '
  561.   ' up tail or down tail
  562.   IF nte%>39 THEN
  563.     qnt%=tnt%+1
  564.   ENDIF
  565.   IF nte%=40 AND usesharps%=1
  566.     qnt%=tnt%
  567.   ENDIF
  568.   IF nte%>(49+usesharps%)
  569.     qnt%=tnt%
  570.   ENDIF
  571.   IF nte%>60
  572.     qnt%=tnt%+1
  573.   ENDIF
  574.   IF nte%=49
  575.     qnt%=tnt%
  576.     yp%=74
  577.   ENDIF
  578.   IF (ABS(assumed_accidental%(ltr%))=1) ! sharps or flats subsumed
  579.     accid%=0
  580.   ENDIF
  581.   IF (ABS(assumed_accidental%(ltr%))<>2)
  582.     IF accid%=0
  583.       GOTO noaccidentals
  584.     ENDIF
  585.     '
  586.     ' draw accidental (sharp  or flat)
  587.     IF (qnt% MOD 2)=1 THEN
  588.       accbse%=2
  589.     ENDIF
  590.     IF (qnt% MOD 2)=0 THEN
  591.       accbse%=4
  592.     ENDIF
  593.     PUT xp%,yp%+staff_yshift%,sprite$(accid%+accbse%),7
  594.     xp%=xp%+10
  595.     GOTO noaccidentals
  596.   ENDIF
  597.   '
  598.   ' draw natural sign
  599.   IF (qnt% MOD 2)=1
  600.     accbse%=25
  601.   ELSE
  602.     accbse%=26
  603.   ENDIF
  604.   PUT xp%,yp%+staff_yshift%,sprite$(accbse%),7
  605.   xp%=xp%+10
  606. noaccidentals:
  607.   PUT xp%,yp%+staff_yshift%,sprite$(qnt%),7
  608.   '
  609.   ' extra ledger lines?
  610.   IF nte%=49 AND qnt%=tnt%
  611.     LINE xp%+4,89+staff_yshift%,xp%+19,89+staff_yshift%
  612.   ENDIF
  613.   IF nte%=50 AND qnt%=tnt% AND usesharps%=1
  614.     LINE xp%+4,89+staff_yshift%,xp+19,89+staff_yshift%
  615.   ENDIF
  616.   IF nte%=49 AND qnt%<>tnt%
  617.     LINE xp%+4,96+staff_yshift%,xp%+19,96+staff_yshift%
  618.   ENDIF
  619.   IF nte%=50 AND usesharps%=1 AND qnt%<>tnt%
  620.     LINE xp%+4,96+staff_yshift%,xp%+19,96+staff_yshift%
  621.   ENDIF
  622.   IF nte%>69
  623.     LINE xp%+3,61+staff_yshift%,xp%+20,61+staff_yshift%
  624.   ENDIF
  625.   IF nte%>72 THEN
  626.     LINE xp%+3,57+staff_yshift%,xp%+20,57+staff_yshift%
  627.   ENDIF
  628.   IF nte%=77
  629.     LINE xp%+3,53+staff_yshift%,xp%+20,53+staff_yshift%
  630.   ENDIF
  631.   xp%=xp%+25
  632.   '
  633.   ' dotted note?
  634.   IF (tlen%>2) AND (tlen%<10) AND ((tlen% MOD 2)=1)
  635.     IF (qnt% MOD 2)=0
  636.       PBOX xp%,yp%+staff_yshift%+5,xp%+1,yp%+staff_yshift%+6
  637.     ELSE
  638.       PBOX xp%,yp%+staff_yshift%+15,xp%+1,yp%+staff_yshift%+16
  639.     ENDIF
  640.     xp%=xp%+5
  641.   ENDIF
  642.   IF (tlen%>9)
  643.     DEFTEXT 1,1,0,4
  644.     IF (qnt% MOD 2)=0
  645.       TEXT xp%,yp%+staff_yshift%+7,"3"
  646.     ELSE
  647.       TEXT xp%,yp%+staff_yshift%+17,"3"
  648.     ENDIF
  649.   ENDIF
  650. draw_note_return:
  651.   next_note_xposition%=MAX(xp%,next_note_xposition%)
  652. RETURN
  653. > PROCEDURE draw_marker(num%,xp%)
  654.   ' repeat markers num% from 1 to 3
  655.   IF voic1%<1
  656.     PUT xp%,66+staff_yshift%,sprite$(num%+25),7
  657.   ELSE
  658.     PUT xp%,102+staff_yshift%,sprite$(num%+25),7
  659.   ENDIF
  660.   next_note_xposition%=xp%+15
  661. RETURN
  662. > PROCEDURE new_staff
  663.   DEFFILL 0
  664.   PBOX 0,52+staff_yshift%,639,124+staff_yshift%
  665.   PUT 0,60+staff_yshift%,staff$
  666.   xp%=0
  667.   xnx%=0
  668.   next_note_xposition%=new_staff_xposition%
  669.   DEFFILL 1
  670. RETURN
  671. '
  672. > PROCEDURE yamaha_doc
  673.   ' I was not very successful using the sound or wave commands in gfa
  674.   ' basic to produce polyphonic music. (Its ok for chords). Furthermore
  675.   ' the envelope feature on the Yamaha chip produced problems that I could
  676.   ' not resolve. I therefore implemented the sound at a fairly low level
  677.   ' using BIOS commands. The following functions interface with the xbios
  678.   ' command 28. This is tricky since some of the registers are used for
  679.   ' disk i/o and damage to the disk can result. I put in extra protection
  680.   ' in this code which should never be commented out.
  681.   ' I decided to implement the music production this way rather than
  682.   ' using the xbios 32 play sequence command so that I can follow the
  683.   ' production of each note. Even though I am controlling the amplitude
  684.   ' envelope every 50 th of a second, as well as placing sprites on the
  685.   ' screen, there is ample time left over.
  686.   ' The make_tone_envelope function controls the linear rise and two
  687.   ' linear decay modes of the amplitude. The envelope is put into a table.
  688.   '
  689.   ' The procedure play_next_notes, polls all three voices to see whether
  690.   ' it is time to change the volume or pitch of a note. When it is
  691.   ' time to change it finds the next note and sets the time to change
  692.   ' that note based on the notes duration and the slowness of the music.
  693. RETURN
  694. > PROCEDURE initialize_note_table
  695.   ' Thanks ken
  696.   LOCAL note|
  697.   IF NOT u__init!
  698.     u__init!=TRUE
  699.     DIM u__period%(96)
  700.     FOR note|=0 TO 12
  701.       FOR o%=0 TO 7
  702.         u__period%(12*o%+note|)=125000/(2^o%*440*(2^(note|/12))/(2^(10/12))/16)+0.5
  703.       NEXT o%
  704.     NEXT note|
  705.   ENDIF
  706. RETURN
  707. > PROCEDURE set_tone_period(voice%,period%)
  708.   LOCAL reg%,period_low%,period_hi%,reg_val%
  709.   IF voice%<0 OR voice%>2
  710.     GOTO set_tone_err
  711.   ENDIF
  712.   reg%=voice%*2
  713.   period_low%=AND(period%,255)
  714.   period_hi%=SHR(AND(period%,&HF00),8)
  715.   period%=XBIOS(28,period_low%,reg%+128) !period% is not used anymore
  716.   reg%=reg%+1
  717.   reg_val%=AND(XBIOS(28,0,reg%),&HF0) !must save hi bits
  718.   reg_val%=OR(AND(period_hi%,15),reg_val%) !combine low and hi bits
  719.   reg_val%=XBIOS(28,reg_val%,reg%+128) !output
  720.   GOTO set_tone_return
  721. set_tone_err:
  722.   STOP
  723. set_tone_return:
  724. RETURN
  725. > PROCEDURE disable_noise_channels
  726.   LOCAL reg_val%
  727.   reg_val%=XBIOS(28,0,7)
  728.   reg_val%=OR(AND(reg_val%,192),56)
  729.   reg_val=XBIOS(28,reg_val%,7+128)
  730. RETURN
  731. > PROCEDURE set_volume(voice%,level%)
  732.   ' level between 0 and 15 for constant volume
  733.   ' level 16 for waveform envelope
  734.   LOCAL reg%,reg_val%
  735.   IF voice%<0 OR voice>2 !check for legal voice number
  736.     GOTO set_volume_err
  737.   ENDIF
  738.   IF level%>31 OR level%<0
  739.     GOTO set_volume_err
  740.   ENDIF
  741.   reg%=8+voice%
  742.   regval%=XBIOS(28,0,reg%)
  743.   regval%=AND(regval%,&HE0) !save only top 3 bits
  744.   regval%=OR(regval%,AND(level%,31))
  745.   regval%=XBIOS(28,regval%,reg%+128)
  746.   GOTO set_volume_return
  747. set_volume_err:
  748.   STOP
  749. set_volume_return:
  750. RETURN
  751. > PROCEDURE play_tune(cue_flag%)
  752.   ' The procedure plays song number numb%.
  753.   ' The base_time% is set to the current time in ticks.
  754.   ' The function next_note is called repeatedly, to sound the next
  755.   ' note when it is time to do so. If a note has been sounded, we
  756.   ' draw it on the staff.
  757.   LOCAL i%,note_xposition%
  758.   skoll%=0 ! rem scrolling is off
  759.   @draw_treble_bass_staff
  760.   ' find voices
  761.   IF speed%>0
  762.     slowness=135/speed% !comment this statement when debugging
  763.   ELSE
  764.     slowness=2
  765.   ENDIF
  766.   base_time%=TIMER
  767.   FOR i%=1 TO 3
  768.     IF cue_flag%<>1
  769.       seq%(i%)=0
  770.       repeat_count%(i%-1)=0
  771.       repeat_sign%(i%-1)=0
  772.       play_stop%(i%-1)=vclen%(i%-1)
  773.       elapsed_microbeats%(i%-1)=0
  774.       micro_beat%(i%)=0
  775.       next_bar_line%=bar_length%
  776.     ELSE
  777.       play_stop%(i%-1)=kount%(i%-1)
  778.     ENDIF
  779.     IF klick%=2 AND cue_flag%=1
  780.       play_stop%(i%-1)=vclen%(i%-1)
  781.     ENDIF
  782.     next_event%(i%)=base_time%+slowness*micro_beat%(i%)
  783.     IF seq%(i%)<=play_stop%(i%-1)
  784.       voice_end_flag%(i%)=0
  785.     ELSE
  786.       voice_end_flag%(i%)=1
  787.     ENDIF
  788.     @set_volume(i%-1,10)
  789.     @set_tone_period(i%-1,5)
  790.   NEXT i%
  791.   LOCATE 1,1
  792.   '
  793.   ' ready to start
  794.   @disable_noise_channels
  795.   REPEAT
  796.     FOR i%=1 TO 3
  797.       draw_flag%(i%)=0
  798.     NEXT i%
  799.     @play_next_notes
  800.     ' the rest of this code is used for drawing the notes on the staff
  801.     ' when necessary.
  802.     IF next_note_xposition%>595 THEN
  803.       @new_staff
  804.     ENDIF
  805.     note_xposition%=next_note_xposition%
  806.     FOR i%=1 TO 3
  807.       IF draw_flag%(i%)=1
  808.         kk%=i%
  809.         nte%=note%(i%)
  810.         tlen%=duration%(i%)
  811.         elapsed_microbeats%(i%-1)=elapsed_microbeats%(i%-1)+notes_to_microbeats%(tlen%)
  812.         IF (elapsed_microbeats%(i%-1)>next_bar_line%)
  813.           @new_bar_line
  814.           note_xposition%=next_note_xposition%
  815.         ENDIF
  816.         ' PRINT nte%,tlen%
  817.         IF (nte%>29 AND nte%<90) OR nte%=0
  818.           @draw_note_on_staff(note_xposition%,i%)
  819.         ENDIF
  820.       ENDIF
  821.     NEXT i%
  822.     PAUSE 1 ! we have lots of time to spare
  823.     i%=voice_end_flag%(1)+voice_end_flag%(2)+voice_end_flag%(3)
  824.     key_interrupt$=INKEY$
  825.     IF cue_flag%=1 AND klick%<>2
  826.       IF seq%(voic1%+1)>=kount%(voic1%)
  827.         i%=3
  828.       ENDIF
  829.     ENDIF
  830.   UNTIL i%=3 OR key_interrupt$<>""
  831.   FOR i%=0 TO 2
  832.     set_volume(i%,0)
  833.     IF seq%(i%+1)<=vclen%(i%)
  834.       kount%(i%)=seq%(i%+1) !play_next_notes overshoots
  835.     ELSE
  836.       kount%(i%)=vclen%(i%)
  837.     ENDIF
  838.   NEXT i%
  839.   tlen%=duration%(voic%)
  840.   @update_editor_windows
  841.   @switch_note_duration
  842. RETURN
  843. > PROCEDURE play_next_notes
  844.   LOCAL i%,j%
  845.   ' this procedure sequences through the notes in the tnote array and
  846.   ' sounds them on the Yamaha chip using the xbios function 28. The array
  847.   ' voice_end_flag indicates whether a particular voice has finished.
  848.   ' The next_event% array indicates the next time tick to process the
  849.   ' next note for the particular voice. The tick number was determined
  850.   ' from the previous note duration (and slowness parameter).
  851.   ' If the note was sounded, we store the key and duration for that voice
  852.   ' in the arrays note% and duration%. We set the draw_flag to tell
  853.   ' the procedure play_tune that we have a note to be displayed on the
  854.   ' staff.
  855.   ' this code applies the envelope function to the amplitude.
  856.   t%=TIMER
  857.   FOR i%=1 TO 3
  858.     index%=SHR(t%,2)-note_tick%(i%)
  859.     IF index%>0 AND index%<100
  860.       j%=i%-1
  861.       set_volume(j%,tone_envel%(index%+j%*100))
  862.     ENDIF
  863.   NEXT i%
  864.   '
  865.   FOR i%=1 TO 3 !check if it is time to sound next note for all voices
  866.     IF voice_end_flag%(i%)<1
  867.       IF t%>=next_event%(i%)
  868.         tlen%=-1
  869.         ' find the next note of finite duration and bypass any control
  870.         ' codes
  871.         DO UNTIL tlen%>=0 AND tlen%<13 OR seq%(i%)>play_stop%(i%-1) OR tlen%>14
  872.           seq%(i%)=seq%(i%)+1
  873.           ne%=tnote&(i%-1,seq%(i%))
  874.           IF seq%(i%)>play_stop%(i%-1)
  875.             voice_end_flag%(i%)=1
  876.             set_volume(i%-1,0)
  877.             tlen%=0
  878.           ELSE
  879.             tlen%=SHR(ne%,8)
  880.           ENDIF
  881.           IF tlen%=13
  882.             repeat_sign%(i%-1)=seq%(i%)
  883.             repeat_count%(i%-1)=0
  884.           ENDIF
  885.           IF tlen%=14 AND repeat_count%(i%-1)<1
  886.             seq%(i%)=repeat_sign%(i%-1)
  887.             INC repeat_count%(i%-1)
  888.           ENDIF
  889.           IF tlen%=16
  890.             ' necessary to resync using a variable size rest
  891.             low_byte%=ne% MOD 256
  892.             elapsed_microbeats%(i%-1)=elapsed_microbeats%(i%-1)+low_byte%*96
  893.             micro_beat%(i%)=micro_beat%(i%)+low_byte%*96
  894.           ENDIF
  895.           IF tlen%=17
  896.             ' necessary to resync using a variable size rest
  897.             low_byte%=ne% MOD 256
  898.             elapsed_microbeats%(i%-1)=elapsed_microbeats%(i%-1)+low_byte%
  899.             micro_beat%(i%)=micro_beat%(i%)+low_byte%
  900.           ENDIF
  901.         LOOP
  902.         IF tlen%=15 AND repeat_count%(i%-1)>0
  903.           skip_to_repeat_sign(i%)
  904.         ENDIF
  905.         IF seq%(i%)>1000
  906.           voice_end_flag%(i%)=1
  907.         ENDIF
  908.         IF voice_end_flag%(i%)=1
  909.           GOTO play_next_voice
  910.         ENDIF
  911.         IF tlen%>13
  912.           next_event%(i%)=base_time%+micro_beat%(i%)*slowness
  913.           set_volume(i%-1,0)
  914.           note_tick%(i%)=0
  915.           GOTO play_next_voice
  916.         ENDIF
  917.         nte%=ne% MOD 256 !get and sound note
  918.         IF nte%<96 AND nte%>5
  919.           set_tone_period(i%-1,u__period%(nte%))
  920.           note_tick%(i%)=SHR(t%,2)
  921.         ENDIF
  922.         ' set time to end note
  923.         micro_beat%(i%)=micro_beat%(i%)+notes_to_microbeats%(tlen%)
  924.         next_event%(i%)=base_time%+micro_beat%(i%)*slowness
  925.         draw_flag%(i%)=1
  926.         note%(i%)=nte%
  927.         duration%(i%)=tlen%
  928.       ENDIF
  929.     ENDIF
  930.   play_next_voice:
  931.   NEXT i% ! next voice
  932. RETURN
  933. > PROCEDURE resync_voices
  934.   ' inserts rests to get all voices resyncd.
  935.   LOCAL i%,j%,repeat%,largest%,nrest%,nfrac%,dif%,timinc%
  936.   largest%=0
  937.   FOR j%=0 TO 2
  938.     repeat%=1
  939.     elapsed_microbeats%(j%)=0
  940.     FOR i%=1 TO vclen%(j%)
  941.       tlen%=SHR(tnote&(j%,i%),8)
  942.       low_byte%=tnote&(j%,i%) MOD 256
  943.       IF tlen%=13
  944.         repeat%=2
  945.       ENDIF
  946.       IF tlen%=14 OR tlen%=15
  947.         repeat%=1
  948.       ENDIF
  949.       IF tlen%>0 AND tlen%<13
  950.         timinc%=notes_to_microbeats%(tlen%)
  951.         elapsed_microbeats%(j%)=elapsed_microbeats%(j%)+timinc%*repeat%
  952.       ENDIF
  953.       IF tlen%=16
  954.         timinc%=low_byte%*96
  955.         elapsed_microbeats%(j%)=elapsed_microbeats%(j%)+timinc%*repeat%
  956.       ENDIF
  957.       IF tlen%=17
  958.         timinc%=low_byte
  959.         elapsed_microbeats%(j%)=elapsed_microbeats%(j%)+timinc%*repeat%
  960.       ENDIF
  961.     NEXT i%
  962.     largest%=MAX(largest%,elapsed_microbeats%(j%))
  963.   NEXT j%
  964.   '  LOCATE 20,1
  965.   ' PRINT SPACE$(20)
  966.   ' LOCATE 20,1
  967.   FOR j%=0 TO 2
  968.     dif%=(largest%-elapsed_microbeats%(j%))
  969.     ' PRINT elapsed_microbeats%(j%);" ";
  970.     nrest%=dif% DIV 96
  971.     nfrac%=dif% MOD 96
  972.     IF nrest%<>0
  973.       INC vclen%(j%)
  974.       tnote&(j%,vclen%(j%))=256*16+nrest%
  975.     ENDIF
  976.     IF nfrac%<>0
  977.       INC vclen%(j%)
  978.       tnote&(j%,vclen%(j%))=256*17+nfrac%
  979.     ENDIF
  980.   NEXT j%
  981. RETURN
  982. > PROCEDURE compute_seq_in_middle(voice%,kounter%)
  983.   ' in order to get random access to any part of the music
  984.   ' in the cue command, the procedure finds note positions
  985.   ' for the other voices which would be sounded at the
  986.   ' same time as tnote(voice%,kounter%). It also sets up
  987.   ' relative delays in case the corresponding notes in the other voices
  988.   ' are not coincident.
  989.   LOCAL i%,stopmubeat%,mubeat%
  990.   stopmubeat%=0
  991.   seq%(voice%+1)=kounter%
  992.   FOR i%=1 TO kounter%
  993.     tlen%=SHR(tnote&(voice%,i%),8)
  994.     IF tlen%>0 AND tlen%<10
  995.       stopmubeat%=stopmubeat%+notes_to_microbeats%(tlen%)
  996.     ENDIF
  997.   NEXT i%
  998.   ' now find seq% for the other voices
  999.   FOR j%=0 TO 2
  1000.     mubeat%(j%)=0
  1001.   NEXT j%
  1002.   FOR j%=0 TO 2
  1003.     IF j%<>voice%
  1004.       FOR i%=0 TO vclen%(j%)
  1005.         '
  1006.         tlen%=SHR(tnote&(j%,i%),8)
  1007.         IF tlen%>0 AND tlen%<13
  1008.           mubeat%(j%)=mubeat%(j%)+notes_to_microbeats%(tlen%)
  1009.         ENDIF
  1010.         EXIT IF mubeat%(j%)>=stopmubeat%
  1011.       NEXT i%
  1012.       seq%(j%+1)=i%
  1013.     ELSE
  1014.       mubeat%(j%)=stopmubeat%
  1015.     ENDIF
  1016.   NEXT j%
  1017.   FOR j%=0 TO 2
  1018.     elapsed_microbeats%(j%)=mubeat%(j%)
  1019.     micro_beat%(j%+1)=mubeat%(j%)-stopmubeat%
  1020.   NEXT j%
  1021.   ' be sure that seq() does not go beyond vclen%()
  1022.   FOR j%=1 TO 3
  1023.     IF vclen%(j%-1)=0
  1024.       seq%(j%)=0
  1025.     ENDIF
  1026.   NEXT j%
  1027.   next_bar_line%=(stopmubeat% DIV bar_length%+1)*bar_length%
  1028. RETURN
  1029. > PROCEDURE cue
  1030.   IF kount%(voic1%)>5
  1031.     compute_seq_in_middle(voic1%,kount%(voic1%)-5)
  1032.   ELSE
  1033.     compute_seq_in_middle(voic1%,1)
  1034.   ENDIF
  1035.   LOCATE 1,1
  1036.   play_tune(1)
  1037. RETURN
  1038. > PROCEDURE skip_to_repeat_sign(i%)
  1039.   LOCAL done%
  1040.   done%=0
  1041.   DO UNTIL voice_end_flag%(i%-1)=1 OR done%=1
  1042.     INC seq%(i%)
  1043.     ne%=tnote&(i%-1,seq%(i%))
  1044.     IF seq%(i%)>play_stop%(i%-1)
  1045.       voice_end_flag%(i%)=1
  1046.       set_volume(i%-1,0)
  1047.       tlen%=0
  1048.     ELSE
  1049.       tlen%=SHR(ne%,8)
  1050.     ENDIF
  1051.     IF tlen%=14
  1052.       done%=1
  1053.     ENDIF
  1054.   LOOP
  1055. RETURN
  1056. '
  1057. > PROCEDURE draw_keyboard
  1058.   LOCAL i%
  1059.   wb%=195
  1060.   wt%=wb%-40
  1061.   REM draw white keys
  1062.   FOR i%=0 TO 28
  1063.     BOX i%*20,wb%,i%*20+18,wt%
  1064.   NEXT i%
  1065.   DEFTEXT 1,0,2700,13
  1066.   TEXT 563,wt%+5,"REST"
  1067.   DEFTEXT 1,1,0,6
  1068. RETURN
  1069. > PROCEDURE draw_black_keys
  1070.   LOCAL i%,j%
  1071.   @read_black_keys
  1072.   DEFFILL 1
  1073.   wb%=wb%-13
  1074.   k%=1
  1075.   REM draw black keys. The black keys are also zoned.
  1076.   FOR j%=1 TO 4
  1077.     FOR i%=1 TO 5
  1078.       PBOX black_keys%(i%),wb%,black_keys%(i%)+10,wt%
  1079.       set_zone(k%,black_keys%(i%),wt%,black_keys%(i%)+10,wb%)
  1080.       k%=k%+1
  1081.       black_keys%(i%)=black_keys%(i%)+140
  1082.     NEXT i%
  1083.   NEXT j%
  1084.   wb%=wb%+13
  1085.   number_of_zones%=k%-1
  1086. RETURN
  1087. > PROCEDURE set_zone(num%,xleft%,ytop%,xright%,ybot%)
  1088.   ' sets up mouse sensitive zones
  1089.   x1%(num%)=xleft%
  1090.   x2%(num%)=xright%
  1091.   y1%(num%)=ytop%
  1092.   y2%(num%)=ybot%
  1093. RETURN
  1094. > FUNCTION get_zone
  1095. LOCAL i%
  1096. button%=0
  1097. FOR i%=1 TO number_of_zones%
  1098.   IF (MOUSEX>x1%(i%))
  1099.     IF MOUSEX<x2%(i%)
  1100.       IF MOUSEY>y1%(i%)
  1101.         IF MOUSEY<y2%(i%)
  1102.           RETURN i%
  1103.         ENDIF
  1104.       ENDIF
  1105.     ENDIF
  1106.   ENDIF
  1107. NEXT i%
  1108. RETURN 0
  1109. ENDFUNC
  1110. > PROCEDURE display_note_duration_menu
  1111. DEFFILL 1
  1112. xp%=1
  1113. yp%=130
  1114. k%=21
  1115. FOR i%=0 TO 12
  1116.   PUT xp%,yp%,sprite$(length_sprite%(i%))
  1117.   IF i%>2 AND (i% MOD 2)=1 AND i%<10
  1118.     PBOX xp%+25,yp%+15,xp%+26,yp%+16
  1119.   ENDIF
  1120.   IF i%>9
  1121.     DEFTEXT 1,1,0,4
  1122.     TEXT xp%+22,yp%+17,"3"
  1123.   ENDIF
  1124.   BOX xp%,yp%,xp%+34,yp%+20
  1125.   @set_zone(k%,xp%,yp%,xp%+34,yp%+20)
  1126.   k%=k%+1
  1127.   xp%=xp%+35
  1128. NEXT i%
  1129. FOR i%=13 TO 15
  1130.   PUT xp%+5,yp%+2,sprite$(i%+14)
  1131.   BOX xp%,yp%,xp%+34,yp%+20
  1132.   @set_zone(k%,xp%,yp%,xp%+34,yp%+20)
  1133.   k%=k%+1
  1134.   xp%=xp%+35
  1135. NEXT i%
  1136. number_of_zones%=k%
  1137. RETURN
  1138. > PROCEDURE switch_note_duration
  1139. COLOR 0
  1140. BOX ltlen%*35+2,131,(1+ltlen%)*35+2,149
  1141. COLOR 1
  1142. BOX tlen%*35+2,131,(1+tlen%)*35+2,149
  1143. ltlen%=tlen%
  1144. RETURN
  1145. > PROCEDURE display_menu
  1146. LOCAL i%
  1147. menu_row%=114
  1148. BOX 0,menu_row%-9,470,menu_row%+12
  1149. INC number_of_zones%
  1150. set_zone(number_of_zones%,0,menu_row%-9,470,menu_row%+12)
  1151. LINE 0,menu_row%+2,470,menu_row%+2
  1152. FOR i%=1 TO 9
  1153.   LINE i%*48-2,menu_row%-9,i%*48-2,menu_row%+12
  1154. NEXT i%
  1155. DEFTEXT 1,0,0,6
  1156. TEXT 2,menu_row%,"PLAY"
  1157. TEXT 6*8,menu_row%,"SHOW"
  1158. TEXT 12*8,menu_row%," -->"
  1159. TEXT 18*8,menu_row%," <-- "
  1160. SELECT voic%
  1161. CASE 1
  1162.   TEXT 24*8,menu_row%,"TRK 1"
  1163. CASE 2
  1164.   TEXT 24*8,menu_row%,"TRK 2"
  1165. CASE 3
  1166.   TEXT 24*8,menu_row%,"TRK 3"
  1167. ENDSELECT
  1168. TEXT 30*8,menu_row%," KEY "
  1169. TEXT 8*36,menu_row%,"RESET"
  1170. TEXT 8*42,menu_row%,"LOAD"
  1171. TEXT 8*48,menu_row%,"APND"
  1172. TEXT 8*54,menu_row%,"QUIT"
  1173. TEXT 2,menu_row%+10," CUE"
  1174. TEXT 6*8,menu_row%+10," FF"
  1175. TEXT 12*8,menu_row%+10," DEL"
  1176. TEXT 18*8,menu_row%+10," INS"
  1177. TEXT 24*8,menu_row%+10,"SPEED"
  1178. TEXT 30*8,menu_row%+10,"TIME"
  1179. TEXT 36*8,menu_row%+10,"CLEAR"
  1180. TEXT 42*8,menu_row%+10,"SAVE"
  1181. TEXT 48*8,menu_row%+10,"HELP"
  1182. TEXT 8*54,menu_row%+10,"ENVL"
  1183. RETURN
  1184. '
  1185. > PROCEDURE execute_menu_command
  1186. LOCAL command%
  1187. command%=((MOUSEY-menu_row%+9) DIV 10)*10+MOUSEX DIV 48
  1188. SELECT command%
  1189. CASE 0
  1190.   @play_tune(0)
  1191. CASE 1
  1192.   @show
  1193. CASE 2
  1194.   @shift_sequence_number(1)
  1195. CASE 3
  1196.   @shift_sequence_number(-1)
  1197. CASE 4
  1198.   @change_voice_number
  1199. CASE 5
  1200.   @set_key_signature
  1201. CASE 6
  1202.   @reset
  1203. CASE 7
  1204.   @read_tune_file
  1205. CASE 8
  1206.   @append_tune_file
  1207. CASE 9
  1208.   END
  1209. CASE 10
  1210.   @cue
  1211. CASE 11
  1212.   @fast_forward
  1213. CASE 12
  1214.   @delete_note
  1215. CASE 13
  1216.   @insert_note
  1217. CASE 14
  1218.   @set_speed
  1219. CASE 15
  1220.   @set_time_signature
  1221. CASE 16
  1222.   @clear_one_voice
  1223. CASE 17
  1224.   @write_tune_file
  1225. CASE 18
  1226.   @show_instructions
  1227. CASE 19
  1228.   @set_tone_envelope
  1229. DEFAULT
  1230.   LOCATE 1,1
  1231.   PRINT command%
  1232. ENDSELECT
  1233. RETURN
  1234. '
  1235. > PROCEDURE shift_sequence_number(dir%)
  1236. IF kount%(voic1%)<2 AND dir%<0
  1237.   GOTO shift_sequence_return
  1238. ENDIF
  1239. IF kount%(voic1%)>=vclen%(voic1%) AND dir%>0
  1240.   GOTO shift_sequence_return
  1241. ENDIF
  1242. IF dir%>0
  1243.   kount%(voic1%)=kount%(voic1%)+dir%
  1244.   ne%=tnote&(voic1%,kount%(voic1%))
  1245.   nte%=ne% MOD 256
  1246.   tlen%=ne% DIV 256
  1247.   IF tlen%<13
  1248.     elapsed_microbeats%(voic1%)=elapsed_microbeats%(voic1%)+notes_to_microbeats%(tlen%)
  1249.     @switch_note_duration
  1250.   ENDIF
  1251. ELSE
  1252.   ne%=tnote&(voic1%,kount%(voic1%))
  1253.   nte%=ne% MOD 256
  1254.   tlen%=ne% DIV 256
  1255.   IF tlen%<13
  1256.     elapsed_microbeats%(voic1%)=elapsed_microbeats%(voic1%)-notes_to_microbeats%(tlen%)
  1257.   ENDIF
  1258.   kount%(voic1%)=kount%(voic1%)+dir%
  1259.   ne%=tnote&(voic1%,kount%(voic1%))
  1260.   nte%=ne% MOD 256
  1261.   tlen%=ne% DIV 256
  1262.   IF tlen%<13
  1263.     @switch_note_duration
  1264.   ENDIF
  1265. ENDIF
  1266. next_bar_line%=(elapsed_microbeats%(voic1%) DIV bar_length%+1)*bar_length%
  1267. @update_editor_windows
  1268. @show
  1269. shift_sequence_return:
  1270. RETURN
  1271. > PROCEDURE change_voice_number
  1272. DEFTEXT 1,0,0,6
  1273. INC voic%
  1274. IF voic%>3
  1275.   voic%=1
  1276. ENDIF
  1277. SELECT voic%
  1278. CASE 1
  1279.   TEXT 24*8,menu_row%,"TRK 1"
  1280. CASE 2
  1281.   TEXT 24*8,menu_row%,"TRK 2"
  1282. CASE 3
  1283.   TEXT 24*8,menu_row%,"TRK 3"
  1284. ENDSELECT
  1285. voic1%=voic%-1
  1286. next_bar_line%=(elapsed_microbeats%(voic1%) DIV bar_length%+1)*bar_length%
  1287. @show
  1288. RETURN
  1289. > PROCEDURE set_speed
  1290. LOCAL xspeed%
  1291. xspeed%=2.3*xspeed%+400
  1292. DEFFILL 0
  1293. PBOX 400,0,639,30
  1294. DEFFILL 1
  1295. BOX 400,10,630,20
  1296. PBOX 400,11,xspeed%,19
  1297. SETMOUSE 510,22
  1298. TEXT 400,28,"SLOW"
  1299. TEXT 600,28,"FAST"
  1300. HIDEM
  1301. PAUSE 15
  1302. DO UNTIL MOUSEK<>0
  1303.   IF MOUSEX<400
  1304.     SETMOUSE 400,22
  1305.   ENDIF
  1306.   IF MOUSEX>630
  1307.     SETMOUSE 630,22
  1308.   ENDIF
  1309.   IF MOUSEY<>22
  1310.     SETMOUSE MOUSEX,22
  1311.   ENDIF
  1312.   DEFFILL 0
  1313.   PBOX MOUSEX,11,629,19
  1314.   DEFFILL 1
  1315.   PBOX 400,11,MOUSEX,19
  1316.   speed%=(MOUSEX-400)/2.3
  1317.   @display_tempo
  1318. LOOP
  1319. SHOWM
  1320. DEFFILL 0
  1321. PBOX 400,0,639,30
  1322. DEFFILL 1
  1323. SETMOUSE 300,100
  1324. PAUSE 5
  1325. RETURN
  1326. > PROCEDURE set_time_signature
  1327. DEFFILL 0
  1328. PBOX 400,0,639,30
  1329. LOCATE 51,1
  1330. PRINT "Press + or - for bar length"
  1331. DEFLINE 1,3
  1332. BOX 410,10,430,20
  1333. TEXT 416,18,"+"
  1334. set_zone(number_of_zones%+1,410,10,430,20)
  1335. BOX 450,10,470,20
  1336. TEXT 456,18,"-"
  1337. set_zone(number_of_zones%+2,450,10,470,20)
  1338. BOX 490,10,520,20
  1339. TEXT 496,18,"ok"
  1340. set_zone(number_of_zones%+3,490,10,520,20)
  1341. DEFLINE 1,1
  1342. eky%=0
  1343. number_of_zones%=number_of_zones%+3
  1344. DO UNTIL eky%=13 OR ky%=41
  1345.   k$=INKEY$
  1346.   eky%=ASC(k$)
  1347.   IF MOUSEK<>0
  1348.     ky%=@get_zone
  1349.     EXIT IF ky%<39
  1350.     PAUSE 10
  1351.   ENDIF
  1352.   IF (eky%=43 OR ky%=39) AND beats_per_bar%<100
  1353.     INC beats_per_bar%
  1354.     @display_number_of_beats
  1355.     ky%=38
  1356.     SHOWM
  1357.   ENDIF
  1358.   IF (eky%=45 OR ky%=40) AND beats_per_bar%>1
  1359.     DEC beats_per_bar%
  1360.     @display_number_of_beats
  1361.     ky%=38
  1362.     SHOWM
  1363.   ENDIF
  1364. LOOP
  1365. next_bar_line%=(elapsed_microbeats%(voic1%) DIV bar_length%+1)*bar_length%
  1366. PBOX 400,0,639,8
  1367. LOCATE 51,1
  1368. PRINT "Press + or - for beat size"
  1369. eky%=0
  1370. ky%=38
  1371. DO UNTIL eky%=13 OR ky%=41
  1372.   k$=INKEY$
  1373.   eky%=ASC(k$)
  1374.   IF MOUSEK<>0
  1375.     ky%=@get_zone
  1376.     PAUSE 10
  1377.     EXIT IF ky%<39
  1378.   ENDIF
  1379.   IF (eky%=43 OR ky%=39) AND beat_size<10
  1380.     INC beat_size%
  1381.     @display_beat_size
  1382.     ky%=38
  1383.     SHOWM
  1384.   ENDIF
  1385.   IF (eky%=45 OR ky%=40) AND beat_size%>1
  1386.     DEC beat_size%
  1387.     @display_beat_size
  1388.     ky%=38
  1389.     SHOWM
  1390.   ENDIF
  1391. LOOP
  1392. next_bar_line%=(elapsed_microbeats%(voic1%) DIV bar_length%+1)*bar_length%
  1393. number_of_zones%=number_of_zones%-3
  1394. PBOX 400,0,639,30
  1395. DEFFILL 1
  1396. RETURN
  1397. > PROCEDURE set_key_signature
  1398. DEFFILL 0
  1399. PBOX 400,0,639,30
  1400. LOCATE 51,1
  1401. PRINT "Press + or - to change key"
  1402. ' LOCATE 51,2
  1403. ' PRINT "(on keypad) and then return"
  1404. DEFLINE 1,3
  1405. BOX 410,10,430,20
  1406. TEXT 416,18,"+"
  1407. set_zone(number_of_zones%+1,410,10,430,20)
  1408. BOX 450,10,470,20
  1409. TEXT 456,18,"-"
  1410. set_zone(number_of_zones%+2,450,10,470,20)
  1411. BOX 490,10,520,20
  1412. TEXT 496,18,"ok"
  1413. set_zone(number_of_zones%+3,490,10,520,20)
  1414. DEFLINE 1,1
  1415. eky%=0
  1416. number_of_zones%=number_of_zones%+3
  1417. DO UNTIL eky%=13 OR ky%=41
  1418.   k$=INKEY$
  1419.   IF MOUSEK<>0
  1420.     ky%=@get_zone
  1421.     EXIT IF ky%<39
  1422.     PAUSE 10
  1423.   ENDIF
  1424.   eky%=ASC(k$)
  1425.   IF (eky%=43 OR ky%=39) AND key_sig%<15
  1426.     key_sig%=key_sig%+1
  1427.     assumed_accidental%(nat_keys%(key_sig%))=assumed_accidental%(nat_keys%(key_sig%))+2
  1428.     assumed_accidental%(shrp_keys%(key_sig%))=assumed_accidental%(shrp_keys%(key_sig%))+1
  1429.     @display_editor_key_sig
  1430.     @draw_treble_bass_staff
  1431.     ky%=38
  1432.     SHOWM
  1433.   ENDIF
  1434.   IF (eky%=45 OR ky%=40) AND key_sig%>1
  1435.     assumed_accidental%(nat_keys%(key_sig%))=assumed_accidental%(nat_keys%(key_sig%))-2
  1436.     assumed_accidental%(shrp_keys%(key_sig%))=assumed_accidental%(shrp_keys%(key_sig%))-1
  1437.     key_sig%=key_sig%-1
  1438.     @display_editor_key_sig
  1439.     @draw_treble_bass_staff
  1440.     ky%=38
  1441.     SHOWM
  1442.   ENDIF
  1443. LOOP
  1444. DEFFILL 0
  1445. PBOX 400,0,639,30
  1446. number_of_zones%=number_of_zones%-3
  1447. DEFFILL 1
  1448. RETURN
  1449. > PROCEDURE set_tone_envelope
  1450. CLS
  1451. @show_tone_envelope(voic1%)
  1452. TEXT 150,18,"Volume"
  1453. TEXT 150,30,"Decay"
  1454. BOX 210,10,230,20
  1455. TEXT 216,18,"+"
  1456. set_zone(number_of_zones%+1,210,10,230,20)
  1457. BOX 250,10,270,20
  1458. TEXT 256,18,"-"
  1459. set_zone(number_of_zones%+2,250,10,270,20)
  1460. BOX 210,22,230,32
  1461. TEXT 216,30,"+"
  1462. set_zone(number_of_zones%+3,210,22,230,30)
  1463. BOX 250,22,270,32
  1464. TEXT 256,30,"-"
  1465. set_zone(number_of_zones%+4,250,22,270,30)
  1466. BOX 290,10,320,20
  1467. TEXT 296,18,"ok"
  1468. set_zone(number_of_zones%+5,290,10,320,20)
  1469. DEFLINE 1,1
  1470. eky%=0
  1471. number_of_zones%=number_of_zones%+5
  1472. DO UNTIL ky%=43
  1473.   IF MOUSEK<>0
  1474.     ky%=@get_zone
  1475.   ENDIF
  1476.   IF (ky%=39)
  1477.     INC volum(voic1%)
  1478.     volum(voic1%)=MAX(15,volum(voic1%))
  1479.     @make_tone_envelope(voic1%,volum(voic1%),decay(voic1%))
  1480.     @show_tone_envelope(voic1%)
  1481.     ky%=0
  1482.     SHOWM
  1483.   ENDIF
  1484.   IF (ky%=40)
  1485.     DEC volum(voic1%)
  1486.     volum(voic%)=MIN(0,volum(voic1%))
  1487.     @make_tone_envelope(voic1%,volum(voic1%),decay(voic1%))
  1488.     @show_tone_envelope(voic1%)
  1489.     ky%=0
  1490.     SHOWM
  1491.   ENDIF
  1492.   IF (ky%=41)
  1493.     decay(voic1%)=decay(voic1%)+0.04
  1494.     decay(voic1%)=MIN(0.6,decay(voic1%))
  1495.     @make_tone_envelope(voic1%,volum(voic1%),decay(voic1%))
  1496.     @show_tone_envelope(voic1%)
  1497.     ky%=0
  1498.     SHOWM
  1499.   ENDIF
  1500.   IF (ky%=42)
  1501.     decay(voic1%)=decay(voic1%)-0.04
  1502.     decay(voic1%)=MAX(0,decay(voic1%))
  1503.     @make_tone_envelope(voic1%,volum(voic1%),decay(voic1%))
  1504.     @show_tone_envelope(voic1%)
  1505.     ky%=0
  1506.     SHOWM
  1507.   ENDIF
  1508. LOOP
  1509. DEFFILL 0
  1510. PBOX 400,0,639,30
  1511. number_of_zones%=number_of_zones%-5
  1512. DEFFILL 1
  1513. @draw_musedt_screen
  1514. RETURN
  1515. > PROCEDURE show_tone_envelope(num%)
  1516. LOCAL index%,i%,ix%,iy%
  1517. index%=100*num%
  1518. DEFFILL 0
  1519. PBOX 20,190,420,35
  1520. BOX 20,190,420,35
  1521. DEFFILL 1
  1522. FOR i%=0 TO 99
  1523.   ix%=20+4*i%
  1524.   iy%=190-10*tone_envel%(i%+index%)
  1525.   PBOX ix%,iy%,ix%+2,iy%-3
  1526. NEXT i%
  1527. TEXT 50,170,"Track"
  1528. TEXT 100,170,STR$(num%+1)
  1529. RETURN
  1530. > PROCEDURE make_tone_envelope(num%,offset,attenuation)
  1531. LOCAL index%,val%,i%
  1532. index%=num%*100
  1533. FOR i%=0 TO 99
  1534.   val%=offset-i%*attenuation
  1535.   val%=MAX(val%,0)
  1536.   val%=MIN(val%,15)
  1537.   tone_envel%(i%+index%)=val%
  1538. NEXT i%
  1539. RETURN
  1540. '
  1541. > PROCEDURE display_top_menu
  1542. edy%=14
  1543. edx%=58
  1544. ecol1%=6
  1545. ecol2%=16
  1546. ecol3%=22
  1547. ply%=2
  1548. plx%=1
  1549. LOCATE plx%,ply%
  1550. PRINT "Tempo"
  1551. LOCATE plx%+16,ply%
  1552. PRINT "Key Sig"
  1553. LOCATE plx%,ply%+1
  1554. PRINT "Num Beats"
  1555. LOCATE plx%+16,ply%+1
  1556. PRINT "Beat = "
  1557. RETURN
  1558. > PROCEDURE display_note_sequence
  1559. LOCAL beatnu%,beatfra%
  1560. LOCATE edx%+ecol1%,edy%
  1561. PRINT "          ";
  1562. LOCATE edx%+ecol1%,edy%
  1563. PRINT kount%(voic1%);
  1564. LOCATE edx%+ecol1%+4,edy%
  1565. beatnu%=elapsed_microbeats%(voic1%) DIV notes_to_microbeats%(beat_size%)
  1566. beatfra%=elapsed_microbeats%(voic1%) MOD notes_to_microbeats%(beat_size%)
  1567. PRINT beatnu%;"  ";beatfra%;
  1568. RETURN
  1569. > PROCEDURE display_note_name
  1570. ntelet%=nte% MOD 12
  1571. IF ntelet%=0 THEN
  1572.   ntelet%=12
  1573. ENDIF
  1574. nteoct%=nte% DIV 12
  1575. LOCATE edx%+ecol2%+1,edy%+voic%
  1576. PRINT "  ";
  1577. LOCATE edx%+ecol2%+1,edy%+voic%
  1578. IF nte%=0
  1579.   PRINT "PA";
  1580. ELSE
  1581.   IF kys%<8 THEN
  1582.     PRINT flat_key_to_letter$(ntelet%)
  1583.   ELSE
  1584.     PRINT sharp_key_to_letter$(ntelet%)
  1585.   ENDIF
  1586.   LOCATE edx%+ecol2%+3,edy%+voic%
  1587.   PRINT nteoct%;
  1588. ENDIF
  1589. RETURN
  1590. > PROCEDURE display_note_duration_name
  1591. LOCATE edx%+ecol2%+2,edy%
  1592. PRINT "   ";
  1593. LOCATE edx%+ecol2%+2,edy%
  1594. PRINT duration_to_text$(tlen%);
  1595. RETURN
  1596. > PROCEDURE update_editor_windows
  1597. @display_note_sequence
  1598. '  @display_note_name
  1599. @display_note_duration_name
  1600. REM gosub 6990 : rem return cursor to item
  1601. RETURN
  1602. > PROCEDURE display_tempo
  1603. LOCATE plx%+10,ply%
  1604. PRINT "   "
  1605. LOCATE plx%+10,ply%
  1606. PRINT speed%;
  1607. RETURN
  1608. > PROCEDURE display_editor_key_sig
  1609. LOCATE plx%+25,ply%
  1610. PRINT "       "
  1611. LOCATE plx%+25,ply%
  1612. PRINT keysig_to_text$(key_sig%);
  1613. RETURN
  1614. > PROCEDURE display_number_of_beats
  1615. LOCATE plx%+10,ply%+1
  1616. PRINT "  "
  1617. LOCATE plx%+10,ply%+1
  1618. PRINT beats_per_bar%;
  1619. bar_length%=beats_per_bar%*notes_to_microbeats%(beat_size%)
  1620. RETURN
  1621. > PROCEDURE display_beat_size
  1622. LOCATE plx%+23,ply%+1
  1623. PRINT "   "
  1624. LOCATE plx%+23,ply%+1
  1625. PRINT duration_to_text$(beat_size%);
  1626. bar_length%=beats_per_bar%*notes_to_microbeats%(beat_size%)
  1627. RETURN
  1628. '
  1629. > PROCEDURE show
  1630. LOCAL tlen%
  1631. @draw_treble_bass_staff
  1632. ' back up by 12 notes
  1633. IF kount%(voic1%)<1
  1634.   GOTO show_return
  1635. ENDIF
  1636. FOR i%=0 TO 12
  1637.   EXIT IF (kount%(voic1%)-i%<1)
  1638.   nc%=tnote&(voic1%,kount%(voic1%)-i%)
  1639.   tlen%=nc% DIV 256
  1640.   IF tlen%<13
  1641.     elapsed_microbeats%(voic1%)=elapsed_microbeats%(voic1%)-notes_to_microbeats%(tlen%)
  1642.   ENDIF
  1643.   begn%=kount%(voic1%)-i%
  1644. NEXT i%
  1645. IF begn%>vclen%(voic1%)
  1646.   GOTO show_return
  1647. ENDIF
  1648. next_bar_line%=(elapsed_microbeats%(voic1%) DIV bar_length%+1)*bar_length%
  1649. kk%=voic%
  1650. FOR i%=begn% TO kount%(voic1%)
  1651.   nc%=tnote&(voic1%,i%)
  1652.   nte%=nc% MOD 256
  1653.   tlen%=nc% DIV 256
  1654.   IF tlen%<13
  1655.     elapsed_microbeats%(voic1%)=elapsed_microbeats%(voic1%)+notes_to_microbeats%(tlen%)
  1656.   ENDIF
  1657.   IF (tlen%<16)
  1658.     IF (elapsed_microbeats%(voic1%)>next_bar_line%)
  1659.       @new_bar_line
  1660.       note_xposition%=next_note_xposition%
  1661.     ENDIF
  1662.     @draw_note_on_staff(next_note_xposition%,voic%)
  1663.   ENDIF
  1664. NEXT i%
  1665. write%=0
  1666. show_return:
  1667. @update_editor_windows
  1668. RETURN
  1669. > PROCEDURE clear_one_voice
  1670. DEFFILL 0
  1671. PBOX 400,0,639,30
  1672. LOCATE 51,1
  1673. PRINT "Clear track ";voic1%+1;" to end?"
  1674. DEFLINE 1,3
  1675. BOX 410,10,440,20
  1676. TEXT 416,18,"yes"
  1677. set_zone(number_of_zones%+1,416,10,436,20)
  1678. BOX 460,10,490,20
  1679. TEXT 468,18,"no"
  1680. set_zone(number_of_zones%+2,460,10,490,20)
  1681. DEFLINE 1,1
  1682. DO UNTIL MOUSEK<>0
  1683. LOOP
  1684. number_of_zones%=number_of_zones%+2
  1685. ky%=@get_zone
  1686. IF ky%=39
  1687.   vclen%(voic1%)=kount%(voic1%)
  1688. ENDIF
  1689. PAUSE 10
  1690. number_of_zones%=number_of_zones%-2
  1691. PBOX 400,0,639,30
  1692. DEFFILL 1
  1693. RETURN
  1694. > PROCEDURE reset
  1695. FOR i%=0 TO 2
  1696.   kount%(i%)=0
  1697.   vclen%(i%)=0
  1698.   elapsed_microbeats%(i%)=0
  1699. NEXT i%
  1700. @draw_treble_bass_staff
  1701. write%=0
  1702. next_bar_line%=bar_length%
  1703. voic%=1
  1704. voic1%=0
  1705. DEFTEXT 1,0,0,6
  1706. TEXT 24*8,menu_row%,"TRK 1"
  1707. note_xcoor%=40
  1708. tlen%=4
  1709. @switch_note_duration
  1710. RETURN
  1711. > PROCEDURE write_tune_file
  1712. LOCATE 51,2
  1713. DEFFILL 0
  1714. PBOX 400,0,639,30
  1715. DEFFILL 1
  1716. ' @tune_file_selector
  1717. FILESELECT #"output file","*.tun","noname.tun",tun$
  1718. @assert_tun_extension
  1719. PRINT "Output file :";tun$
  1720. IF tun$<>""
  1721.   OPEN "o",#1,tun$
  1722.   OUT #1,33
  1723.   OUT #1,key_sig%
  1724.   OUT #1,34
  1725.   OUT #1,beats_per_bar%
  1726.   OUT #1,35
  1727.   OUT #1,beat_size%
  1728.   OUT #1,36
  1729.   OUT #1,speed%
  1730.   OUT #1,37
  1731.   OUT #1,TRUNC(volum(0))+TRUNC(decay(0)*25)*16
  1732.   OUT #1,38
  1733.   OUT #1,TRUNC(volum(1))+TRUNC(decay(1)*25)*16
  1734.   OUT #1,39
  1735.   OUT #1,TRUNC(volum(2))+TRUNC(decay(2)*25)*16
  1736.   l%=8
  1737.   FOR i%=0 TO 2
  1738.     IF vclen%(i%)=0
  1739.       GOTO write_next_i
  1740.     ENDIF
  1741.     FOR k%=1 TO vclen%(i%)
  1742.       nc%=tnote&(i%,k%)
  1743.       tnte%=nc% MOD 256
  1744.       nlen%=nc% DIV 256
  1745.       OUT #1,nlen%
  1746.       OUT #1,tnte%
  1747.       l%=l%+2
  1748.     NEXT k%
  1749.     OUT #1,32
  1750.     OUT #1,0
  1751.     l%=l%+2
  1752.   write_next_i:
  1753.   NEXT i%
  1754.   CLOSE #1
  1755.   LOCATE 51,3
  1756.   PRINT l%;" bytes written"
  1757. ENDIF
  1758. write_tune_return:
  1759. ON ERROR
  1760. RETURN
  1761. > PROCEDURE write_tune_error
  1762. LOCATE 40,3
  1763. PRINT "disk write error"
  1764. RESUME write_tune_return
  1765. RETURN
  1766. > PROCEDURE read_tune_file
  1767. DEFFILL 0
  1768. PBOX 400,0,639,30
  1769. DEFFILL 1
  1770. LOCATE 51,2
  1771. ' PRINT "Enter input file :";
  1772. ' @tune_file_selector
  1773. FILESELECT #"input file","*.tun","noname.tun",tun$
  1774. PRINT "Input file = ";tun$
  1775. IF EXIST(tun$)=-1
  1776.   OPEN "i",#1,tun$
  1777.   FOR i%=0 TO 2
  1778.     vclen%(i%)=0
  1779.     kount%(i%)=0
  1780.   NEXT i%
  1781.   i%=0
  1782.   l%=0
  1783.   FOR k%=1 TO LOF(#1)/2
  1784.     s$=INPUT$(1,#1)
  1785.     nlen%=ASC(s$)
  1786.     s$=INPUT$(1,#1)
  1787.     tnte%=ASC(s$)
  1788.     nc%=nlen%*256+tnte%
  1789.     IF nlen%>17
  1790.       IF nlen%=32
  1791.         kount%(i%)=l%
  1792.         vclen%(i%)=l%
  1793.         l%=0
  1794.         i%=i%+1
  1795.       ENDIF
  1796.       IF nlen%=33
  1797.         next_key_sig%=tnte%
  1798.         @new_key_signature
  1799.       ENDIF
  1800.       IF nlen%=34
  1801.         beats_per_bar%=tnte%
  1802.         @display_number_of_beats
  1803.       ENDIF
  1804.       IF nlen%=35 THEN
  1805.         beat_size%=tnte%
  1806.         @display_beat_size
  1807.       ENDIF
  1808.       IF nlen%=36
  1809.         speed%=tnte%
  1810.         @display_tempo
  1811.       ENDIF
  1812.       IF nlen%=37
  1813.         volum(0)=tnte% MOD 16
  1814.         decay(0)=(tnte% DIV 16)/25
  1815.         @make_tone_envelope(0,volum(0),decay(0))
  1816.       ENDIF
  1817.       IF nlen%=38
  1818.         volum(1)=tnte% MOD 16
  1819.         decay(1)=(tnte% DIV 16)/25
  1820.         @make_tone_envelope(1,volum(1),decay(1))
  1821.       ENDIF
  1822.       IF nlen%=39
  1823.         volum(2)=tnte% MOD 16
  1824.         decay(2)=(tnte% DIV 16)/25
  1825.         @make_tone_envelope(2,volum(2),decay(2))
  1826.       ENDIF
  1827.     ELSE
  1828.       l%=l%+1
  1829.       tnote&(i%,l%)=nc%
  1830.     ENDIF
  1831.   NEXT k%
  1832.   CLOSE #1
  1833.   LOCATE 51,3
  1834.   PRINT k%;" notes read"
  1835.   vclen%(voic1%)=kount%(voic1%)
  1836. ELSE
  1837.   LOCATE 60,3
  1838.   PRINT "cannot read file"
  1839. ENDIF
  1840. read_tune_return:
  1841. RETURN
  1842. > PROCEDURE append_tune_file
  1843. DEFFILL 0
  1844. PBOX 400,0,639,30
  1845. DEFFILL 1
  1846. LOCATE 51,2
  1847. '  PRINT "Append file :";
  1848. '  @tune_file_selector
  1849. FILESELECT #"append file","*.tun","noname.tun",tun$
  1850. @resync_voices
  1851. IF EXIST(tun$)=-1
  1852.   OPEN "i",#1,tun$
  1853.   i%=0
  1854.   l%=vclen%(i%)
  1855.   FOR k%=1 TO LOF(#1)/2
  1856.     s$=INPUT$(1,#1)
  1857.     nlen%=ASC(s$)
  1858.     s$=INPUT$(1,#1)
  1859.     tnte%=ASC(s$)
  1860.     nc%=nlen%*256+tnte%
  1861.     IF nlen%>17
  1862.       IF nlen%=32
  1863.         kount%(i%)=l%
  1864.         vclen%(i%)=l%
  1865.         i%=i%+1
  1866.         IF i%<3
  1867.           l%=vclen%(i%)
  1868.         ENDIF
  1869.       ENDIF
  1870.     ELSE
  1871.       l%=l%+1
  1872.       tnote&(i%,l%)=nc%
  1873.     ENDIF
  1874.   NEXT k%
  1875.   CLOSE #1
  1876.   LOCATE 51,3
  1877.   PRINT k%;" notes read"
  1878.   vclen%(voic1%)=kount%(voic1%)
  1879. ELSE
  1880.   LOCATE 60,3
  1881.   PRINT "cannot read file"
  1882. ENDIF
  1883. RETURN
  1884. > PROCEDURE assert_tun_extension
  1885. k%=LEN(tun$)
  1886. IF k%>12
  1887.   tun$=LEFT$(tun$,12)
  1888. ENDIF
  1889. k%=INSTR(tun$,".")
  1890. IF (k%>0)
  1891.   tun$=LEFT$(tun$,k%-1)
  1892. ENDIF
  1893. tun$=tun$+".TUN"
  1894. RETURN
  1895. > PROCEDURE delete_note
  1896. ptlen%=tlen%
  1897. IF kount%(voic1%)<vclen%(voic1%)
  1898.   IF tlen%<13
  1899.     elapsed_microbeats%(voic1%)=elapsed_microbeats%(voic1%)-notes_to_microbeats%(tlen%)
  1900.   ENDIF
  1901.   FOR l%=kount%(voic1%) TO vclen%(voic1%)
  1902.     tnote&(voic1%,l%)=tnote&(voic1%,l%+1)
  1903.   NEXT l%
  1904.   vclen%(voic1%)=vclen%(voic1%)-1
  1905.   nte%=tnote&(voic1%,kount%(voic1%)) MOD 256
  1906.   tlen%=tnote&(voic1%,kount%(voic1%)) DIV 256
  1907.   IF tlen%<13
  1908.     elapsed_microbeats%(voic1%)=elapsed_microbeats%(voic1%)+notes_to_microbeats%(tlen%)
  1909.   ENDIF
  1910.   next_bar_line%=(elapsed_microbeats%(voic1%) DIV bar_length%+1)*bar_length%
  1911.   @update_editor_windows
  1912.   tlen%=ptlen%
  1913.   @switch_note_duration
  1914.   GOTO delete_note_return
  1915. ELSE
  1916.   ' deleting last note
  1917.   IF kount%(voic1%)<1
  1918.     GOTO delete_note_return
  1919.   ENDIF
  1920.   IF vclen%(voic1%)<1
  1921.     GOTO delete_note_return
  1922.   ENDIF
  1923.   tlen%=SHR(tnote&(voic1%,kount%(voic1%)),8)
  1924.   IF tlen%<13
  1925.     elapsed_microbeats%(voic1%)=elapsed_microbeats%(voic1%)-notes_to_microbeats%(tlen%)
  1926.   ENDIF
  1927.   vclen%(voic1%)=vclen%(voic1%)-1
  1928.   kount%(voic1%)=kount%(voic1%)-1
  1929.   IF kount%(voic1%)<1
  1930.     @update_editor_windows
  1931.     GOTO delete_note_return
  1932.   ENDIF
  1933.   nte%=tnote&(voic1%,kount%(voic1%)) MOD 256
  1934.   tlen%=tnote&(voic1%,kount%(voic1%)) DIV 256
  1935.   next_bar_line%=(elapsed_microbeats%(voic1%) DIV bar_length%+1)*bar_length%
  1936.   @update_editor_windows
  1937.   tlen%=ptlen%
  1938.   @switch_note_duration
  1939. ENDIF
  1940. delete_note_return:
  1941. @show
  1942. RETURN
  1943. > PROCEDURE insert_note
  1944. ld%=vclen%(voic1%)
  1945. lum%=vclen%(voic1%)-kount%(voic1%)
  1946. FOR l%=0 TO lum%
  1947.   tnote&(voic1%,ld%+1-l%)=tnote&(voic1%,ld%-l%)
  1948. NEXT l%
  1949. vclen%(voic1%)=vclen%(voic1%)+1
  1950. ne%=nte%+tlen%*256
  1951. tnote&(voic1%,kount%(voic1%))=ne%
  1952. INC kount%(voic1%)
  1953. @show
  1954. RETURN
  1955. > PROCEDURE sound_note
  1956. ntelet%=nte% MOD 12
  1957. IF ntelet%=12
  1958.   ntelet%=12
  1959. ENDIF
  1960. nteoct%=nte% DIV 12
  1961. SOUND 0,10,ntelet%,nteoct%,0
  1962. WAVE 7,7,1,5000,10
  1963. RETURN
  1964. > PROCEDURE show_instructions
  1965. LOCAL i%,string$
  1966. RESTORE instructions
  1967. CLS
  1968. LOCATE 1,1
  1969. FOR i%=1 TO 22
  1970.   READ string$
  1971.   PRINT string$
  1972. NEXT i%
  1973. ~INP(2)
  1974. CLS
  1975. @draw_musedt_screen
  1976. instructions:
  1977. DATA Left mouse button keys in next note on piano.
  1978. DATA Right mouse button alters last note keyed on piano.
  1979. DATA The space bar stops the music when playing.
  1980. DATA PLAY - plays back everything keyed in.
  1981. DATA CUE - plays last few notes keyed in.
  1982. DATA SHOW - displays last few notes in active track.
  1983. DATA --> shift to next note in current track.
  1984. DATA <-- shift to previous note in current track.
  1985. DATA DEL - delete current note.
  1986. DATA INS - same note into track.
  1987. DATA FF - fast forward to any note in the memory
  1988. DATA TRK - select track number.
  1989. DATA SPEED - select tempo of music.
  1990. DATA KEY - select key signature.
  1991. DATA TIME - set time signature.
  1992. DATA RESET - clears everything
  1993. DATA CLEAR - clears selected track.
  1994. DATA SAVE - save work on disk producing a *.TUN file.
  1995. DATA LOAD - load a *.TUN file into memory.
  1996. DATA APND - append a *.TUN file to the music already in memory
  1997. DATA The musedt.hlp file has more detailed instructions
  1998. DATA ..........hit any key to continue
  1999. RETURN
  2000. > PROCEDURE fast_forward
  2001. LOCAL lastpos%,nextpos%
  2002. DEFFILL 0
  2003. PBOX 400,0,639,30
  2004. DEFFILL 1
  2005. BOX 399,10,631,20
  2006. TEXT 400,28,"start"
  2007. TEXT 600,28,"end"
  2008. HIDEM
  2009. DEFFILL 1
  2010. SETMOUSE kount%(voic1%)/vclen%(voic1%)*230+400,22
  2011. DO UNTIL MOUSEK<>0
  2012.   IF MOUSEX<401
  2013.     SETMOUSE 401,22
  2014.   ENDIF
  2015.   IF MOUSEX>629
  2016.     SETMOUSE 629,22
  2017.   ENDIF
  2018.   lastpos%=kount%(voic1%)/vclen%(voic1%)*230+400
  2019.   nextpos%=MOUSEX
  2020.   LOCATE 70,1
  2021.   PRINT "    "
  2022.   LOCATE 70,1
  2023.   PRINT kount%(voic1%)
  2024.   IF lastpos%<>nextpos%
  2025.     COLOR 0
  2026.     LINE lastpos%,11,lastpos%,19
  2027.     COLOR 1
  2028.     IF nextpos%>629
  2029.       nextpos%=629
  2030.     ENDIF
  2031.     IF nextpos%<401
  2032.       nextpos%=401
  2033.     ENDIF
  2034.     kount%(voic1%)=(nextpos%-400)/230*vclen%(voic1%)
  2035.     nextpos%=kount%(voic1%)/vclen%(voic1%)*230+400
  2036.     LINE nextpos%,11,nextpos%,19
  2037.   ENDIF
  2038.   PAUSE 5
  2039. LOOP
  2040. LOCATE 78,1
  2041. PRINT vclen%(voic1%);
  2042. DEFFILL 0
  2043. PBOX 396,0,639,30
  2044. DEFFILL 1
  2045. RETURN
  2046.