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

0 Members and 1 Guest are viewing this topic.

Offline Junior Librarian

  • Moderator
  • Newbie
  • Posts: 19
    • View Profile
Simple Piano by Terry Ritchie
« on: September 22, 2021, 05:49:27 am »
QB64 Simple Piano

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

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

 
                                                                                                                                         (136 downloads previously)

PIANO Screenshot.png
« Last Edit: September 22, 2021, 06:29:56 am by Junior Librarian »