Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Piano - a simple keyboard prog
#1
This is a fairly simple programme that allows the user to compose tunes, using the volume, tempo, note-length and tone features provided in QB64PE.

Code: (Select All)
Common Shared LineNumum, LN$, CPR, MX, MY, Tune$, Tunes$(), Octave, Length, Tempo, Volume, NT, NT$
Common Shared TN$, OldTune$, LastOp$, Remove$
SW = 1040: sh = 720
Screen _NewImage(SW, sh, 32)
SetFont: f& = _LoadFont("C:\WINDOWS\fonts\courbd.ttf", 20, "monospace"): _Font f&
CPR = SW / _PrintWidth("X") '                                       chars per row for this screen setting
_ScreenMove (_DesktopWidth - SW) / 2, 100
Color _RGB(255, 255, 255), _RGB(64, 64, 0): Cls
'Kill "TuneDir": Kill "Tunes"
If Not _FileExists("TuneDir") Or Not _FileExists("Tunes") Then
   Open "TuneDir" For Output As #1: Open "Tunes" For Output As #2 ' create new files if missing
   Close
End If

'Kill "TUNEDIR": Kill "TUNES" '                                     delete all tunes for testing functions

Instructions
Octave = 3: Length = 4: Tempo = 125: Volume = 50
Dim Tunes$(9)
Box1$ = "r143d35l143u35r47nd35r63nd35": Box2$ = "r83d35l85u35"

Tune$ = "v0o3l4t120cv50"
Play Tune$ '                                                        set defaults

Start:
Yellow: Locate 2, 16: Print "OCTAVE"; Tab(31); "1/LENGTH"; Tab(47); "TEMPO"; Tab(61); "VOLUME"
Yellow: Locate 4, 15: Print "-   ";: White: Print LTrim$(Str$(Octave));: Yellow: Print "   +"
Yellow: Locate 4, 29: Print "-   ";: White: Print LTrim$(Str$(Length));: Yellow: Print "   +"
Yellow: Locate 4, 45: Print "-  ";: White: Print LTrim$(Str$(Tempo));: Yellow: Print "  +"
Yellow: Locate 4, 60: Print "-  ";: White: Print LTrim$(Str$(Volume));: Yellow: Print "   +"

Locate 7, 16: Print "NEW"
Locate 7, 26: Print "BACK"
Locate 7, 40: Print "PLAY"
Locate 7, 53: Print "LOAD"
Locate 7, 64: Print "SAVE"
PSet (165, 50)
Draw Box1$
PSet (350, 50)
Draw Box1$
PSet (555, 50)
Draw Box1$
PSet (748, 50)
Draw Box1$

PSet (170, 110)
Draw Box2$
PSet (310, 110)
Draw Box2$
PSet (490, 110)
Draw Box2$
PSet (660, 110)
Draw Box2$
PSet (805, 110)
Draw Box2$

whitekeys:
For a = 292 To 682 Step 65
   Line (a, 505)-(a + 60, 635), _RGB(255, 255, 255), BF
Next
blackkeys:
Line (332, 505)-(372, 560), _RGB(32, 32, 0), BF
Line (397, 505)-(437, 560), _RGB(32, 32, 0), BF
Line (527, 505)-(567, 560), _RGB(32, 32, 0), BF
Line (592, 505)-(631, 560), _RGB(32, 32, 0), BF
Line (657, 505)-(696, 560), _RGB(32, 32, 0), BF

KeyLabels:
Centre "C#   Eb        F#   Ab   Bb ", 25
Centre "C    D    E    F    G    A    B", 33

Tune$ = ""
Do
   DisplayTune
   Do
      i = _MouseInput
   Loop Until _MouseButton(1)
   MX = _MouseX: MY = _MouseY

   DealWithMouse
   Do
      i = _MouseInput
   Loop Until Not _MouseButton(1)
Loop

