Some Music

Well since you have a keymap… This has all the octives with your keymap (again in scientific/MIDI scale), defaulting for 4th octive but the “z” and “x” should change it. And even the next octive “k” (C5) “o” (C#5) and “l” (D5) are mapped.

Probably could deal with velocity using keymap (instead of using numbers 1, 2, … to double, triple, … length=). I just don’t know a good base for the note length and how much velocity should increase with the “c” and “v” velocity keys. If you had a preference, that be easy to add.

{
:local nms 125ms
:local octive 4
:global scalearr {"a"=(33,65,131,262,523,1047,2093,4186,8372) ; 
"w"=(35,69,139,277,554,1109,2217,4435,8870) ;
"s"=(37,73,147,294,587,1175,2349,4699,9397) ;
"e"=(39,78,156,311,622,1245,2489,4978,9956) ;
"d"=(41,82,165,330,659,1319,2637,5274,10548) ;
"f"=(44,87,175,349,698,1397,2794,5588,11175) ;
"t"=(46,92,185,370,740,1480,2960,5920,11840) ; 
"g"=(49,98,196,392,784,1568,3136,6272,12544) ;
"y"=(52,104,208,415,831,1661,3322,6645,13290) ;
"h"=(55,110,220,440,880,1760,3520,7040,14080) ;
"u"=(58,117,233,466,932,1865,3729,7459,14917) ;
"j"=(62,123,247,494,988,1976,3951,7902,15804) ;
"k"=(65,131,262,523,1047,2093,4186,8372,16744) ; 
"o"=(69,139,277,554,1109,2217,4435,8870,17739) ;
"l"=(73,147,294,587,1175,2349,4699,9397,18795) ;
}
:local "ascii-map" {"";"NUL";"SOH";"STX";"ETX";"EOT";"ENQ";"ACK";"back";"back";"tab";"VT";"FF";"enter";"return";"SI";"DLE";"DC1";"DC2";"DC3";"DC4";"NAK";"SYN";"ETB";"CAN";"EM";"SUB";"ESC";"FS";"GS";"RS";"US";"space";"!";"\"";"comment";"\$";"%";"&";"";"(";")";"*";"+";",";"-";".";"/";"0";"1";"2";"3";"4";"5";"6";"7";"8";"9";":";";";"<";"=";">";"\?";"@";"A";"B";"C";"D";"E";"F";"G";"H";"I";"J";"K";"L";"M";"N";"O";"P";"Q";"R";"S";"T";"U";"V";"W";"X";"Y";"Z";"[";"\\";"]";"^";"_";"`";"a";"b";"c";"d";"e";"f";"g";"h";"i";"j";"k";"l";"m";"n";"o";"p";"q";"r";"s";"t";"u";"v";"w";"x";"y";"z";"{";"|";"}";"~";"delete"}

:local lastkey 65535
:put "** ROUTEROS PLAYER PIANO **"
:put "Type a key to play a note...  The note will play for $nms.  Keep holding to continue playing."
:foreach nltr,nfreq in=$scalearr do={:put "\t$nltr  \t  $($nfreq->octive) Hz"}
:put "\t\t\tNotes are in the $($octive) octive of the scientific scale."
:put "\t\t\tSharp # notes are denoted by using a CAPTIAL letter of the note."
:put "\tTo play a longer note, type a number before the note"
:put "\t\te.g. 2 will play all future notes twice as long so $($nms*2).  Hit 1 to reset to $(nms)"
:put "\tCurrent octive is $octive.  Use \"x\" for next higher octive, or \"z\" to lower octive"

:put "\tTo quit, hit \"q\""
:local lnms $nms
:while ($lastkey != 113) do={
    :set lastkey [/terminal inkey]
    :if ($lastkey = 65535) do={:delay $nms} else={
        :if ($lastkey > 48 && $lastkey < 58) do={
            :set $lnms ($nms*($lastkey - 48))
            :put "\t\tnote length = $lnms"
        }
        :local lastascii ($"ascii-map"->$lastkey)
        :if ($lastascii = "x") do={:set octive ($octive+1); :put "\t\toctive = $octive" }
        :if ($lastascii = "z") do={:set octive ($octive-1); :put "\t\toctive = $octive" }
        :local freq ($scalearr->$lastascii->($octive+1))
        :if ([:typeof $freq]="num") do={
            :beep frequency=$freq length=$lnms
            :delay $lnms
            /terminal cuu 
        }
    }
}
}

Octave change is great! But I dont think you could change velocity in mikrotik, in midi format velocity affect volume of note, and I cant see any possible way how to change loudness of beep in mikrotik. Correct me if im wrong.

That’s right: velocity is loudness/attenuation/volume. Correct, not possible :wink:. I thought it was “note length”. It’s how quarter/half/ull notes are handled, not so sure. e.g. currently: 1 = 125ms, 2 = 250ms, 3 = 375ms, etc.

Also need to mention that quarter/half/full value is also affected by bpm count. Heres online calculator - https://muted.io/bpm-to-ms/

I made a better help screen. If using winbox terminal, or any shell with ANSI colors, the NOTES will be reversed and other help shown.





Here is some updated code with better help and formatting. Also made code a function, so it can be called more than once using “$PIANO ” after the function is loaded.

:global PIANO do={
:local nms 125ms
:if ([:typeof [:totime $1]]="time") do={:set nms [:totime $1]}
:local octive 4
:local scalearr {"a"=(33,65,131,262,523,1047,2093,4186,8372) ; 
"w"=(35,69,139,277,554,1109,2217,4435,8870) ;
"s"=(37,73,147,294,587,1175,2349,4699,9397) ;
"e"=(39,78,156,311,622,1245,2489,4978,9956) ;
"d"=(41,82,165,330,659,1319,2637,5274,10548) ;
"f"=(44,87,175,349,698,1397,2794,5588,11175) ;
"t"=(46,92,185,370,740,1480,2960,5920,11840) ; 
"g"=(49,98,196,392,784,1568,3136,6272,12544) ;
"y"=(52,104,208,415,831,1661,3322,6645,13290) ;
"h"=(55,110,220,440,880,1760,3520,7040,14080) ;
"u"=(58,117,233,466,932,1865,3729,7459,14917) ;
"j"=(62,123,247,494,988,1976,3951,7902,15804) ;
"k"=(65,131,262,523,1047,2093,4186,8372,16744) ; 
"o"=(69,139,277,554,1109,2217,4435,8870,17739) ;
"l"=(73,147,294,587,1175,2349,4699,9397,18795) ;
}
:local "ascii-map" {"";"NUL";"SOH";"STX";"ETX";"EOT";"ENQ";"ACK";"back";"back";"tab";"VT";"FF";"enter";"return";"SI";"DLE";"DC1";"DC2";"DC3";"DC4";"NAK";"SYN";"ETB";"CAN";"EM";"SUB";"ESC";"FS";"GS";"RS";"US";"space";"!";"\"";"comment";"\$";"%";"&";"";"(";")";"*";"+";",";"-";".";"/";"0";"1";"2";"3";"4";"5";"6";"7";"8";"9";":";";";"<";"=";">";"\?";"@";"A";"B";"C";"D";"E";"F";"G";"H";"I";"J";"K";"L";"M";"N";"O";"P";"Q";"R";"S";"T";"U";"V";"W";"X";"Y";"Z";"[";"\\";"]";"^";"_";"`";"a";"b";"c";"d";"e";"f";"g";"h";"i";"j";"k";"l";"m";"n";"o";"p";"q";"r";"s";"t";"u";"v";"w";"x";"y";"z";"{";"|";"}";"~";"delete"}
:local lnms $nms
:local lastkey 65535

:put "\t\t** ROUTEROS PLAYER PIANO **"
:put "Type a key to play a note...  The note will play for $nms."
:put "To play a longer note, type a number before the note"
:put "e.g. 2 will play all future notes twice. Hit 1 to reset to $(nms)"
:put "Current octive is $octive.  Use \"x\" for next higher octive, or \"z\" to lower octive"
:put "To quit, hit \"q\""
:put ""
:put "\t\1B[2;31mLENGTH \1B[1;31m1x\1B[0m \1B[1;31m2x\1B[0m \1B[1;31m3x\1B[0m \1B[1;31m4x\1B[0m \1B[1;31m5x\1B[0m \1B[1;31m6x\1B[0m \1B[1;31m7x\1B[0m \1B[1;31m8x\1B[0m" 
:put "\t\1B[0m    `  1  2  3  4  5  6  7  8  9  0  -  = del"
:put "\t      \1B[2;7mQUIT\1B[0m \1B[1;7mC#\1B[0m \1B[1;7mD#\1B[0m    \1B[1;7mF#\1B[0m \1B[1;7mG#\1B[0m \1B[1;7mA#\1B[0m    \1B[1;7mC#\1B[0m"
:put "\t\1B[0m   tab  q  w  e  r  t  y  u  i  o  p  [  ]  \\"
:put "\t         \1B[1;7mC\1B[0m  \1B[1;7mD\1B[0m  \1B[1;7mE\1B[0m  \1B[1;7mF\1B[0m  \1B[1;7mG\1B[0m  \1B[1;7mA\1B[0m  \1B[1;7mB\1B[0m  \1B[1;7mC\1B[0m  \1B[1;7mD\1B[0m "
:put "\t\1B[0m   caps  a  s  d  f  g  h  j  k  l  ;  '  ret"
:put "\t\1B[1;31m          <  >        "
:put "\t\1B[0m   shft   z  x  c  v  b  n  m  ,  .  /  shft"
:put "\t         \1B[2;31mOCTIVE \1B[1m$octive\1B[0m    \1B[2;31mNOTE \1B[1m$lnms\1B[0m "

:while ($lastkey != 113) do={
    :set lastkey [/terminal inkey]
    :if ($lastkey = 65535) do={:delay $nms} else={
        :if ($lastkey > 48 && $lastkey < 58) do={
            :set $lnms ($nms*($lastkey - 48))
            /terminal cuu
            :put "\t         \1B[2;31mOCTIVE \1B[1m$octive\1B[0m    \1B[2;31mBEAT \1B[1m$lnms\1B[0m "
        }
        :local lastascii ($"ascii-map"->$lastkey)
        :if ($lastascii ~ "x|z") do={
            :if ($lastascii = "z") do={ :set octive ($octive-1); } else={ :set octive ($octive+1); } 
            /terminal cuu
            :put "\t         \1B[2;31mOCTIVE \1B[1m$octive\1B[0m    \1B[2;31mBEAT \1B[1m$lnms\1B[0m "
        }
        :local freq ($scalearr->$lastascii->($octive+1))
        :if ([:typeof $freq]="num") do={
            :beep frequency=$freq length=$lnms
            :delay $lnms
            /terminal cuu 
        }
    }
}
}
$PIANO 125ms

[me@router] > $PIANO 50ms
** ROUTEROS PLAYER PIANO **
Type a key to play a note… The note will play for 00:00:00.050.
To play a longer note, type a number before the note
e.g. 2 will play all future notes twice. Hit 1 to reset to 00:00:00.050
Current octive is 4. Use “x” for next higher octive, or “z” to lower octive
To quit, hit “q”

LENGTH 1x 2x 3x 4x 5x 6x 7x 8x
` 1 2 3 4 5 6 7 8 9 0 - = del
QUIT C# D# F# G# A# C#
tab q w e r t y u i o p [ ]
C D E F G A B C D
caps a s d f g h j k l ; ’ ret
< >
shft z x c v b n m , . / shft
OCTIVE 4 NOTE 00:00:00.050

Now its perfect! Great job, thank you !

Well, not quite. In my experience, every musician wants to record themselves. So added a recording feature, a bpm= option, and better help & improved status bar. Created a thread to discuss further (since I hijacked this one)… with new version of $PIANO here: http://forum.mikrotik.com/t/piano-interactive-player-piano-studio-quality-recorder-using-beep/173756/1