Author Topic: Simple Piano by Terry Ritchie  (Read 705 times)

0 Members and 1 Guest are viewing this topic.

Offline Qwerkey

  • Moderator
  • Forum Resident
  • Posts: 736
Simple Piano by Terry Ritchie
« on: May 03, 2020, 04:36:15 AM »
QB64 Simple Piano

Author: @TerryRitchie
Source: qb64.org Forum
URL: https://www.qb64.org/forum/index.php?topic=2400.msg116185#msg116185
Version: 2
Tags: [Graphics], [Music]

Description:
This is a little program I wrote back in 2014. It's a one-octave piano simulator that allows you to switch between octaves. The asset files (images and sounds) are contained in the zip file. Be sure to place the \PIANO folder in your QB64 folder and load the PIANO.bas file into the IDE.  Make sure that you have the RUN option “Output EXE to Source Folder” checked.

Directions for use are at the top of the source code listing.

Note: I wrote this using version 0.954 and because of that the sounds are loaded using options not available in the latest versions of QB64. If you compile this using an SDL version of QB64 the piano keys will stop the sound as soon as you release them. In non SDL versions of QB64 the key sustains even after released.


The thread for this project also contains variants by @Petr for saving the tunes created with this program.

Source Code:
Librarian's note: The code is given here for reference only.  Load the .bas file in the folder.
Code: QB64: [Select]
  1. '*
  2. '* QB64 Simple Piano
  3. '*
  4. '* by Terry Ritchie
  5. '*
  6. '* Demonstrates the use of external sound files to create a realistic piano.
  7. '*
  8. '* Modified 03/26/20
  9. '* Removed the need for a separate .\PIANO\ folder to hold the graphics and
  10. '* sound assets. All assets are now to be contained in the same folder as
  11. '* PIANO.EXE
  12. '*
  13. '* ESC         - exit program
  14. '* RIGHT ARROW - increase octave
  15. '* LEFT ARROW  - decrease octave
  16. '* Piano Keys  -  R T  U I O   (black keys)
  17. '*             - D F GH J K L  (white keys)
  18. '*
  19.  
  20. '--------------------------------
  21. '- Variable Declaration Section -
  22. '--------------------------------
  23.  
  24. TYPE IVORY '          key information
  25.     u AS INTEGER '    upper case value
  26.     l AS INTEGER '    lower case value
  27.     Down AS INTEGER ' key position
  28.     x AS INTEGER '    key indicator x coordinate
  29.     y AS INTEGER '    key indicator y coordinate
  30.  
  31. DIM K(12) AS IVORY '  key information array
  32. DIM Tone&(88) '       piano key sounds array
  33. DIM imgPiano& '       piano keyboard image
  34. DIM imgAoctave& '     active octave image
  35. DIM imgIoctave& '     inactive octave image
  36. DIM Octave% '         current octave
  37. DIM Khit& '           keyboard status
  38. DIM Keys% '           key cycle counter
  39.  
  40. '----------------------------
  41. '- Main Program Begins Here -
  42. '----------------------------
  43.  
  44. LOADPIANO '                                                          load piano assets
  45. SCREEN _NEWIMAGE(512, 263, 32) '                                     create default screen
  46. _TITLE "PIANO" '                                                     set window title
  47. _SCREENMOVE _MIDDLE '                                                center window on desktop
  48. _DELAY .25
  49. _PUTIMAGE (0, 0), imgPiano& '                                        show piano image
  50. SHOWOCTAVE '                                                         update octave indicator
  51. DO '                                                                 MAIN LOOP begins
  52.     Khit& = _KEYHIT '                                                get keyboard status
  53.     IF Khit& THEN '                                                  was a key hit?
  54.         IF Khit& = 19200 OR Khit& = 19712 THEN '                     yes, left or right key?
  55.             IF Khit& = 19200 THEN '                                  yes, left key?
  56.                 Octave% = Octave% - 1 '                              yes, decrease octave
  57.                 IF Octave% = -1 THEN Octave% = 0 '                   keep octave in limits
  58.             ELSE '                                                   no, must be right key
  59.                 Octave% = Octave% + 1 '                              increase octave
  60.                 IF Octave% = 5 THEN Octave% = 4 '                    keep octave in limits
  61.             END IF
  62.             SHOWOCTAVE '                                             update octave indicator
  63.         ELSEIF Khit& = 27 THEN '                                     no, escape key?
  64.             QUIT '                                                   yes, quit program
  65.         END IF
  66.     END IF
  67.     FOR Keys% = 1 TO 12 '                                            cycle through keys
  68.         IF _KEYDOWN(K(Keys%).u) OR _KEYDOWN(K(Keys%).l) THEN '       key pressed?
  69.             PRESS Keys% '                                            yes, play note
  70.         ELSE '                                                       no
  71.             RELEASE Keys% '                                          remove key indicator
  72.         END IF
  73.     NEXT Keys%
  74.     _DISPLAY '                                                       update screen changes
  75. LOOP '                                                               MAIN LOOP back
  76.  
  77. '-----------------------------------
  78. '- Function and Subroutine section -
  79. '-----------------------------------
  80.  
  81. '--------------------------------------------------------------------------------------------
  82.  
  83. SUB QUIT ()
  84.  
  85.     '*
  86.     '* Cleans RAM by removing all image and sound assets and then exits to Windows.
  87.     '*
  88.  
  89.     SHARED Tone&() '     need access to piano key sounds array
  90.     SHARED imgPiano& '   need access to piano keyboard image
  91.     SHARED imgAoctave& ' need access to active octave image
  92.     SHARED imgIoctave& ' need access to inactive octave image
  93.  
  94.     DIM Count% '         generic counter
  95.  
  96.     FOR Count% = 1 TO 88 '        cycle through all 88 sound files
  97.         _SNDCLOSE Tone&(Count%) ' remove sound file from RAM
  98.     NEXT Count%
  99.     _FREEIMAGE imgPiano& '        remove piano image from RAM
  100.     _FREEIMAGE imgAoctave& '      remove active octave image from RAM
  101.     _FREEIMAGE imgIoctave& '      remove inactive octave image from RAM
  102.     SYSTEM '                      return to Windows
  103.  
  104.  
  105. '--------------------------------------------------------------------------------------------
  106.  
  107. SUB RELEASE (k%)
  108.  
  109.     '*
  110.     '* Removes key press display and sets key as being released
  111.     '*
  112.  
  113.     SHARED K() AS IVORY ' need access to key information array
  114.  
  115.     IF K(k%).Down THEN '                                                  is key pressed?
  116.         K(k%).Down = 0 '                                                  yes, set it as released
  117.         SELECT CASE k% '                                                  which key is it?
  118.             CASE 1, 3, 5, 6, 8, 10, 12 '                                  white key
  119.                 LINE (K(k%).x, K(k%).y)-(K(k%).x + 27, K(k%).y + 27), _RGB32(255, 255, 255), BF
  120.             CASE ELSE '                                                   black key
  121.                 LINE (K(k%).x, K(k%).y)-(K(k%).x + 27, K(k%).y + 27), _RGB32(32, 32, 32), BF
  122.         END SELECT
  123.     END IF
  124.  
  125.  
  126. '--------------------------------------------------------------------------------------------
  127.  
  128. SUB PRESS (k%)
  129.  
  130.     '*
  131.     '* Applies key press display and sets key as being pressed
  132.     '*
  133.  
  134.     SHARED K() AS IVORY ' need access to key information array
  135.     SHARED Tone&() '      need access to piano key sounds array
  136.     SHARED Octave% '      need access to current octave
  137.  
  138.     IF NOT K(k%).Down THEN '                                               is key released?
  139.         K(k%).Down = -1 '                                                  yes, set it as pressed
  140.         _SNDPLAY Tone&(Octave% * 12 + k%) '                                play tone for key
  141.         SELECT CASE k% '                                                   which key is it?
  142.             CASE 1, 3, 5, 6, 8, 10, 12 '                                   white key
  143.                 LINE (K(k%).x, K(k%).y)-(K(k%).x + 27, K(k%).y + 27), _RGB32(0, 0, 0), BF
  144.             CASE ELSE '                                                    black key
  145.                 LINE (K(k%).x, K(k%).y)-(K(k%).x + 27, K(k%).y + 27), _RGB32(255, 255, 255), BF
  146.         END SELECT
  147.     END IF
  148.  
  149.  
  150. '--------------------------------------------------------------------------------------------
  151.  
  152. SUB SHOWOCTAVE
  153.  
  154.     '*
  155.     '* Updates the small top piano keyboard to show current active octave
  156.     '*
  157.  
  158.     SHARED Octave% '     need access to current octave
  159.     SHARED imgAoctave& ' need access to active octave image
  160.     SHARED imgIoctave& ' need access to inactive octave image
  161.  
  162.     DIM Count% '         generic counter
  163.  
  164.     FOR Count% = 0 TO 4 '                                    cycle through octaves
  165.         IF Count% = Octave% THEN '                           current octave?
  166.             _PUTIMAGE (96 + (Count% * 64), 0), imgAoctave& ' yes, place active octave image
  167.         ELSE '                                               no
  168.             _PUTIMAGE (96 + (Count% * 64), 0), imgIoctave& ' place inactive octave image
  169.         END IF
  170.     NEXT Count%
  171.  
  172.  
  173. '--------------------------------------------------------------------------------------------
  174.  
  175. SUB LOADPIANO ()
  176.  
  177.     '*
  178.     '* Loads the piano sounds and images and initializes variables
  179.     '*
  180.  
  181.     SHARED K() AS IVORY ' need access to key information array
  182.     SHARED Tone&() '      need access to piano key sounds array
  183.     SHARED imgPiano& '    need access to piano keyboard image
  184.     SHARED imgAoctave& '  need access to active octave image
  185.     SHARED imgIoctave& '  need access to inactive octave image
  186.     SHARED Octave% '      need access to current octave
  187.  
  188.     DIM Note% '           counter used to open sounds
  189.     DIM Count% '          counter used to close sounds if error
  190.     DIM File$ '           sound file names
  191.  
  192.     FOR Note% = 1 TO 88 '                                          cycle through notes
  193.         File$ = LTRIM$(STR$(Note%)) + ".ogg" '                     construct file name
  194.         IF _FILEEXISTS(File$) THEN '                               sound file exist?
  195.             Tone&(Note%) = _SNDOPEN(File$, "VOL,SYNC,LEN,PAUSE") ' yes, load sound file
  196.         ELSE '                                                     no, sound file missing
  197.             PRINT '                                                report error to user
  198.             PRINT " ERROR: Sound file "; File$; " is missing."
  199.             IF Note% > 1 THEN '                                    did any sounds load?
  200.                 FOR Count% = Note% TO 1 STEP -1 '                  yes, cycle notes backwards
  201.                     _SNDCLOSE Tone&(Count%) '                      remove sound from RAM
  202.                 NEXT Count%
  203.                 END '                                              end program
  204.             END IF
  205.         END IF
  206.     NEXT Note%
  207.     IF _FILEEXISTS("piano.png") THEN '                             image file exist?
  208.         imgPiano& = _LOADIMAGE("piano.png", 32) '                  yes, load image file
  209.     ELSE '                                                         no, image file missing
  210.         PRINT '                                                    report error to user
  211.         PRINT " ERROR: piano.png missing."
  212.         END '                                                      end program
  213.     END IF
  214.     IF _FILEEXISTS("active.png") THEN '                            image file exist?
  215.         imgAoctave& = _LOADIMAGE("active.png", 32) '               yes, load image file
  216.     ELSE '                                                         no, image file missing
  217.         PRINT '                                                    report error to user
  218.         PRINT " ERROR: active.png missing."
  219.         _FREEIMAGE imgPiano& '                                     remove image from RAM
  220.         END '                                                      end program
  221.     END IF
  222.     IF _FILEEXISTS(Path$ + "inactive.png") THEN '                  image file exist?
  223.         imgIoctave& = _LOADIMAGE("inactive.png", 32) '             yes, load image file
  224.     ELSE '                                                         no, image file missing
  225.         PRINT '                                                    report error to user
  226.         PRINT " ERROR: inactive.png missing."
  227.         _FREEIMAGE imgPiano& '                                     remove image from RAM
  228.         _FREEIMAGE imgAoctave& '                                   remove image from RAM
  229.         END '                                                      end program
  230.     END IF
  231.  
  232.     K(1).x = 22: K(1).y = 212: K(2).x = 60: K(2).y = 132 '         set indicator coordinates
  233.     K(3).x = 95: K(3).y = 212: K(4).x = 134: K(4).y = 132
  234.     K(5).x = 168: K(5).y = 212: K(6).x = 241: K(6).y = 212
  235.     K(7).x = 278: K(7).y = 132: K(8).x = 314: K(8).y = 212
  236.     K(9).x = 353: K(9).y = 132: K(10).x = 387: K(10).y = 212
  237.     K(11).x = 428: K(11).y = 132: K(12).x = 460: K(12).y = 212
  238.     K(1).l = 100: K(1).u = 68: K(2).l = 114: K(2).u = 82 '         set key case values
  239.     K(3).l = 102: K(3).u = 70: K(4).l = 116: K(4).u = 84
  240.     K(5).l = 103: K(5).u = 71: K(6).l = 104: K(6).u = 72
  241.     K(7).l = 117: K(7).u = 85: K(8).l = 106: K(8).u = 74
  242.     K(9).l = 105: K(9).u = 73: K(10).l = 107: K(10).u = 75
  243.     K(11).l = 111: K(11).u = 79: K(12).l = 108: K(12).u = 76
  244.     Octave% = 2 '                                                  set initial octave
  245.  
  246.  
  247. '--------------------------------------------------------------------------------------------
  248.