Sub DealWithMouse
   Select Case MY
      Case 50 To 85 '                                               <---------------------   octave, length, tempo, volume
         White: Locate 8, 1
         Select Case MX '                                           get the mouse horiz position
            Case 164 To 204 '                                       Octave -
               If Octave > 0 Then '                                 don't do anything if at octave 0
                  If LastOp$ = "O" Then
                     Tune$ = Left$(Tune$, Len(Tune$) - 2)
                  End If
                  Octave = Octave - 1
                  Locate 4, 19: White: Print LTrim$(Str$(Octave)) + " "
                  Tune$ = Tune$ + "O" + LTrim$(Str$(Octave))
                  LastOp$ = "O"
               End If

            Case 267 To 307 '                                       Octave +
               If Octave < 6 Then '                                 don't do anything if at octave 6
                  If LastOp$ = "O" Then
                     Tune$ = Left$(Tune$, Len(Tune$) - 2)
                  End If
                  Octave = Octave + 1
                  Locate 4, 19: White: Print LTrim$(Str$(Octave)) + " "
                  Tune$ = Tune$ + "O" + LTrim$(Str$(Octave))
                  LastOp$ = "O"
               End If

            Case 352 To 392 '                                        Length -
               If Length > 1 Then
                  If LastOp$ = "L" Then Tune$ = Left$(Tune$, Len(Tune$) - Len((Str$(Length))))
                  Length = Length / 2
                  Locate 4, 33: Print Space$(3): Locate 4, 33: White: Print LTrim$(Str$(Length)) + " "
                  Tune$ = Tune$ + "L" + LTrim$(Str$(Length))
                  LastOp$ = "L"
               End If

            Case 455 To 495 '                                        Length +
               If Length < 64 Then
                  If LastOp$ = "L" Then Tune$ = Left$(Tune$, Len(Tune$) - Len(Str$(Length)))
                  Length = Length * 2
                  Locate 4, 33: Print Space$(3): Locate 4, 33:: White: Print LTrim$(Str$(Length)) + " "
                  Tune$ = Tune$ + "L" + LTrim$(Str$(Length))
                  LastOp$ = "L"
               End If

            Case 555 To 595 '                                        Tempo -
               If Tempo > 40 Then '                                  only if not at maximum
                  If LastOp$ = "T" Then Tune$ = Left$(Tune$, Len(Tune$) - Len(Str$(Tempo)))
                  Tempo = Tempo - 10
                  Locate 4, 48: White: Print LTrim$(Str$(Tempo)) + " "
                  Tune$ = Tune$ + "T" + LTrim$(Str$(Tempo))
                  LastOp$ = "T"
               End If

            Case 658 To 698 '                                        tempo +
               If Tempo < 246 Then '                                 only if not at maximum
                  If LastOp$ = "T" Then Tune$ = Left$(Tune$, Len(Tune$) - Len(Str$(Tempo)))
                  Tempo = Tempo + 10
                  Locate 4, 48: White: Print LTrim$(Str$(Tempo)) + " "
                  Tune$ = Tune$ + "T" + LTrim$(Str$(Tempo))
                  LastOp$ = "T"
               End If

            Case 750 To 790 ' Volume-
               If Volume > 4 Then
                  If LastOp$ = "V" Then Tune$ = Left$(Tune$, Len(Tune$) - Len(Str$(Volume)))
                  Volume = Volume - 5
                  Locate 4, 63: White: Print Space$(4): Locate 4, 63: Print LTrim$(Str$(Volume))
                  Tune$ = Tune$ + "V" + LTrim$(Str$(Volume))
                  LastOp$ = "V"
               End If

            Case 853 To 893 ' Volume+
               If Volume < 96 Then
                  If LastOp$ = "V" Then Tune$ = Left$(Tune$, Len(Tune$) - Len(Str$(Volume)))
                  Volume = Volume + 5
                  Locate 4, 63: White: Print Space$(4): Locate 4, 63: Print LTrim$(Str$(Volume))
                  Tune$ = Tune$ + "V" + LTrim$(Str$(Volume))
                  LastOp$ = "V"
               End If
         End Select

      Case 110 To 145 '                                              <---------------------   New, Back, Play, Save
         Play "o3l4t125v50" ' '                                      reset defaults
         LastOp$ = ""
         Select Case MX

            Case 170 To 253 '                                        new tune
               Tune$ = "" '                                          delete tune string
               Octave = 3: Length = 4: Tempo = 125: Volume = 50 '    reset defaults
               For a = 9 To 20: Locate a, 1: Print Space$(80);: Next '  erase old tune display
               Locate 4, 19: White: Print LTrim$(Str$(Octave))
               Locate 4, 33: White: Print "    ": Locate 4, 33: Print LTrim$(Str$(Length))
               Locate 4, 48: White: Print "   ": Locate 4, 48: Print LTrim$(Str$(Tempo))
               Locate 4, 63: White: Print "   ": Locate 4, 63: Print LTrim$(Str$(Volume))

            Case 490 To 573 '                                        play tune
               Play "v0o3l4t120cv50" '                               ensure default settings are applied first
               Play Tune$

            Case 660 To 743 '                                        load tune
               NT = 0
               Open "TuneDir" For Input As #1
               If LOF(1) < 2 Then Play bad$: Centre "No tunes saved yet, sorry", 10: Sleep 1: WIPE "10": Close: Exit Sub
               Play "v0o3l4t120cv50"
               WipeTuneDisplay
               Locate 10, 1
               While Not EOF(1)
                  NT = NT + 1
                  Input #1, Tune$
                  Print Tab(35); NT; Tab(40); Tune$
               Wend
               Close
               Centre "Number of the tune to load    ", 22 '         invite number selection
               Locate 22, 53: Input TN$
               If Val(TN$) > NT Or Val(TN$) = 0 Then Exit Sub
               TN = Val(TN$)
               Open "tunes" For Input As #1
               For a = 1 To TN: Input #1, Tune$: Next: Close
               Locate 18, 60
               _KeyClear
               WipeTuneDisplay '                                    tune may be shorter, so erase previous tune display
               WIPE "1822": Centre "The requested tune is loaded", 18: Sleep 1
               l = Len(Tune$)

            Case 805 To 888 '                                        save tune
               If Tune$ = "" Then Exit Sub
               Cls: Close
               NT = 0
               Yellow: Centre "Existing Tunes:", 12: White
               Open "TuneDir" For Input As #1 '                      get Tunes list
               While Not EOF(1)
                  Input #1, OldTune$
                  NT = NT + 1
                  Print Tab(35); NT; Tab(40); OldTune$
               Wend
               Close
               _KeyClear
               If NT > 9 Then
                  Yellow: Centre "No more room; tune to be replaced (1 to 10)     ", 24
                  White: Locate 24, 60: Input Remove$
                  If Val(Remove$) > 10 Or Val(Remove$) < 1 Then Run
                  DeleteTune
               End If
               WIPE "24"
               Yellow: Centre "What will you call your new tune       ", 24
               White: Locate 24, 53: Input TuneName$
               If TuneName$ = "" Then
                  Centre "No file changes made", 12: Sleep 1
                  Run
               End If
               WIPE "1224"
               NT = NT + 1
               Open "TuneDir" For Append As #1
               Open "tunes" For Append As #2
               Write #1, TuneName$
               Write #2, Tune$
               Close '                                               place name and tune number in tune directory
               txt$ = "Added " + TuneName$ + " to file"
               Centre txt$, 12: Sleep 1: Cls
               NT = 0
               Yellow: Centre "Existing Tunes", 12: White
               Open "TuneDir" For Input As #1 '                      get Tunes list
               While Not EOF(1)
                  Input #1, OldTune$
                  NT = NT + 1
                  Print Tab(35); NT; Tab(40); OldTune$
               Wend
               Close: Sleep 2: Tune$ = ""
               Run

            Case 310 To 393 '                                        erase last char of tune
               Tune$ = Left$(Tune$, Len(Tune$) - 1)
               DisplayTune
         End Select

         KeyBoard:
      Case 504 To 561 '                                              black keys
         LastOp$ = ""
         Select Case MX
            Case 333 To 373
               Tune$ = Tune$ + "C+"
            Case 397 To 437
               Tune$ = Tune$ + "E-"
            Case 527 To 566
               Tune$ = Tune$ + "F+"
            Case 592 To 631
               Tune$ = Tune$ + "A-"
            Case 657 To 696
               Tune$ = Tune$ + "B-"
         End Select

      Case 504 To 634 '                                              white keys
         LastOp$ = ""
         Select Case MX
            Case 291 To 354
               Tune$ = Tune$ + "C"
            Case 356 To 419
               Tune$ = Tune$ + "D"
            Case 421 To 484
               Tune$ = Tune$ + "E"
            Case 486 To 549
               Tune$ = Tune$ + "F"
            Case 551 To 614
               Tune$ = Tune$ + "G"
            Case 616 To 679
               Tune$ = Tune$ + "A"
            Case 681 To 744
               Tune$ = Tune$ + "B"
         End Select
   End Select
