Author Topic: Keys48 - Playable/Recordable instrument program  (Read 6293 times)

0 Members and 1 Guest are viewing this topic.

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Keys48 - Playable/Recordable instrument program
« on: January 18, 2021, 02:40:51 pm »
Here's something I've been working on for about a week.  It's a simple piano program that you can play and save little songs with.  Use the mouse to click on and play the notes.  There's a menu listing the simple commands.  Saved songs have a very small size thanks to the _DEFLATE command.

I've included a few songs I've recorded here.  When you start the program, press "L" and load a sample song like, DAV, or SAMPLE or WALTZ to hear an example of what you can record with it.

Made just for fun - it's not a serious program or anything, just something to code.  Let me know how it runs.  I'll post the code here, but you will need to whole package to compile it...

- Dav

NOTE: You need the attachment to compile this...
Code: QB64: [Select]
  1. '==========
  2. 'KEYS48.BAS v1.0
  3. '==========
  4. 'A Playable/Recordable Keyboard instrument
  5. 'Coded by Dav for QB64, JAN/2021
  6.  
  7. 'NOTE: Before compiling, check 'Output EXE to Source'
  8.  
  9. '-----
  10. 'ABOUT
  11. '-----
  12.  
  13. 'KEYS48 is a virtual instrument that you can play and
  14. 'and record little piano tunes with.  Use mouse to click on
  15. 'and play notes. The program starts in freeplay mode, but
  16. 'you can record in real time as you play by pressing R.
  17. 'Record over your song several times to add more notes and
  18. 'make more complex patterns (called overdubbing).
  19.  
  20. '--------
  21. 'CONTROLS
  22. '--------
  23.  
  24. 'Press M fo a menu list of commands.
  25.  
  26. 'Press R to record song and to overdub (add) notes to a song.
  27. 'Press U to Undo last recording (in case you make a mistake!)
  28. 'Press P to playback the recorded song currently in memory.
  29. 'Press C to clear (erase) recorded notes currently in memory.
  30. 'Press +/- keys to adjust playback and recording speed.
  31. '        Current speed value is shown at the top left.
  32. 'Press ENTER to go back to default speed of 100.
  33.  
  34. 'Press ESC to stop recording playback of the song.
  35. 'NOTE: You can also play notes during song playback.
  36.  
  37. 'Press S to Save your recording to .K46 file in songs dir.
  38. '        If the file already exists, it will be overwritten.
  39. '        If not the program will ask you for a song name.
  40. '        The .K48 extension will be added automatically.
  41. 'Press L to Load a saved song in the songs dir.
  42. 'Press D to Delete currently load song.
  43. '
  44. '=========================================================
  45. '
  46. 'PRO TIP: Having trouble playing fast enough with mouse?
  47. '         Slow down Speed BEFORE recording, then raise it
  48. '         back up when playing song back.
  49. '
  50. '=========================================================
  51. '
  52. 'NOTES: The directory 'keys' hold the keyboard sounds.
  53. '       The directory 'songs' holds all the .K48 songs.
  54. '       Both directories are required to use this program.
  55. '       They must be in the current EXE program path.
  56. '       Currently loaded song and speed is shown top left.
  57. '       Song speed setting is saved with the song file.
  58. '       Currently the max song length is about 6 minutes.
  59. '       You can change that with the MaxSongLength var.
  60. '
  61. '=========================================================
  62. '
  63. 'Things planned in next version: Record speed changes
  64. '                                (Add Page Up/Down +/- 5)
  65. '                                Turn Overdub ON/Off
  66. '                                Add a Metronome click
  67. '                                Add render to .WAV file
  68. '                                (will ask Petr for help!)
  69. '                                Add more keyboard sounds
  70. '                                Add Loop song playing
  71. '                                pause, record position
  72. '                                Seek position in song
  73. '
  74. '=========================================================
  75.  
  76. SCREEN _LOADIMAGE("keys48.png", 32)
  77.  
  78. _TITLE "Dav's 48 Keys v1.0": _ICON _DISPLAY
  79.  
  80. 'Make sure keys directory is present first...
  81. IF _DIREXISTS("keys") = 0 THEN
  82.     DrawBox: LOCATE 15, 37:
  83.     PRINT "ERROR: Needed 'keys' directory not found!"
  84.     END
  85.  
  86. 'Make a songs directory if not found
  87. IF _DIREXISTS("songs") = 0 THEN MKDIR "songs"
  88.  
  89. 'share note variable, playing flag, timer for all 48 keys
  90. DIM SHARED n01flag, n01timer, n01&, n02flag, n02timer, n02&
  91. DIM SHARED n03flag, n03timer, n03&, n04flag, n04timer, n04&
  92. DIM SHARED n05flag, n05timer, n05&, n06flag, n06timer, n06&
  93. DIM SHARED n07flag, n07timer, n07&, n08flag, n08timer, n08&
  94. DIM SHARED n09flag, n09timer, n09&, n10flag, n10timer, n10&
  95. DIM SHARED n11flag, n11timer, n11&, n12flag, n12timer, n12&
  96. DIM SHARED n13flag, n13timer, n13&, n14flag, n14timer, n14&
  97. DIM SHARED n15flag, n15timer, n15&, n16flag, n16timer, n16&
  98. DIM SHARED n17flag, n17timer, n17&, n18flag, n18timer, n18&
  99. DIM SHARED n19flag, n19timer, n19&, n20flag, n20timer, n20&
  100. DIM SHARED n21flag, n21timer, n21&, n22flag, n22timer, n22&
  101. DIM SHARED n23flag, n23timer, n23&, n24flag, n24timer, n24&
  102. DIM SHARED n25flag, n25timer, n25&, n26flag, n26timer, n26&
  103. DIM SHARED n27flag, n27timer, n27&, n28flag, n28timer, n28&
  104. DIM SHARED n29flag, n29timer, n29&, n30flag, n30timer, n30&
  105. DIM SHARED n31flag, n31timer, n31&, n32flag, n32timer, n32&
  106. DIM SHARED n33flag, n33timer, n33&, n34flag, n34timer, n34&
  107. DIM SHARED n35flag, n35timer, n35&, n36flag, n36timer, n36&
  108. DIM SHARED n37flag, n37timer, n37&, n38flag, n38timer, n38&
  109. DIM SHARED n39flag, n39timer, n39&, n40flag, n40timer, n40&
  110. DIM SHARED n41flag, n41timer, n41&, n42flag, n42timer, n42&
  111. DIM SHARED n43flag, n43timer, n43&, n44flag, n44timer, n44&
  112. DIM SHARED n45flag, n45timer, n45&, n46flag, n46timer, n46&
  113. DIM SHARED n47flag, n47timer, n47&, n48flag, n48timer, n48&
  114.  
  115. 'Load/open all keys sound files
  116. n01& = _SNDOPEN("keys\01.key"): n02& = _SNDOPEN("keys\02.key")
  117. n03& = _SNDOPEN("keys\03.key"): n04& = _SNDOPEN("keys\04.key")
  118. n05& = _SNDOPEN("keys\05.key"): n06& = _SNDOPEN("keys\06.key")
  119. n07& = _SNDOPEN("keys\07.key"): n08& = _SNDOPEN("keys\08.key")
  120. n09& = _SNDOPEN("keys\09.key"): n10& = _SNDOPEN("keys\10.key")
  121. n11& = _SNDOPEN("keys\11.key"): n12& = _SNDOPEN("keys\12.key")
  122. n13& = _SNDOPEN("keys\13.key"): n14& = _SNDOPEN("keys\14.key")
  123. n15& = _SNDOPEN("keys\15.key"): n16& = _SNDOPEN("keys\16.key")
  124. n17& = _SNDOPEN("keys\17.key"): n18& = _SNDOPEN("keys\18.key")
  125. n19& = _SNDOPEN("keys\19.key"): n20& = _SNDOPEN("keys\20.key")
  126. n21& = _SNDOPEN("keys\21.key"): n22& = _SNDOPEN("keys\22.key")
  127. n23& = _SNDOPEN("keys\23.key"): n24& = _SNDOPEN("keys\24.key")
  128. n25& = _SNDOPEN("keys\25.key"): n26& = _SNDOPEN("keys\26.key")
  129. n27& = _SNDOPEN("keys\27.key"): n28& = _SNDOPEN("keys\28.key")
  130. n29& = _SNDOPEN("keys\29.key"): n30& = _SNDOPEN("keys\30.key")
  131. n31& = _SNDOPEN("keys\31.key"): n32& = _SNDOPEN("keys\32.key")
  132. n33& = _SNDOPEN("keys\33.key"): n34& = _SNDOPEN("keys\34.key")
  133. n35& = _SNDOPEN("keys\35.key"): n36& = _SNDOPEN("keys\36.key")
  134. n37& = _SNDOPEN("keys\37.key"): n38& = _SNDOPEN("keys\38.key")
  135. n39& = _SNDOPEN("keys\39.key"): n40& = _SNDOPEN("keys\40.key")
  136. n41& = _SNDOPEN("keys\41.key"): n42& = _SNDOPEN("keys\42.key")
  137. n43& = _SNDOPEN("keys\43.key"): n44& = _SNDOPEN("keys\44.key")
  138. n45& = _SNDOPEN("keys\45.key"): n46& = _SNDOPEN("keys\46.key")
  139. n47& = _SNDOPEN("keys\47.key"): n48& = _SNDOPEN("keys\48.key")
  140.  
  141. 'Share/define these values - used often
  142. DIM SHARED WhtOn&, WhtOff&, BlkOn&, BlkOff&, Blk& 'colors
  143. DIM SHARED speed, MaxSongLength, release, header$
  144. DIM SHARED scr1 AS _MEM, scr2 AS _MEM 'for screen saving
  145.  
  146. WhtOn& = _RGB(179, 192, 211): WhtOff& = _RGB(246, 255, 255) 'key colors
  147. BlkOn& = _RGB(48, 84, 107): BlkOff& = _RGB(43, 56, 63): Blk& = _RGB(23, 23, 23)
  148. release = .4 'how long to highlight notes when played
  149. MaxSongLength = 500000 'max of 500k of song memory
  150. speed = 100 'playback speed defaults to 100%
  151.  
  152. GOSUB UpdateInfo
  153.  
  154. '========
  155. MainLoop: 'I dont currently call this, but it's here if needed.
  156. '========
  157.  
  158.  
  159.     GOSUB PlayKeys 'freeplay notes
  160.  
  161.     'Get user input...
  162.     k$ = UCASE$(INKEY$)
  163.     IF k$ <> "" THEN
  164.  
  165.         IF k$ = "R" THEN
  166.             GOSUB record: GOSUB UpdateInfo
  167.         END IF
  168.  
  169.         IF k$ = "P" THEN
  170.             GOSUB playback: GOSUB UpdateInfo
  171.         END IF
  172.  
  173.         IF k$ = "C" THEN
  174.             NoteData$ = "": song$ = ""
  175.             GOSUB SaveScreen
  176.             DrawBox: LOCATE 15, 37: PRINT " SONG MEMORY IS NOW CLEARED! "
  177.             _DELAY 2
  178.             GOSUB RestoreScreen: GOSUB UpdateInfo
  179.         END IF
  180.  
  181.         IF k$ = "U" THEN
  182.             GOSUB SaveScreen: DrawBox
  183.             IF NoteData$ <> "" THEN
  184.                 NoteData$ = UndoData$
  185.                 LOCATE 15, 37: PRINT "  UNDOING YOUR LAST RECORDING...  ";
  186.             ELSE
  187.                 LOCATE 15, 37: PRINT "  THERE'S NO RECORDING TO UNDO!";
  188.             END IF
  189.             _DELAY 2
  190.             GOSUB RestoreScreen
  191.         END IF
  192.  
  193.         IF k$ = "S" THEN
  194.  
  195.             GOSUB SaveScreen: DrawBox
  196.  
  197.             IF NoteData$ = "" THEN
  198.                 LOCATE 15, 37: PRINT "  THERE IS NO SONG TO SAVE!  ";
  199.                 _DELAY 2
  200.             END IF
  201.  
  202.             IF song$ <> "" THEN 'song already opened...just update song
  203.                 OPEN "songs\" + song$ FOR OUTPUT AS #1
  204.                 header$ = CHR$(27) + "K48V100" + CHR$(speed)
  205.                 PRINT #1, header$;
  206.                 PRINT #1, _DEFLATE$(NoteData$);: CLOSE 1
  207.                 LOCATE 15, 37: PRINT UCASE$(song$); " HAS BEEN SAVED!";
  208.                 _DELAY 2
  209.             END IF
  210.  
  211.             'notedata here, song$ not made yet, so save new file
  212.             IF NoteData$ <> "" AND song$ = "" THEN
  213.                 LOCATE 15, 37: INPUT "SONG TO SAVE: ", song$
  214.                 IF song$ <> "" THEN
  215.                     'strip out any path given (thanks, Steve!)
  216.                     song$ = MID$(song$, _INSTRREV(song$, "\") + 1)
  217.                     IF INSTR(1, song$, ".") = 0 THEN song$ = song$ + ".k48"
  218.                     OPEN "songs\" + song$ FOR OUTPUT AS #1
  219.                     header$ = CHR$(27) + "K48V100" + CHR$(speed)
  220.                     PRINT #1, header$;
  221.                     PRINT #1, _DEFLATE$(NoteData$);: CLOSE 1
  222.                     LOCATE 15, 37: PRINT SPACE$(45);
  223.                     LOCATE 15, 37: PRINT UCASE$(song$); " HAS BEEN SAVED!";
  224.                     _DELAY 2
  225.                 END IF
  226.             END IF
  227.  
  228.             GOSUB RestoreScreen
  229.             GOSUB UpdateInfo
  230.  
  231.         END IF
  232.  
  233.         IF k$ = "L" THEN
  234.  
  235.             GOSUB SaveScreen: DrawBox
  236.  
  237.             LOCATE 15, 37: INPUT "SONG TO LOAD: ", tmpsong$
  238.             IF tmpsong$ <> "" THEN
  239.                 'strip out any path given (thanks, Steve!)
  240.                 tmpsong$ = MID$(tmpsong$, _INSTRREV(tmpsong$, "\") + 1)
  241.                 IF INSTR(1, tmpsong$, ".") = 0 THEN tmpsong$ = tmpsong$ + ".k48"
  242.                 IF _FILEEXISTS("songs\" + tmpsong$) THEN
  243.                     OPEN "songs\" + tmpsong$ FOR BINARY AS #1
  244.                     IF LOF(1) < 9 THEN
  245.                         header$ = "" 'file not big enough
  246.                     ELSE
  247.                         header$ = INPUT$(9, 1) 'load header
  248.                     END IF
  249.                     IF MID$(header$, 1, 8) <> CHR$(27) + "K48V100" THEN
  250.                         DrawBox: LOCATE 15, 37: PRINT UCASE$(tmpsong$); " FILE NOT VALID!";
  251.                     ELSE
  252.                         'set saved speed
  253.                         speed = ASC(MID$(header$, 9, 1))
  254.                         NoteData$ = _INFLATE$(INPUT$(LOF(1) - 9, 1)): CLOSE 1
  255.                         DrawBox: LOCATE 15, 37: PRINT UCASE$(tmpsong$); " HAS BEEN LOADED.";
  256.                         song$ = tmpsong$
  257.                     END IF
  258.                 ELSE
  259.                     DrawBox: LOCATE 15, 37: PRINT UCASE$(tmpsong$); " SONG FILE NOT FOUND!";
  260.                 END IF
  261.                 _DELAY 2
  262.             END IF
  263.  
  264.             GOSUB RestoreScreen
  265.             GOSUB UpdateInfo
  266.  
  267.         END IF
  268.  
  269.         IF k$ = "D" THEN
  270.  
  271.             GOSUB SaveScreen: DrawBox
  272.  
  273.             IF song$ <> "" AND _FILEEXISTS("songs\" + song$) THEN
  274.                 LOCATE 15, 37: PRINT "DELETE FILE "; UCASE$(song$);
  275.                 LOCATE 16, 45: PRINT "ARE YOU SURE? (Y/N)";
  276.                 sure$ = UCASE$(INPUT$(1))
  277.                 IF sure$ = "Y" THEN
  278.                     DrawBox
  279.                     KILL "songs\" + song$
  280.                     LOCATE 15, 37: PRINT UCASE$(song$); " DELETED!";
  281.                     NoteData$ = "": song$ = ""
  282.                     _DELAY 2
  283.                 END IF
  284.             ELSE
  285.                 LOCATE 15, 37: PRINT " NO SONG FOUND TO DELETE!  ";
  286.                 _DELAY 2
  287.             END IF
  288.  
  289.             GOSUB RestoreScreen
  290.             GOSUB UpdateInfo
  291.  
  292.         END IF
  293.  
  294.         IF k$ = "M" THEN
  295.             GOSUB SaveScreen
  296.             menu& = _LOADIMAGE("keys48m.png", 32)
  297.             _PUTIMAGE (235, 90), menu&: _FREEIMAGE menu&
  298.             SLEEP: _KEYCLEAR
  299.             GOSUB RestoreScreen
  300.         END IF
  301.  
  302.         IF k$ = "-" THEN
  303.             speed = speed - 1: IF speed < 40 THEN speed = 40
  304.             GOSUB UpdateInfo
  305.         END IF
  306.  
  307.         IF k$ = "+" THEN
  308.             speed = speed + 1: IF speed > 200 THEN speed = 200
  309.             GOSUB UpdateInfo
  310.         END IF
  311.  
  312.         IF k$ = CHR$(13) THEN
  313.             speed = 100: GOSUB UpdateInfo
  314.         END IF
  315.  
  316.         _KEYCLEAR
  317.  
  318.     END IF
  319.  
  320.     _LIMIT speed * 15 'this is the current delay/speed method....
  321.  
  322.  
  323.  
  324.  
  325. '=========================================================
  326. PlayKeys: 'Gets mouse input and plays keyboard
  327. '=======
  328.  
  329. IF _MOUSEBUTTON(1) = 0 THEN done = 0
  330.  
  331. IF _MOUSEBUTTON(1) AND done = 0 THEN
  332.     mx = _MOUSEX: my = _MOUSEY
  333.  
  334.     '=== play notes if clicked on one
  335.     'bottom row...
  336.     IF mx > 4 AND mx < 63 AND my > 432 AND my < 515 THEN DoNote 1
  337.     IF mx > 42 AND mx < 76 AND my > 348 AND my < 428 THEN DoNote 2
  338.     IF mx > 68 AND mx < 127 AND my > 432 AND my < 515 THEN DoNote 3
  339.     IF mx > 112 AND mx < 146 AND my > 348 AND my < 428 THEN DoNote 4
  340.     IF mx > 133 AND mx < 189 AND my > 432 AND my < 515 THEN DoNote 5
  341.     IF mx > 182 AND mx < 214 AND my > 348 AND my < 428 THEN DoNote 6
  342.     IF mx > 196 AND mx < 255 AND my > 432 AND my < 515 THEN DoNote 7
  343.     IF mx > 260 AND mx < 319 AND my > 432 AND my < 515 THEN DoNote 8
  344.     IF mx > 298 AND mx < 332 AND my > 348 AND my < 428 THEN DoNote 9
  345.     IF mx > 324 AND mx < 383 AND my > 432 AND my < 515 THEN DoNote 10
  346.     IF mx > 373 AND mx < 409 AND my > 348 AND my < 428 THEN DoNote 11
  347.     IF mx > 387 AND mx < 447 AND my > 432 AND my < 515 THEN DoNote 12
  348.     IF mx > 451 AND mx < 512 AND my > 432 AND my < 515 THEN DoNote 13
  349.     IF mx > 489 AND mx < 526 AND my > 348 AND my < 428 THEN DoNote 14
  350.     IF mx > 515 AND mx < 575 AND my > 432 AND my < 515 THEN DoNote 15
  351.     IF mx > 557 AND mx < 596 AND my > 348 AND my < 428 THEN DoNote 16
  352.     IF mx > 579 AND mx < 639 AND my > 432 AND my < 515 THEN DoNote 17
  353.     IF mx > 627 AND mx < 667 AND my > 348 AND my < 428 THEN DoNote 18
  354.     IF mx > 643 AND mx < 702 AND my > 432 AND my < 515 THEN DoNote 19
  355.     IF mx > 707 AND mx < 767 AND my > 432 AND my < 515 THEN DoNote 20
  356.     IF mx > 743 AND mx < 783 AND my > 348 AND my < 428 THEN DoNote 21
  357.     IF mx > 771 AND mx < 831 AND my > 432 AND my < 515 THEN DoNote 22
  358.     IF mx > 818 AND mx < 858 AND my > 348 AND my < 428 THEN DoNote 23
  359.     IF mx > 835 AND mx < 895 AND my > 432 AND my < 515 THEN DoNote 24
  360.     'top row...
  361.     IF mx > 5 AND mx < 65 AND my > 211 AND my < 294 THEN DoNote 25
  362.     IF mx > 42 AND mx < 81 AND my > 124 AND my < 207 THEN DoNote 26
  363.     IF mx > 69 AND mx < 129 AND my > 211 AND my < 294 THEN DoNote 27
  364.     IF mx > 114 AND mx < 147 AND my > 124 AND my < 207 THEN DoNote 28
  365.     IF mx > 133 AND mx < 192 AND my > 211 AND my < 294 THEN DoNote 29
  366.     IF mx > 184 AND mx < 215 AND my > 124 AND my < 207 THEN DoNote 30
  367.     IF mx > 197 AND mx < 256 AND my > 211 AND my < 294 THEN DoNote 31
  368.     IF mx > 261 AND mx < 320 AND my > 211 AND my < 294 THEN DoNote 32
  369.     IF mx > 301 AND mx < 332 AND my > 124 AND my < 207 THEN DoNote 33
  370.     IF mx > 325 AND mx < 384 AND my > 211 AND my < 294 THEN DoNote 34
  371.     IF mx > 376 AND mx < 407 AND my > 124 AND my < 207 THEN DoNote 35
  372.     IF mx > 388 AND mx < 448 AND my > 211 AND my < 294 THEN DoNote 36
  373.     IF mx > 452 AND mx < 512 AND my > 211 AND my < 294 THEN DoNote 37
  374.     IF mx > 493 AND mx < 525 AND my > 124 AND my < 207 THEN DoNote 38
  375.     IF mx > 516 AND mx < 576 AND my > 211 AND my < 294 THEN DoNote 39
  376.     IF mx > 561 AND mx < 594 AND my > 124 AND my < 207 THEN DoNote 40
  377.     IF mx > 580 AND mx < 640 AND my > 211 AND my < 294 THEN DoNote 41
  378.     IF mx > 631 AND mx < 664 AND my > 124 AND my < 207 THEN DoNote 42
  379.     IF mx > 644 AND mx < 703 AND my > 211 AND my < 294 THEN DoNote 43
  380.     IF mx > 708 AND mx < 767 AND my > 211 AND my < 294 THEN DoNote 44
  381.     IF mx > 748 AND mx < 780 AND my > 124 AND my < 207 THEN DoNote 45
  382.     IF mx > 772 AND mx < 831 AND my > 211 AND my < 294 THEN DoNote 46
  383.     IF mx > 823 AND mx < 855 AND my > 124 AND my < 207 THEN DoNote 47
  384.     IF mx > 836 AND mx < 895 AND my > 211 AND my < 294 THEN DoNote 48
  385.  
  386.     done = 1 'make a mouse click flag
  387.  
  388.  
  389. GOSUB NoteDisplay
  390.  
  391.  
  392.  
  393. '=========================================================
  394. record:
  395. '=======
  396.  
  397. 'Make copy of NoteData$ for undo purposes
  398. UndoData$ = NoteData$
  399.  
  400. IF NoteData$ = "" THEN NoteData$ = "1" 'song recording marker
  401. note = 1
  402.  
  403. COLOR _RGB(255, 255, 255), _RGB(255, 0, 0)
  404. LOCATE 1, 1: PRINT " Now Recording | ESC to Stop ";
  405.  
  406.  
  407.  
  408.     _LIMIT speed * 15 'this is the current delay/speed method....
  409.  
  410.     note$ = ""
  411.  
  412.     'playback any previously recorded notes
  413.     SELECT CASE MID$(NoteData$, note, 1)
  414.         CASE CHR$(1): DoNote 1
  415.         CASE CHR$(2): DoNote 2
  416.         CASE CHR$(3): DoNote 3
  417.         CASE CHR$(4): DoNote 4
  418.         CASE CHR$(5): DoNote 5
  419.         CASE CHR$(6): DoNote 6
  420.         CASE CHR$(7): DoNote 7
  421.         CASE CHR$(8): DoNote 8
  422.         CASE CHR$(9): DoNote 9
  423.         CASE CHR$(10): DoNote 10
  424.         CASE CHR$(11): DoNote 11
  425.         CASE CHR$(12): DoNote 12
  426.         CASE CHR$(13): DoNote 13
  427.         CASE CHR$(14): DoNote 14
  428.         CASE CHR$(15): DoNote 15
  429.         CASE CHR$(16): DoNote 16
  430.         CASE CHR$(17): DoNote 17
  431.         CASE CHR$(18): DoNote 18
  432.         CASE CHR$(19): DoNote 19
  433.         CASE CHR$(20): DoNote 20
  434.         CASE CHR$(21): DoNote 21
  435.         CASE CHR$(22): DoNote 22
  436.         CASE CHR$(23): DoNote 23
  437.         CASE CHR$(24): DoNote 24
  438.         CASE CHR$(25): DoNote 25
  439.         CASE CHR$(26): DoNote 26
  440.         CASE CHR$(27): DoNote 27
  441.         CASE CHR$(28): DoNote 28
  442.         CASE CHR$(29): DoNote 29
  443.         CASE CHR$(30): DoNote 30
  444.         CASE CHR$(31): DoNote 31
  445.         CASE CHR$(32): DoNote 32
  446.         CASE CHR$(33): DoNote 33
  447.         CASE CHR$(34): DoNote 34
  448.         CASE CHR$(35): DoNote 35
  449.         CASE CHR$(36): DoNote 36
  450.         CASE CHR$(37): DoNote 37
  451.         CASE CHR$(38): DoNote 38
  452.         CASE CHR$(39): DoNote 39
  453.         CASE CHR$(40): DoNote 40
  454.         CASE CHR$(41): DoNote 41
  455.         CASE CHR$(42): DoNote 42
  456.         CASE CHR$(43): DoNote 43
  457.         CASE CHR$(44): DoNote 44
  458.         CASE CHR$(45): DoNote 45
  459.         CASE CHR$(46): DoNote 46
  460.         CASE CHR$(47): DoNote 47
  461.         CASE CHR$(48): DoNote 48
  462.     END SELECT
  463.  
  464.     mi = _MOUSEINPUT
  465.     IF _MOUSEBUTTON(1) = 0 THEN done = 0
  466.  
  467.     IF _MOUSEBUTTON(1) AND done = 0 THEN
  468.         mx = _MOUSEX: my = _MOUSEY
  469.  
  470.         '=== play notes if clicked on one
  471.         'top row...
  472.         IF mx > 4 AND mx < 63 AND my > 432 AND my < 515 THEN DoNote 1: note$ = CHR$(1)
  473.         IF mx > 42 AND mx < 76 AND my > 348 AND my < 428 THEN DoNote 2: note$ = CHR$(2)
  474.         IF mx > 68 AND mx < 127 AND my > 432 AND my < 515 THEN DoNote 3: note$ = CHR$(3)
  475.         IF mx > 112 AND mx < 146 AND my > 348 AND my < 428 THEN DoNote 4: note$ = CHR$(4)
  476.         IF mx > 133 AND mx < 189 AND my > 432 AND my < 515 THEN DoNote 5: note$ = CHR$(5)
  477.         IF mx > 182 AND mx < 214 AND my > 348 AND my < 428 THEN DoNote 6: note$ = CHR$(6)
  478.         IF mx > 196 AND mx < 255 AND my > 432 AND my < 515 THEN DoNote 7: note$ = CHR$(7)
  479.         IF mx > 260 AND mx < 319 AND my > 432 AND my < 515 THEN DoNote 8: note$ = CHR$(8)
  480.         IF mx > 298 AND mx < 332 AND my > 348 AND my < 428 THEN DoNote 9: note$ = CHR$(9)
  481.         IF mx > 324 AND mx < 383 AND my > 432 AND my < 515 THEN DoNote 10: note$ = CHR$(10)
  482.         IF mx > 373 AND mx < 409 AND my > 348 AND my < 428 THEN DoNote 11: note$ = CHR$(11)
  483.         IF mx > 387 AND mx < 447 AND my > 432 AND my < 515 THEN DoNote 12: note$ = CHR$(12)
  484.         IF mx > 451 AND mx < 512 AND my > 432 AND my < 515 THEN DoNote 13: note$ = CHR$(13)
  485.         IF mx > 489 AND mx < 526 AND my > 348 AND my < 428 THEN DoNote 14: note$ = CHR$(14)
  486.         IF mx > 515 AND mx < 575 AND my > 432 AND my < 515 THEN DoNote 15: note$ = CHR$(15)
  487.         IF mx > 557 AND mx < 596 AND my > 348 AND my < 428 THEN DoNote 16: note$ = CHR$(16)
  488.         IF mx > 579 AND mx < 639 AND my > 432 AND my < 515 THEN DoNote 17: note$ = CHR$(17)
  489.         IF mx > 627 AND mx < 667 AND my > 348 AND my < 428 THEN DoNote 18: note$ = CHR$(18)
  490.         IF mx > 643 AND mx < 702 AND my > 432 AND my < 515 THEN DoNote 19: note$ = CHR$(19)
  491.         IF mx > 707 AND mx < 767 AND my > 432 AND my < 515 THEN DoNote 20: note$ = CHR$(20)
  492.         IF mx > 743 AND mx < 783 AND my > 348 AND my < 428 THEN DoNote 21: note$ = CHR$(21)
  493.         IF mx > 771 AND mx < 831 AND my > 432 AND my < 515 THEN DoNote 22: note$ = CHR$(22)
  494.         IF mx > 818 AND mx < 858 AND my > 348 AND my < 428 THEN DoNote 23: note$ = CHR$(23)
  495.         IF mx > 835 AND mx < 895 AND my > 432 AND my < 515 THEN DoNote 24: note$ = CHR$(24)
  496.         'bottom row...
  497.         IF mx > 5 AND mx < 65 AND my > 211 AND my < 294 THEN DoNote 25: note$ = CHR$(25)
  498.         IF mx > 42 AND mx < 81 AND my > 124 AND my < 207 THEN DoNote 26: note$ = CHR$(26)
  499.         IF mx > 69 AND mx < 129 AND my > 211 AND my < 294 THEN DoNote 27: note$ = CHR$(27)
  500.         IF mx > 114 AND mx < 147 AND my > 124 AND my < 207 THEN DoNote 28: note$ = CHR$(28)
  501.         IF mx > 133 AND mx < 192 AND my > 211 AND my < 294 THEN DoNote 29: note$ = CHR$(29)
  502.         IF mx > 184 AND mx < 215 AND my > 124 AND my < 207 THEN DoNote 30: note$ = CHR$(30)
  503.         IF mx > 197 AND mx < 256 AND my > 211 AND my < 294 THEN DoNote 31: note$ = CHR$(31)
  504.         IF mx > 261 AND mx < 320 AND my > 211 AND my < 294 THEN DoNote 32: note$ = CHR$(32)
  505.         IF mx > 301 AND mx < 332 AND my > 124 AND my < 207 THEN DoNote 33: note$ = CHR$(33)
  506.         IF mx > 325 AND mx < 384 AND my > 211 AND my < 294 THEN DoNote 34: note$ = CHR$(34)
  507.         IF mx > 376 AND mx < 407 AND my > 124 AND my < 207 THEN DoNote 35: note$ = CHR$(35)
  508.         IF mx > 388 AND mx < 448 AND my > 211 AND my < 294 THEN DoNote 36: note$ = CHR$(36)
  509.         IF mx > 452 AND mx < 512 AND my > 211 AND my < 294 THEN DoNote 37: note$ = CHR$(37)
  510.         IF mx > 493 AND mx < 525 AND my > 124 AND my < 207 THEN DoNote 38: note$ = CHR$(38)
  511.         IF mx > 516 AND mx < 576 AND my > 211 AND my < 294 THEN DoNote 39: note$ = CHR$(39)
  512.         IF mx > 561 AND mx < 594 AND my > 124 AND my < 207 THEN DoNote 40: note$ = CHR$(40)
  513.         IF mx > 580 AND mx < 640 AND my > 211 AND my < 294 THEN DoNote 41: note$ = CHR$(41)
  514.         IF mx > 631 AND mx < 664 AND my > 124 AND my < 207 THEN DoNote 42: note$ = CHR$(42)
  515.         IF mx > 644 AND mx < 703 AND my > 211 AND my < 294 THEN DoNote 43: note$ = CHR$(43)
  516.         IF mx > 708 AND mx < 767 AND my > 211 AND my < 294 THEN DoNote 44: note$ = CHR$(44)
  517.         IF mx > 748 AND mx < 780 AND my > 124 AND my < 207 THEN DoNote 45: note$ = CHR$(45)
  518.         IF mx > 772 AND mx < 831 AND my > 211 AND my < 294 THEN DoNote 46: note$ = CHR$(46)
  519.         IF mx > 823 AND mx < 855 AND my > 124 AND my < 207 THEN DoNote 47: note$ = CHR$(47)
  520.         IF mx > 846 AND mx < 895 AND my > 211 AND my < 294 THEN DoNote 48: note$ = CHR$(48)
  521.  
  522.         done = 1 'did a mouse click
  523.  
  524.     END IF
  525.  
  526.     GOSUB NoteDisplay
  527.  
  528.     IF note$ <> "" THEN
  529.         IF note <= LEN(NoteData$) THEN
  530.             MID$(NoteData$, note, 1) = note$ 'add the note
  531.         ELSE
  532.             NoteData$ = NoteData$ + note$
  533.         END IF
  534.     ELSE
  535.         IF note >= LEN(NoteData$) THEN
  536.             NoteData$ = NoteData$ + CHR$(255) 'else add empty space
  537.         END IF
  538.     END IF
  539.  
  540.     note = note + 1
  541.     IF note >= MaxSongLength THEN EXIT DO
  542.  
  543.  
  544.  
  545.  
  546. '=========================================================
  547. playback:
  548. '========
  549.  
  550. 'If nothing recorded yet, don't try play
  551. IF NoteData$ = "" THEN
  552.     COLOR _RGB(0, 0, 0), _RGB(255, 255, 0)
  553.     LOCATE 1, 1: PRINT " No recorded song in memory! ";
  554.     _DELAY 2
  555.     DO: LOOP UNTIL INKEY$ = ""
  556.     RETURN
  557.  
  558. COLOR _RGB(0, 0, 0), _RGB(0, 255, 0)
  559. LOCATE 1, 1: PRINT " Playing song | ESC to stop  ";
  560.  
  561. note = 1
  562.  
  563.  
  564.     _LIMIT speed * 15 'this is the current delay/speed method....
  565.  
  566.     SELECT CASE MID$(NoteData$, note, 1)
  567.         CASE CHR$(1): DoNote 1
  568.         CASE CHR$(2): DoNote 2
  569.         CASE CHR$(3): DoNote 3
  570.         CASE CHR$(4): DoNote 4
  571.         CASE CHR$(5): DoNote 5
  572.         CASE CHR$(6): DoNote 6
  573.         CASE CHR$(7): DoNote 7
  574.         CASE CHR$(8): DoNote 8
  575.         CASE CHR$(9): DoNote 9
  576.         CASE CHR$(10): DoNote 10
  577.         CASE CHR$(11): DoNote 11
  578.         CASE CHR$(12): DoNote 12
  579.         CASE CHR$(13): DoNote 13
  580.         CASE CHR$(14): DoNote 14
  581.         CASE CHR$(15): DoNote 15
  582.         CASE CHR$(16): DoNote 16
  583.         CASE CHR$(17): DoNote 17
  584.         CASE CHR$(18): DoNote 18
  585.         CASE CHR$(19): DoNote 19
  586.         CASE CHR$(20): DoNote 20
  587.         CASE CHR$(21): DoNote 21
  588.         CASE CHR$(22): DoNote 22
  589.         CASE CHR$(23): DoNote 23
  590.         CASE CHR$(24): DoNote 24
  591.         CASE CHR$(25): DoNote 25
  592.         CASE CHR$(26): DoNote 26
  593.         CASE CHR$(27): DoNote 27
  594.         CASE CHR$(28): DoNote 28
  595.         CASE CHR$(29): DoNote 29
  596.         CASE CHR$(30): DoNote 30
  597.         CASE CHR$(31): DoNote 31
  598.         CASE CHR$(32): DoNote 32
  599.         CASE CHR$(33): DoNote 33
  600.         CASE CHR$(34): DoNote 34
  601.         CASE CHR$(35): DoNote 35
  602.         CASE CHR$(36): DoNote 36
  603.         CASE CHR$(37): DoNote 37
  604.         CASE CHR$(38): DoNote 38
  605.         CASE CHR$(39): DoNote 39
  606.         CASE CHR$(40): DoNote 40
  607.         CASE CHR$(41): DoNote 41
  608.         CASE CHR$(42): DoNote 42
  609.         CASE CHR$(43): DoNote 43
  610.         CASE CHR$(44): DoNote 44
  611.         CASE CHR$(45): DoNote 45
  612.         CASE CHR$(46): DoNote 46
  613.         CASE CHR$(47): DoNote 47
  614.         CASE CHR$(48): DoNote 48
  615.     END SELECT
  616.  
  617.     note = note + 1
  618.  
  619.     'if done playing, exit
  620.     IF note >= LEN(NoteData$) THEN EXIT DO
  621.  
  622.     GOSUB PlayKeys 'you can play notes too while song plays
  623.  
  624.     k$ = INKEY$
  625.     IF k$ <> "" THEN
  626.         IF k$ = "-" THEN
  627.             speed = speed - 1
  628.             IF speed < 40 THEN speed = 40
  629.             COLOR _RGB(163, 163, 175), _RGB(70, 95, 114)
  630.             LOCATE 3, 3: PRINT " Speed ="; speed; "   ";
  631.         END IF
  632.         IF k$ = "+" THEN
  633.             speed = speed + 1
  634.             IF speed > 200 THEN speed = 200
  635.             COLOR _RGB(163, 163, 175), _RGB(70, 95, 114)
  636.             LOCATE 3, 3: PRINT " Speed ="; speed; "   ";
  637.         END IF
  638.         IF k$ = CHR$(13) THEN
  639.             speed = 100
  640.             COLOR _RGB(163, 163, 175), _RGB(70, 95, 114)
  641.             LOCATE 3, 3: PRINT " Speed ="; speed; "   ";
  642.         END IF
  643.         _KEYCLEAR
  644.     END IF
  645.  
  646. LOOP UNTIL k$ = CHR$(27)
  647.  
  648.  
  649.  
  650. '=======================================================
  651. NoteDisplay:
  652. '===========
  653. 'if note playing flag is on, check its timer.
  654. 'If release time is past, note goes back to normal, flag off
  655. IF n01flag = 1 THEN
  656.     IF TIMER - n01timer > release THEN 'f1
  657.         n01flag = 0
  658.         LINE (4, 346)-(40, 434), WhtOff&, BF
  659.         LINE (4, 434)-(63, 515), WhtOff&, BF
  660.     END IF
  661.  
  662. IF n02flag = 1 THEN
  663.     IF TIMER - n02timer > release THEN '
  664.         n02timer = 0: LINE (44, 348)-(76, 429), BlkOff&, BF
  665.     END IF
  666.  
  667. IF n03flag = 1 THEN
  668.     IF TIMER - n03timer > release THEN '
  669.         n03timer = 0
  670.         LINE (81, 346)-(109, 434), WhtOff&, BF
  671.         LINE (68, 434)-(127, 515), WhtOff&, BF
  672.     END IF
  673.  
  674. IF n04flag = 1 THEN
  675.     IF TIMER - n04timer > release THEN '
  676.         n04timer = 0: LINE (113, 348)-(146, 429), BlkOff&, BF
  677.     END IF
  678.  
  679. IF n05flag = 1 THEN
  680.     IF TIMER - n05timer > release THEN '
  681.         n05timer = 0
  682.         LINE (150, 346)-(178, 434), WhtOff&, BF
  683.         LINE (132, 434)-(191, 515), WhtOff&, BF
  684.     END IF
  685.  
  686. IF n06flag = 1 THEN
  687.     IF TIMER - n06timer > release THEN '
  688.         n06timer = 0: LINE (183, 348)-(214, 429), BlkOff&, BF
  689.     END IF
  690.  
  691. IF n07flag = 1 THEN
  692.     IF TIMER - n07timer > release THEN '
  693.         n07timer = 0
  694.         LINE (219, 346)-(255, 434), WhtOff&, BF
  695.         LINE (196, 434)-(255, 515), WhtOff&, BF
  696.     END IF
  697.  
  698. IF n08flag = 1 THEN
  699.     IF TIMER - n08timer > release THEN '
  700.         n08timer = 0
  701.         LINE (260, 346)-(295, 434), WhtOff&, BF
  702.         LINE (260, 434)-(319, 515), WhtOff&, BF
  703.     END IF
  704.  
  705. IF n09flag = 1 THEN
  706.     IF TIMER - n09timer > release THEN '
  707.         n09timer = 0: LINE (300, 348)-(332, 429), BlkOff&, BF
  708.     END IF
  709.  
  710. IF n10flag = 1 THEN
  711.     IF TIMER - n10timer > release THEN '
  712.         n10timer = 0
  713.         LINE (337, 346)-(370, 434), WhtOff&, BF
  714.         LINE (324, 434)-(383, 515), WhtOff&, BF
  715.     END IF
  716.  
  717. IF n11flag = 1 THEN
  718.     IF TIMER - n11timer > release THEN '
  719.         n11timer = 0: LINE (375, 348)-(406, 429), BlkOff&, BF
  720.     END IF
  721.  
  722. IF n12flag = 1 THEN
  723.     IF TIMER - n12timer > release THEN '
  724.         n12timer = 0
  725.         LINE (411, 346)-(447, 434), WhtOff&, BF
  726.         LINE (387, 434)-(447, 515), WhtOff&, BF
  727.     END IF
  728.  
  729. IF n13flag = 1 THEN
  730.     IF TIMER - n13timer > release THEN '
  731.         n13timer = 0
  732.         LINE (451, 346)-(487, 434), WhtOff&, BF
  733.         LINE (451, 434)-(511, 515), WhtOff&, BF
  734.     END IF
  735.  
  736. IF n14flag = 1 THEN
  737.     IF TIMER - n14timer > release THEN '
  738.         n14timer = 0: LINE (492, 348)-(523, 429), BlkOff&, BF
  739.     END IF
  740.  
  741. IF n15flag = 1 THEN
  742.     IF TIMER - n15timer > release THEN '
  743.         n15timer = 0
  744.         LINE (528, 346)-(556, 434), WhtOff&, BF
  745.         LINE (515, 434)-(575, 515), WhtOff&, BF
  746.     END IF
  747.  
  748. IF n16flag = 1 THEN
  749.     IF TIMER - n16timer > release THEN '
  750.         n16timer = 0: LINE (560, 348)-(593, 429), BlkOff&, BF
  751.     END IF
  752.  
  753. IF n17flag = 1 THEN
  754.     IF TIMER - n17timer > release THEN '
  755.         n17timer = 0
  756.         LINE (598, 346)-(625, 434), WhtOff&, BF
  757.         LINE (579, 434)-(639, 515), WhtOff&, BF
  758.     END IF
  759.  
  760. IF n18flag = 1 THEN
  761.     IF TIMER - n18timer > release THEN '
  762.         n18timer = 0: LINE (630, 348)-(663, 429), BlkOff&, BF
  763.     END IF
  764.  
  765. IF n19flag = 1 THEN
  766.     IF TIMER - n19timer > release THEN '
  767.         n19timer = 0
  768.         LINE (667, 346)-(702, 434), WhtOff&, BF
  769.         LINE (643, 434)-(702, 515), WhtOff&, BF
  770.     END IF
  771.  
  772. IF n20flag = 1 THEN
  773.     IF TIMER - n20timer > release THEN '
  774.         n20timer = 0
  775.         LINE (707, 346)-(743, 434), WhtOff&, BF
  776.         LINE (707, 434)-(766, 515), WhtOff&, BF
  777.     END IF
  778.  
  779. IF n21flag = 1 THEN
  780.     IF TIMER - n21timer > release THEN '
  781.         n21timer = 0: LINE (747, 348)-(779, 429), BlkOff&, BF
  782.     END IF
  783.  
  784. IF n22flag = 1 THEN
  785.     IF TIMER - n22timer > release THEN '
  786.         n22timer = 0
  787.         LINE (784, 346)-(817, 434), WhtOff&, BF
  788.         LINE (771, 434)-(830, 515), WhtOff&, BF
  789.     END IF
  790.  
  791. IF n23flag = 1 THEN
  792.     IF TIMER - n23timer > release THEN '
  793.         n23timer = 0: LINE (822, 348)-(854, 429), BlkOff&, BF
  794.     END IF
  795.  
  796. IF n24flag = 1 THEN
  797.     IF TIMER - n24timer > release THEN '
  798.         n24timer = 0
  799.         LINE (858, 346)-(894, 434), WhtOff&, BF
  800.         LINE (835, 434)-(894, 515), WhtOff&, BF
  801.     END IF
  802.  
  803. IF n25flag = 1 THEN
  804.     IF TIMER - n25timer > release THEN '
  805.         n25timer = 0
  806.         LINE (5, 123)-(41, 210), WhtOff&, BF
  807.         LINE (5, 211)-(64, 292), WhtOff&, BF
  808.     END IF
  809.  
  810. IF n26flag = 1 THEN
  811.     IF TIMER - n26timer > release THEN '
  812.         n26timer = 0: LINE (45, 125)-(78, 207), BlkOff&, BF
  813.     END IF
  814.  
  815. IF n27flag = 1 THEN
  816.     IF TIMER - n27timer > release THEN '
  817.         n27timer = 0
  818.         LINE (82, 123)-(110, 210), WhtOff&, BF
  819.         LINE (69, 211)-(128, 292), WhtOff&, BF
  820.     END IF
  821.  
  822. IF n28flag = 1 THEN
  823.     IF TIMER - n28timer > release THEN '
  824.         n28timer = 0: LINE (114, 125)-(147, 207), BlkOff&, BF
  825.     END IF
  826.  
  827. IF n29flag = 1 THEN
  828.     IF TIMER - n29timer > release THEN '
  829.         n29timer = 0
  830.         LINE (151, 123)-(179, 210), WhtOff&, BF
  831.         LINE (133, 211)-(192, 292), WhtOff&, BF
  832.     END IF
  833.  
  834. IF n30flag = 1 THEN
  835.     IF TIMER - n30timer > release THEN '
  836.         n30timer = 0: LINE (184, 125)-(215, 207), BlkOff&, BF
  837.     END IF
  838.  
  839. IF n31flag = 1 THEN
  840.     IF TIMER - n31timer > release THEN '
  841.         n31timer = 0
  842.         LINE (220, 123)-(256, 210), WhtOff&, BF
  843.         LINE (197, 211)-(256, 292), WhtOff&, BF
  844.     END IF
  845.  
  846. IF n32flag = 1 THEN
  847.     IF TIMER - n32timer > release THEN '
  848.         n32timer = 0
  849.         LINE (261, 123)-(296, 210), WhtOff&, BF
  850.         LINE (261, 211)-(320, 292), WhtOff&, BF
  851.     END IF
  852.  
  853. IF n33flag = 1 THEN
  854.     IF TIMER - n33timer > release THEN '
  855.         n33timer = 0: LINE (301, 125)-(332, 207), BlkOff&, BF
  856.     END IF
  857.  
  858. IF n34flag = 1 THEN
  859.     IF TIMER - n34timer > release THEN '
  860.         n34timer = 0
  861.         LINE (338, 123)-(371, 210), WhtOff&, BF
  862.         LINE (325, 211)-(384, 292), WhtOff&, BF
  863.     END IF
  864.  
  865. IF n35flag = 1 THEN
  866.     IF TIMER - n35timer > release THEN '
  867.         n35timer = 0: LINE (376, 125)-(407, 207), BlkOff&, BF
  868.     END IF
  869.  
  870. IF n36flag = 1 THEN
  871.     IF TIMER - n36timer > release THEN '
  872.         n36timer = 0
  873.         LINE (412, 123)-(448, 210), WhtOff&, BF
  874.         LINE (388, 211)-(448, 292), WhtOff&, BF
  875.     END IF
  876.  
  877. IF n37flag = 1 THEN
  878.     IF TIMER - n37timer > release THEN '
  879.         n37timer = 0
  880.         LINE (452, 123)-(488, 210), WhtOff&, BF
  881.         LINE (452, 211)-(512, 292), WhtOff&, BF
  882.     END IF
  883.  
  884. IF n38flag = 1 THEN
  885.     IF TIMER - n38timer > release THEN '
  886.         n38timer = 0: LINE (493, 125)-(525, 207), BlkOff&, BF
  887.     END IF
  888.  
  889. IF n39flag = 1 THEN
  890.     IF TIMER - n39timer > release THEN '
  891.         n39timer = 0
  892.         LINE (529, 123)-(557, 210), WhtOff&, BF
  893.         LINE (516, 211)-(576, 292), WhtOff&, BF
  894.     END IF
  895.  
  896. IF n40flag = 1 THEN
  897.     IF TIMER - n40timer > release THEN '
  898.         n40timer = 0: LINE (561, 125)-(594, 207), BlkOff&, BF
  899.     END IF
  900.  
  901. IF n41flag = 1 THEN
  902.     IF TIMER - n41timer > release THEN '
  903.         n41timer = 0
  904.         LINE (599, 123)-(626, 210), WhtOff&, BF
  905.         LINE (580, 211)-(640, 292), WhtOff&, BF
  906.     END IF
  907.  
  908. IF n42flag = 1 THEN
  909.     IF TIMER - n42timer > release THEN '
  910.         n42timer = 0: LINE (631, 125)-(664, 207), BlkOff&, BF
  911.     END IF
  912.  
  913. IF n43flag = 1 THEN
  914.     IF TIMER - n43timer > release THEN '
  915.         n43timer = 0
  916.         LINE (668, 123)-(703, 210), WhtOff&, BF
  917.         LINE (644, 211)-(703, 292), WhtOff&, BF
  918.     END IF
  919.  
  920. IF n44flag = 1 THEN
  921.     IF TIMER - n44timer > release THEN '
  922.         n44timer = 0
  923.         LINE (708, 123)-(744, 210), WhtOff&, BF
  924.         LINE (708, 211)-(767, 292), WhtOff&, BF
  925.     END IF
  926.  
  927. IF n45flag = 1 THEN
  928.     IF TIMER - n45timer > release THEN '
  929.         n45timer = 0: LINE (748, 125)-(780, 207), BlkOff&, BF
  930.     END IF
  931.  
  932. IF n46flag = 1 THEN
  933.     IF TIMER - n46timer > release THEN '
  934.         n46timer = 0
  935.         LINE (785, 123)-(818, 210), WhtOff&, BF
  936.         LINE (772, 211)-(831, 292), WhtOff&, BF
  937.     END IF
  938.  
  939. IF n47flag = 1 THEN
  940.     IF TIMER - n47timer > release THEN '
  941.         n47timer = 0: LINE (823, 125)-(855, 207), BlkOff&, BF
  942.     END IF
  943.  
  944. IF n48flag = 1 THEN
  945.     IF TIMER - n48timer > release THEN '
  946.         n48timer = 0
  947.         LINE (859, 123)-(895, 210), WhtOff&, BF
  948.         LINE (836, 211)-(895, 292), WhtOff&, BF
  949.     END IF
  950.  
  951.  
  952. '==========================================================
  953. SaveScreen: 'save current screen image
  954. '=========
  955. scr1 = _MEMIMAGE(0): scr2 = _MEMNEW(scr1.SIZE)
  956. _MEMCOPY scr1, scr1.OFFSET, scr1.SIZE TO scr2, scr2.OFFSET
  957.  
  958.  
  959. '==========================================================
  960. RestoreScreen: 'restores screen image saved
  961. '============
  962. _MEMCOPY scr2, scr2.OFFSET, scr2.SIZE TO scr1, scr1.OFFSET
  963. _MEMFREE scr1: _MEMFREE scr2
  964.  
  965.  
  966. '==========================================================
  967. UpdateInfo: 'clears area and sets info at the top left
  968. '=============
  969. COLOR _RGB(163, 163, 175), _RGB(70, 95, 114)
  970. LOCATE 1, 1: PRINT SPACE$(32);
  971. LOCATE 2, 1: PRINT SPACE$(32);
  972. IF song$ = "" THEN
  973.     LOCATE 2, 3: PRINT " Song: (none)"
  974.     LOCATE 2, 3: PRINT " Song: "; UCASE$(song$);
  975. LOCATE 3, 3: PRINT " Speed ="; speed; "   ";
  976.  
  977.  
  978. '==========================================================
  979.  
  980. SUB DoNote (keynum)
  981.     'Plays the note$ sound, sets playing flag
  982.     SELECT CASE keynum
  983.         CASE 1: _SNDPLAYCOPY n01&
  984.             n01flag = 1: n01timer = TIMER
  985.             LINE (4, 346)-(40, 434), WhtOn&, BF
  986.             LINE (4, 434)-(63, 515), WhtOn&, BF
  987.         CASE 2: _SNDPLAYCOPY n02&
  988.             n02flag = 1: n02timer = TIMER
  989.             LINE (44, 348)-(76, 429), BlkOn&, BF
  990.         CASE 3: _SNDPLAYCOPY n03&
  991.             n03flag = 1: n03timer = TIMER
  992.             LINE (81, 346)-(109, 434), WhtOn&, BF
  993.             LINE (68, 434)-(127, 515), WhtOn&, BF
  994.         CASE 4: _SNDPLAYCOPY n04&
  995.             n04flag = 1: n04timer = TIMER
  996.             LINE (113, 348)-(146, 429), BlkOn&, BF
  997.         CASE 5: _SNDPLAYCOPY n05&
  998.             n05flag = 1: n05timer = TIMER:
  999.             LINE (150, 346)-(178, 434), WhtOn&, BF
  1000.             LINE (132, 434)-(191, 515), WhtOn&, BF
  1001.         CASE 6: _SNDPLAYCOPY n06&
  1002.             n06flag = 1: n06timer = TIMER
  1003.             LINE (183, 348)-(214, 429), BlkOn&, BF
  1004.         CASE 7: _SNDPLAYCOPY n07&
  1005.             n07flag = 1: n07timer = TIMER
  1006.             LINE (219, 346)-(255, 434), WhtOn&, BF
  1007.             LINE (196, 434)-(255, 515), WhtOn&, BF
  1008.         CASE 8: _SNDPLAYCOPY n08&
  1009.             n08flag = 1: n08timer = TIMER
  1010.             LINE (260, 346)-(295, 434), WhtOn&, BF
  1011.             LINE (260, 434)-(319, 515), WhtOn&, BF
  1012.         CASE 9: _SNDPLAYCOPY n09&
  1013.             n09flag = 1: n09timer = TIMER
  1014.             LINE (300, 348)-(332, 429), BlkOn&, BF
  1015.         CASE 10: _SNDPLAYCOPY n10&
  1016.             n10flag = 1: n10timer = TIMER
  1017.             LINE (337, 346)-(370, 434), WhtOn&, BF
  1018.             LINE (324, 434)-(383, 515), WhtOn&, BF
  1019.         CASE 11: _SNDPLAYCOPY n11&
  1020.             n11flag = 1: n11timer = TIMER
  1021.             LINE (375, 348)-(406, 429), BlkOn&, BF
  1022.         CASE 12: _SNDPLAYCOPY n12&
  1023.             n12flag = 1: n12timer = TIMER
  1024.             LINE (411, 346)-(447, 434), WhtOn&, BF
  1025.             LINE (387, 434)-(447, 515), WhtOn&, BF
  1026.         CASE 13: _SNDPLAYCOPY n13&
  1027.             n13flag = 1: n13timer = TIMER
  1028.             LINE (451, 346)-(487, 434), WhtOn&, BF
  1029.             LINE (451, 434)-(511, 515), WhtOn&, BF
  1030.         CASE 14: _SNDPLAYCOPY n14&
  1031.             n14flag = 1: n14timer = TIMER
  1032.             LINE (492, 348)-(523, 429), BlkOn&, BF
  1033.         CASE 15: _SNDPLAYCOPY n15&
  1034.             n15flag = 1: n15timer = TIMER
  1035.             LINE (528, 346)-(556, 434), WhtOn&, BF
  1036.             LINE (515, 434)-(575, 515), WhtOn&, BF
  1037.         CASE 16: _SNDPLAYCOPY n16&
  1038.             n16flag = 1: n16timer = TIMER
  1039.             LINE (560, 348)-(593, 429), BlkOn&, BF
  1040.         CASE 17: _SNDPLAYCOPY n17&
  1041.             n17flag = 1: n17timer = TIMER
  1042.             LINE (598, 346)-(625, 434), WhtOn&, BF
  1043.             LINE (579, 434)-(639, 515), WhtOn&, BF
  1044.         CASE 18: _SNDPLAYCOPY n18&
  1045.             n18flag = 1: n18timer = TIMER
  1046.             LINE (630, 348)-(663, 429), BlkOn&, BF
  1047.         CASE 19: _SNDPLAYCOPY n19&
  1048.             n19flag = 1: n19timer = TIMER
  1049.             LINE (667, 346)-(702, 434), WhtOn&, BF
  1050.             LINE (643, 434)-(702, 515), WhtOn&, BF
  1051.         CASE 20: _SNDPLAYCOPY n20&
  1052.             n20flag = 1: n20timer = TIMER
  1053.             LINE (707, 346)-(743, 434), WhtOn&, BF
  1054.             LINE (707, 434)-(766, 515), WhtOn&, BF
  1055.         CASE 21: _SNDPLAYCOPY n21&
  1056.             n21flag = 1: n21timer = TIMER
  1057.             LINE (747, 348)-(779, 429), BlkOn&, BF
  1058.         CASE 22: _SNDPLAYCOPY n22&
  1059.             n22flag = 1: n22timer = TIMER
  1060.             LINE (784, 346)-(817, 434), WhtOn&, BF
  1061.             LINE (771, 434)-(830, 515), WhtOn&, BF
  1062.         CASE 23: _SNDPLAYCOPY n23&
  1063.             n23flag = 1: n23timer = TIMER
  1064.             LINE (822, 348)-(854, 429), BlkOn&, BF
  1065.         CASE 24: _SNDPLAYCOPY n24&
  1066.             n24flag = 1: n24timer = TIMER
  1067.             LINE (858, 346)-(894, 434), WhtOn&, BF
  1068.             LINE (835, 434)-(894, 515), WhtOn&, BF
  1069.         CASE 25: _SNDPLAYCOPY n25&
  1070.             n25flag = 1: n25timer = TIMER
  1071.             LINE (5, 123)-(41, 210), WhtOn&, BF
  1072.             LINE (5, 211)-(64, 292), WhtOn&, BF
  1073.         CASE 26: _SNDPLAYCOPY n26&
  1074.             n26flag = 1: n26timer = TIMER
  1075.             LINE (45, 125)-(78, 207), BlkOn&, BF
  1076.         CASE 27: _SNDPLAYCOPY n27&
  1077.             n27flag = 1: n27timer = TIMER
  1078.             LINE (82, 123)-(110, 210), WhtOn&, BF
  1079.             LINE (69, 211)-(128, 292), WhtOn&, BF
  1080.         CASE 28: _SNDPLAYCOPY n28&
  1081.             n28flag = 1: n28timer = TIMER
  1082.             LINE (114, 125)-(147, 207), BlkOn&, BF
  1083.         CASE 29: _SNDPLAYCOPY n29&
  1084.             n29flag = 1: n29timer = TIMER
  1085.             LINE (151, 123)-(179, 210), WhtOn&, BF
  1086.             LINE (133, 211)-(192, 292), WhtOn&, BF
  1087.         CASE 30: _SNDPLAYCOPY n30&
  1088.             n30flag = 1: n30timer = TIMER
  1089.             LINE (184, 125)-(215, 207), BlkOn&, BF
  1090.         CASE 31: _SNDPLAYCOPY n31&
  1091.             n31flag = 1: n31timer = TIMER
  1092.             LINE (220, 123)-(256, 210), WhtOn&, BF
  1093.             LINE (197, 211)-(256, 292), WhtOn&, BF
  1094.         CASE 32: _SNDPLAYCOPY n32&
  1095.             n32flag = 1: n32timer = TIMER
  1096.             LINE (261, 123)-(296, 210), WhtOn&, BF
  1097.             LINE (261, 211)-(320, 292), WhtOn&, BF
  1098.         CASE 33: _SNDPLAYCOPY n33&
  1099.             n33flag = 1: n33timer = TIMER
  1100.             LINE (301, 125)-(332, 207), BlkOn&, BF
  1101.         CASE 34: _SNDPLAYCOPY n34&
  1102.             n34flag = 1: n34timer = TIMER
  1103.             LINE (338, 123)-(371, 210), WhtOn&, BF
  1104.             LINE (325, 211)-(384, 292), WhtOn&, BF
  1105.         CASE 35: _SNDPLAYCOPY n35&
  1106.             n35flag = 1: n35timer = TIMER
  1107.             LINE (376, 125)-(407, 207), BlkOn&, BF
  1108.         CASE 36: _SNDPLAYCOPY n36&
  1109.             n36flag = 1: n36timer = TIMER
  1110.             LINE (412, 123)-(448, 210), WhtOn&, BF
  1111.             LINE (388, 211)-(448, 292), WhtOn&, BF
  1112.         CASE 37: _SNDPLAYCOPY n37&
  1113.             n37flag = 1: n37timer = TIMER
  1114.             LINE (452, 123)-(488, 210), WhtOn&, BF
  1115.             LINE (452, 211)-(512, 292), WhtOn&, BF
  1116.         CASE 38: _SNDPLAYCOPY n38&
  1117.             n38flag = 1: n38timer = TIMER
  1118.             LINE (493, 125)-(525, 207), BlkOn&, BF
  1119.         CASE 39: _SNDPLAYCOPY n39&
  1120.             n39flag = 1: n39timer = TIMER
  1121.             LINE (529, 123)-(557, 210), WhtOn&, BF
  1122.             LINE (516, 211)-(576, 292), WhtOn&, BF
  1123.         CASE 40: _SNDPLAYCOPY n40&
  1124.             n40flag = 1: n40timer = TIMER
  1125.             LINE (561, 125)-(594, 207), BlkOn&, BF
  1126.         CASE 41: _SNDPLAYCOPY n41&
  1127.             n41flag = 1: n41timer = TIMER
  1128.             LINE (599, 123)-(626, 210), WhtOn&, BF
  1129.             LINE (580, 211)-(640, 292), WhtOn&, BF
  1130.         CASE 42: _SNDPLAYCOPY n42&
  1131.             n42flag = 1: n42timer = TIMER
  1132.             LINE (632, 125)-(664, 207), BlkOn&, BF
  1133.         CASE 43: _SNDPLAYCOPY n43&
  1134.             n43flag = 1: n43timer = TIMER
  1135.             LINE (668, 123)-(703, 210), WhtOn&, BF
  1136.             LINE (644, 211)-(703, 292), WhtOn&, BF
  1137.         CASE 44: _SNDPLAYCOPY n44&
  1138.             n44flag = 1: n44timer = TIMER
  1139.             LINE (708, 123)-(744, 210), WhtOn&, BF
  1140.             LINE (708, 211)-(767, 292), WhtOn&, BF
  1141.         CASE 45: _SNDPLAYCOPY n45&
  1142.             n45flag = 1: n45timer = TIMER
  1143.             LINE (748, 125)-(780, 207), BlkOn&, BF
  1144.         CASE 46: _SNDPLAYCOPY n46&
  1145.             n46flag = 1: n46timer = TIMER
  1146.             LINE (785, 123)-(818, 210), WhtOn&, BF
  1147.             LINE (772, 211)-(831, 292), WhtOn&, BF
  1148.         CASE 47: _SNDPLAYCOPY n47&
  1149.             n47flag = 1: n47timer = TIMER
  1150.             LINE (823, 125)-(855, 207), BlkOn&, BF
  1151.         CASE 48: _SNDPLAYCOPY n48&
  1152.             n48flag = 1: n48timer = TIMER
  1153.             LINE (859, 123)-(895, 210), WhtOn&, BF
  1154.             LINE (836, 211)-(895, 292), WhtOn&, BF
  1155.  
  1156.     END SELECT
  1157.  
  1158.  
  1159. '=======================================================
  1160.  
  1161. SUB DrawBox 'Draws the litte info box.  Used often
  1162.     LINE (250, 200)-(650, 270), _RGB(70, 95, 114), BF
  1163.     LINE (252, 202)-(648, 268), _RGB(255, 255, 255), B
  1164.     COLOR _RGB(255, 255, 255), _RGB(70, 95, 114)
  1165.  

 
keys48.jpg
* keys48-v10.zip (Filesize: 623.73 KB, Downloads: 124)
« Last Edit: January 18, 2021, 03:50:51 pm by Dav »

Offline SpriggsySpriggs

  • Forum Resident
  • Posts: 1145
  • Larger than life
    • View Profile
    • GitHub
Re: Keys48 - Playable/Recordable instrument program
« Reply #1 on: January 18, 2021, 02:50:48 pm »
Wow! That screenshot looks beautiful as does the source code. I'll be sure to give this a try on my home PC.
Shuwatch!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Keys48 - Playable/Recordable instrument program
« Reply #2 on: January 18, 2021, 03:14:22 pm »
Yes nice, the way it holds notes seems natural.

Be nice to do several keys/notes at once, time to invent 5 fingered mice or just transform the keyboard.

Not an .ogg in sight! File Explorer has no problem with compressed files.

Offline SierraKen

  • Forum Resident
  • Posts: 1454
    • View Profile
Re: Keys48 - Playable/Recordable instrument program
« Reply #3 on: January 18, 2021, 03:25:16 pm »
I wonder if you can add a beat sound to it for the background. Lots of possible potential! But this is really cool.

Offline SierraKen

  • Forum Resident
  • Posts: 1454
    • View Profile
Re: Keys48 - Playable/Recordable instrument program
« Reply #4 on: January 18, 2021, 03:34:57 pm »
I just tried it out... incredible job! You might want to add the ability to drag the mouse with the left mouse button down to be able to slide the piano keys down at one time. Awesome job also on your 3 songs! I have no idea how you made your .key files. :)

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Keys48 - Playable/Recordable instrument program
« Reply #5 on: January 18, 2021, 03:55:04 pm »
Thanks, guys!  It was fun to make.  My wife is glad this is completed, lol.

I just updated the code - I had left out a BF on the LINE statement, which made note 21 look sticky.  You can fix your code without re-downloading - at line# 815, change it to a BF on the end, not a B:

 n21timer = 0: LINE (747, 348)-(779, 429), BlkOff&, BF

I updated the posted code and .zip with the fix.

That's a good idea, @SierraKen - I was thinking on how to do that, maybe press Shift and the mouse will drag over the notes.

- Dav

« Last Edit: January 18, 2021, 03:57:29 pm by Dav »

Offline SierraKen

  • Forum Resident
  • Posts: 1454
    • View Profile
Re: Keys48 - Playable/Recordable instrument program
« Reply #6 on: January 18, 2021, 04:22:30 pm »
It's line #817 on mine, but I fixed it. :)

This code example I just found on the Wiki might help you Dav. I was also thinking that it would be really cool if you could change the piano so the note it plays could keep going in length the longer you hold down the left mouse button.

Example 2: How to monitor when a button is down or wait until a mouse button is not held down.
Code: QB64: [Select]
  1. PRINT "Hold down the left mouse button until you want to quit!"
  2.     i = _MOUSEINPUT ' read #1
  3.     IF _MOUSEBUTTON(1) THEN PRINT "Left button down!": EXIT DO
  4. DO '                                                      need to wait
  5.     i = _MOUSEINPUT '  read #2                         until the mouse
  6. LOOP UNTIL NOT _MOUSEBUTTON(1) '                       button is released
  7.  
  8. PRINT "DONE!"  
  9.  
  10.  

From here: https://qb64.org/wiki/MOUSEBUTTON

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Keys48 - Playable/Recordable instrument program
« Reply #7 on: January 18, 2021, 05:17:35 pm »
Thanks, @SierraKen. I'll play around with it.  i've always been a little clumsy with mouse programming. I think i need to work in some aftertouch code, and figure out how to keep the notes playing. 

- Dav

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Keys48 - Playable/Recordable instrument program
« Reply #8 on: January 18, 2021, 05:22:11 pm »
@Dav   This is really a very nicely done program! I like it!

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: Keys48 - Playable/Recordable instrument program
« Reply #9 on: January 18, 2021, 07:06:24 pm »
That's one that reminds of my college daze. I took a course in assembly programming and the main grade project was to produce a keyboard that played notes. I never got mine to work and the grade reflected that fact. That was my only brush with assembly.

Offline SierraKen

  • Forum Resident
  • Posts: 1454
    • View Profile
Re: Keys48 - Playable/Recordable instrument program
« Reply #10 on: January 18, 2021, 10:24:41 pm »
Dav, I tried that code I posted for you and added the SOUND command and also the PLAY command, and couldn't get the timing right myself. So no worries if you can't get it. I know the Sound Card and BASIC has always been 2 different things. But I really like what you got already!

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Keys48 - Playable/Recordable instrument program
« Reply #11 on: January 19, 2021, 07:57:22 pm »
Thanks, @Petr. This was fun to make!

@OldMoses, that sound like a tough first project for assembly.  I would have loved to taken a course in programming in school.   I tried enrolling one year, but was denied taking any kind of computer classes at all.  I didnt have any of the math classes required.  They did me a favor saying no - could have ruined all the fun Ive had learning it on my own.

@SierraKen, i think Ive got the mouse thing worked out, but I need to resample the key  sounds - I'm thinking every key will need two sounds, one to play a long, and when the key is released, the  fade out note sound will take over. 

- Dav

Offline SierraKen

  • Forum Resident
  • Posts: 1454
    • View Profile
Re: Keys48 - Playable/Recordable instrument program
« Reply #12 on: January 20, 2021, 12:04:47 am »
Incredible Dav! No rush of course :)

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Keys48 - Playable/Recordable instrument program
« Reply #13 on: January 20, 2021, 12:44:53 am »
Dav,

Please excuse my apparent ignorance... Your sample playbacks 'seem' to be polyphonic, how else, except for a tablet-type device or instrument keyboard input, can a single mouse pointer be hopeful of recreating such examples? I am not complaining. Just curious.

By the way... very nicely done....

J
Logic is the beginning of wisdom.

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Keys48 - Playable/Recordable instrument program
« Reply #14 on: January 20, 2021, 06:38:14 am »
@johnno56: By overdubbing you can add layers of more notes.  Record some notes, then do record again adding more notes on top of that first recording, add so on.  They are merged.  It is tedious, but with one layer at a time you can end up with some complex stuff.

The example songs i recorded at a slow speed, around 50, then when finished i raised it up. I didn't finish the Dav.k48 song, my finger got tired of clicking...

- Dav
« Last Edit: January 20, 2021, 06:48:45 am by Dav »