Author Topic: Simple Piano  (Read 8593 times)

0 Members and 1 Guest are viewing this topic.

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Simple Piano
« on: March 25, 2020, 02:25:21 pm »
I was going through my QB64 tutorials and forget about this 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 attached PIANO.zip file. Be sure to place the \PIANO folder in your QB64 folder (the programs looks for the .\PIANO\ folder when loading assets.

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.

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

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Simple Piano
« Reply #1 on: March 25, 2020, 05:19:50 pm »
Hi, i like this nice program!

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Simple Piano
« Reply #2 on: March 25, 2020, 06:43:50 pm »
Hi Terry
I remember this your application about sounds chapter!
Fine!
Programming isn't difficult, only it's  consuming time and coffee

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Simple Piano
« Reply #3 on: March 25, 2020, 07:32:55 pm »
Nicely done! Slight modification to PATH (Linux user), but other than that, works quite well. Thank you!
Logic is the beginning of wisdom.

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Simple Piano
« Reply #4 on: March 26, 2020, 12:15:03 am »
Thanks everyone :-)

Johnno, what did you need to change? I need to start taking note of the Linux differences. I'm thinking about switching my main programming system over to Linux soon. I'll need to start using metacommands to detect Linux vs Windows systems for the compiled .EXE files.
In order to understand recursion, one must first understand recursion.

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: Simple Piano
« Reply #5 on: March 26, 2020, 02:00:11 am »
WOW! I liked this program a lot! Great Job!
@TerryRitchie Could you please add a feature so that I can save the music I create in .wav or .mp3 or any other format?
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Simple Piano
« Reply #6 on: March 26, 2020, 05:55:44 am »
Ashish wrote:

Quote
WOW! I liked this program a lot! Great Job!
@TerryRitchie Could you please add a feature so that I can save the music I create in .wav or .mp3 or any other format?

GREAT IDEA! I'm not with a source code computer now, but TODAY later I add functional source code here that can save WAV files. You will still need to convert the OGG source files to WAV format for the feature you describe and the concept I have in mind. Combining individual keys, when playing 4 notes at the same time, is performed as a mathematical average of the values of the wav files. This interweaving really works like this, I have tried it. I will also try to modify this program in the way you write about!

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Simple Piano
« Reply #7 on: March 26, 2020, 06:32:50 am »
Terry,

The only change needed was:

Line 193: Path$ = ".\PIANO\"  to  Path$ = "./PIANO/"

Hope this helps.

J
Logic is the beginning of wisdom.

Offline luke

  • Administrator
  • Seasoned Forum Regular
  • Posts: 324
    • View Profile
Re: Simple Piano
« Reply #8 on: March 26, 2020, 06:45:03 am »
I'm not in a position to check right now, but I'm pretty sure QB64 supports paths with "/” slashes on both Windows and Unix. If that is indeed correct they're the safer slash to use everywhere.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Simple Piano
« Reply #9 on: March 26, 2020, 06:49:03 am »
I'm not in a position to check right now, but I'm pretty sure QB64 supports paths with "/” slashes on both Windows and Unix. If that is indeed correct they're the safer slash to use everywhere.

I thought QB64 changed slashes to fit the file system automatically, so it didn't matter if either / or \ was used? 
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Qwerkey

  • Forum Resident
  • Posts: 755
    • View Profile
Re: Simple Piano
« Reply #10 on: March 26, 2020, 07:42:45 am »
We Librarians (well one of us at least) like this.  @TerryRitchie Now that we have "Output EXE to Source Folder", if you're going to update this program, why not get rid of all the PATH$ and IF _FILEEXISTS stuff?

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Simple Piano
« Reply #11 on: March 26, 2020, 09:42:28 am »
WOW! I liked this program a lot! Great Job!
@TerryRitchie Could you please add a feature so that I can save the music I create in .wav or .mp3 or any other format?

Hmmm, after reading your request I thought "Yeah, that would be cool". But then a few seconds more thinking and ... "How the heck would I do that?" Does anyone have any suggestions as a starting point?
In order to understand recursion, one must first understand recursion.

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Simple Piano
« Reply #12 on: March 26, 2020, 09:52:46 am »
We Librarians (well one of us at least) like this.  @TerryRitchie Now that we have "Output EXE to Source Folder", if you're going to update this program, why not get rid of all the PATH$ and IF _FILEEXISTS stuff?

Here is the code modified to remove the need for a separate .\PIANO\ folder for the assets.

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.  
In order to understand recursion, one must first understand recursion.

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Simple Piano
« Reply #13 on: March 26, 2020, 09:55:48 am »
Terry,

The only change needed was:

Line 193: Path$ = ".\PIANO\"  to  Path$ = "./PIANO/"

Hope this helps.

J

I though an earlier version of QB64 corrected that ... the / or \ could be used and the compiler would correct for the underlying OS?

Oh, I see that Steve thought that too.
In order to understand recursion, one must first understand recursion.

FellippeHeitor

  • Guest
Re: Simple Piano
« Reply #14 on: March 26, 2020, 10:11:11 am »
For internal file commands like OPEN, image, sound and font, etc. QB64 does the conversion, so it doesn't matter.

For SHELL calls, they remain unchanged. It is advisable, if it's for SHELL calls, to create a precompiler block and define the separator:

Code: QB64: [Select]
  1. $IF WIN THEN
  2.     pathSep$ = "\"
  3.     pathSep$ = "/"

That's what I use in my code.