End Sub

Sub DisplayTune:
   WipeTuneDisplay '                                                tune may be shorter, so erase previous tune display
   Locate 14, 10
   l = Len(Tune$)
   For a = 1 To l
      If a Mod (60) = 0 Then Print Tab(10); '                       display tune in rows of 60 chars
      Print Mid$(Tune$, a, 1);
   Next
End Sub

Sub DeleteTune
   Open "TuneDir" For Input As #1 '                                  get old files
   Open "Tunes" For Input As #2

   Open "TempTuneDir" For Output As #3 '                             create new files
   Open "TempTunes" For Output As #4

   For a = 1 To Val(Remove$) - 1
      Input #1, TuneName$: Write #3, TuneName$ '                     copy records before selected into new file
      Input #2, Tune$: Write #4, Tune$
   Next

   Input #1, TuneName$: Input #2, Tune$ '                            read selected record and discard it

   For a = Val(Remove$) + 1 To NT
      Input #1, TuneName$: Write #3, TuneName$ '                     copy remaining old records into new file
      Input #2, Tune$: Write #4, Tune$
   Next

   Close
   Kill "TuneDir": Kill "Tunes" '                                    delete old files
   Name "TempTuneDir" As "TuneDir" '                                 rename new files as old files
   Name "TempTunes" As "Tunes"
   Sleep 2
End Sub

Sub Centre (txt$, linenum)
   ctr = Int(CPR / 2 - Len(txt$) / 2) + 1 '                         CPR is chars per row for this screen setting
   Locate linenum, ctr '                                            place text at horiz centre of screen
   Print txt$
End Sub

Sub WIPE (ln$) '                                                     clear selected screen rows
   If Len(ln$) = 1 Then ln$ = "0" + ln$
   For a = 1 To Len(ln$) - 1 Step 2
      wl = Val(Mid$(ln$, a, 2))
      Locate wl, 1: Print Space$(CPR);
   Next
End Sub

Sub WipeTuneDisplay
   Locate 10, 1: Print Space$(880)
End Sub

Sub White
   Color _RGB(255, 255, 255)
End Sub

Sub Yellow
   Color _RGB(255, 255, 0)

End Sub
Sub Red
   Color _RGB(255, 0, 0)
End Sub

Sub Instructions:
   Yellow: Centre "Piano", 8: White: Print
   Print "   A simple mouse-driven programme to allow tunes to be composed, saved, and"
   Print "   re-played. They can be edited and saved later under the same name or a": Print
   Print "   new one. The tunes can use up to 7 octaves, with standard 13 semitones per"
   Print "   octave (13 TET) notation. It accommodates volume from 0% (silent) to 100% "
   Print "   of the system sound, and tempo from 32 bpm to 255 bpm, with note-lengths of"
   Print "   from 1 to 64, expressed as full-note fractions, e.g. 4 is 1 crotchet."
   Yellow: Centre "Press Left-Mouse to begin", 19
   Do
      m = _MouseInput
      b = _MouseButton(1)
   Loop While b <> -1: Cls '                                         wait for left-mouse click
   Sleep 1
End Sub
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, Western Australia.) Big Grin
Please visit my Website at: http://oldendayskids.blogspot.com/
Reply
#2
That's cool, Phil, and fun to noodle around with. I like the way you handle color and centering text in the program.

I tried re-writing your main loop. It adds a _LIMIT to slow things down.

Code: (Select All)
Do
    While _MouseInput: Wend
    MX = _MouseX: MY = _MouseY: MB = _MouseButton(1)
    DisplayTune
    If MB _AndAlso Not oldMB Then DealWithMouse '  using the Steve trick to limit the mouse click to one input
    oldMB = MB
    _Limit 30
    _Display
    If _KeyDown(27) Then System '  esc to exit
Loop
Reply
#3
(02-22-2026, 12:25 AM)NakedApe Wrote: That's cool, Phil, and fun to noodle around with. I like the way you handle color and centering text in the program.

I tried re-writing your main loop. It adds a _LIMIT to slow things down.

Code: (Select All)
Do
    While _MouseInput: Wend
    MX = _MouseX: MY = _MouseY: MB = _MouseButton(1)
    DisplayTune
    If MB _AndAlso Not oldMB Then DealWithMouse '  using the Steve trick to limit the mouse click to one input
    oldMB = MB
    _Limit 30
    _Display
    If _KeyDown(27) Then System '  esc to exit
Loop

Yes, thanks NakedApe. That's a nice way to limit mouse clicks.  Didn't see that one from Steve; it's neat.  I've never used _AndAlso, I must have a play around with that.
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, Western Australia.) Big Grin
Please visit my Website at: http://oldendayskids.blogspot.com/
Reply
#4
+1 @PhilOfPerth nice work Phil! I think this would be particularly appealing for those who have no background in reading and playing from musical scores.
  724  855  599  923  575  468  400  206  147  564  878  823  652  556 bxor cross forever
Reply
#5
Nicely and usefull for creating some effects!


Reply


Forum Jump:


Users browsing this thread: