RouterOS beeper player
In the Hall of the Mountain King
The tune is written once on B and once on F sharp, as steps up a table of notes; each statement names its keynote and takes its eighth from a tempo list, so the climb and the pressing on are data. It plays the same notes as the notes page, tone for tone.
1# In the Hall of the Mountain King, from Peer Gynt (Edvard Grieg) - for one beeper - https://lab.glossema.dev/play/mountain-king/code2# It plays the notes of https://lab.glossema.dev/play/mountain-king, tone for tone.3# Grieg states one four-bar tune eighteen times, low and quiet at first, then4# higher, louder and faster, and a coda of fifteen bars breaks it off. This plays5# seven of the statements and the whole coda, each in the orchestra's own octave.6# The tune is written twice, on B and on F sharp, as steps up a table of7# semitones; each statement names its keynote, and a tempo list sets its eighth.8{9 # Every semitone from B2 up to D7, in Hz, an octave to a row.10 :local hz {11 123;131;139;147;156;165;175;185;196;208;220;233;12 247;262;277;294;311;330;349;370;392;415;440;466;13 494;523;554;587;622;659;698;740;784;831;880;932;14 988;1047;1109;1175;1245;1319;1397;1480;1568;1661;1760;1865;15 1976;2093;2217;2349}16 # The eighth of each part: 217 ms for the first three, the print's 13817 # quarters a minute, then each part a step faster.18 :local tempo {217ms;217ms;217ms;205ms;190ms;180ms;172ms;166ms;160ms}19 # The bass strokes, each letter in the octave from C3 up to B3, in Hz.20 :local stroke {"B"=247;"D"=147;"F#"=185;"G"=196}2122 # share: the bass strikes its letter in front of a note or a rest and pays for23 # it out of that slot; it hands back what is left of the slot.24 :local share do={25 :beep frequency=$bass length=$hit26 :delay $gap27 :return ($slot - $gap)28 }29 # graced: the piccolo's B6, led in by G#6, A6 and A#6, paid out of its slot.30 :local graced do={31 :local left $slot32 :foreach g in={1661;1760;1865} do={33 :beep frequency=$g length=25ms34 :delay 30ms35 :set left ($left - 30ms)36 }37 :beep frequency=1976 length=$tone38 :return $left39 }4041 # The tune, eight eighths to a bar as the ff parts strike them. Each eighth is42 # a step up the table from the keynote, or hold: the last note or rest goes on.43 :local hold -144 :local onB {45 {0;2;3;5;7;3;7;7};46 {6;2;6;6;5;1;5;5};47 {0;2;3;5;7;3;7;12};48 {10;7;3;7;10;$hold;$hold;$hold}}49 # On F sharp the third is major, the third bar repeats the first, and the50 # second and fourth bars are its own.51 :local riseFsharp {0;2;4;5;7;4;7;7}52 :local onFsharp {$riseFsharp; {8;4;8;8;7;4;7;7}; $riseFsharp; {8;4;8;8;7;$hold;$hold;$hold}}53 # The last statement closes on B.54 :local closing {($onB->0);($onB->1);($onB->2);{7;3;7;12;0;$hold;$hold;$hold}}55 # The coda's phrase: twice the piccolo answers the bass (grace), then the56 # tune's third bar and a close on B.57 :local grace -258 :local answer {$hold;$hold;$grace;$hold;$hold;$hold;$hold;$hold}59 :local coda {$answer;$answer;($onB->2);{11;7;11;14;12;$hold;$hold;$hold}}6061 # The bass letter on beats one and three of every bar, "-" where it rests.62 :local bassTacet {"-";"-";"-";"-";"-";"-";"-";"-"}63 :local bassOnB {"B";"B";"B";"B";"B";"B";"D";"D"}64 :local bassOnFsharp {"F#";"F#";"D";"F#";"F#";"F#";"D";"F#"}65 :local bassClosing {"B";"B";"B";"B";"B";"B";"B";"B"}66 :local bassCoda {"B";"-";"B";"-";"G";"F#";"F#";"B"}6768 # The form: the words each part prints, its bars, its keynote as a step up the69 # table (0 is B2, 7 is F#3, and every octave up adds 12), ff or not, its tone70 # lengths (plain, accented, the closing half, the graced B) and its bass.71 # In the creeping parts the tune is itself the bass.72 :local parts {73 {say="Bars 1-4: the tune, low, pizzicato";74 bars=$onB; key=0; ff=false; tones={76ms;119ms}; bass=$bassTacet};75 {say="Bars 9-12: the tune on F sharp";76 bars=$onFsharp; key=7; ff=false; tones={76ms;119ms}; bass=$bassTacet};77 {say="Bars 25-28: two octaves up, the violins";78 bars=$onB; key=24; ff=false; tones={76ms;119ms}; bass=$bassOnB};79 {say="Bars 33-36: cresc. e stretto poco a poco";80 bars=$onFsharp; key=31; ff=false; tones={92ms;133ms}; bass=$bassOnFsharp};81 {say="Bars 49-52: piu vivo";82 bars=$onB; key=36; ff=true; tones={114ms;152ms;646ms}; bass=$bassOnB};83 {say="Bars 57-60: an octave higher";84 bars=$onFsharp; key=43; ff=true; tones={108ms;144ms;612ms}; bass=$bassOnFsharp};85 {say="Bars 69-72: the tune closes on B";86 bars=$closing; key=36; ff=true; tones={103ms;136ms;585ms}; bass=$bassClosing};87 {say="Bars 73-80: the coda";88 bars=($coda, $coda); key=36; ff=true; tones={100ms;130ms;564ms;149ms}; bass=($bassCoda, $bassCoda)}}8990 :for n from=0 to=([:len $parts] - 1) do={91 :local part ($parts->$n)92 :put ($part->"say")93 :local unit ($tempo->$n)94 :local bars ($part->"bars")95 :local key ($part->"key")96 :local ff ($part->"ff")97 :local tones ($part->"tones")98 :local bass ($part->"bass")99 :local last $hold100 :for b from=0 to=([:len $bars] - 1) do={101 :local bar ($bars->$b)102 :for i from=0 to=([:len $bar] - 1) do={103 :local step ($bar->$i)104 :local slot $unit105 # beats one and three: the bass stroke106 :if (($i % 4) = 0) do={107 :local letter ($bass->(($b * 2) + ($i / 4)))108 :if ($letter != "-") do={109 :set slot [$share bass=($stroke->$letter) hit=30ms gap=35ms slot=$slot]110 }111 }112 :if ($step = $grace) do={113 :set slot [$graced tone=($tones->3) slot=$slot]114 } else={115 # the quiet parts sound a repeated eighth only once, as a quarter116 :if (($step != $hold) && ($ff || ($step != $last))) do={117 # accents on beat three, and on beat one of every second bar;118 # in the ff parts a note on beat three that goes on is the closing half119 :local tone ($tones->0)120 :if (($i = 4) || (($i = 0) && (($b % 2) = 1))) do={ :set tone ($tones->1) }121 :if ($ff && ($i = 4) && (($bar->5) = $hold)) do={ :set tone ($tones->2) }122 :beep frequency=($hz->($key + $step)) length=$tone123 }124 }125 :set last $step126 :delay $slot127 }128 }129 }130131 # The last part, written out: two answers, the crescendo, the roll, the last B.132 :put "Bars 81-87: to the end"133 :local unit ($tempo->8)134 # Two more answers.135 :for bar from=1 to=2 do={136 :delay [$share bass=($stroke->"B") hit=30ms gap=35ms slot=($unit * 2)]137 :delay [$graced tone=144ms slot=($unit * 2)]138 :delay ($unit * 4)139 }140 # p cresc. molto: the graced B on every beat after the first, then on all141 # four, each one 16 ms longer than the one before.142 :delay [$share bass=($stroke->"B") hit=30ms gap=35ms slot=($unit * 2)]143 :for k from=0 to=6 do={144 :delay [$graced tone=(64ms + (16ms * $k)) slot=($unit * 2)]145 }146 # The timpani roll on B from beat three: two pulses to an eighth, and every147 # eighth 3 ms longer, from 7 to 40.148 :delay ($unit * 4)149 :for e from=0 to=11 do={150 :for pulse from=1 to=2 do={151 :beep frequency=($stroke->"B") length=(7ms + (3ms * $e))152 :delay ($unit / 2)153 }154 }155 # fff: the last stroke, 40 ms, and the last B, 230 ms, all the graces leave156 # of its slot.157 :delay [$share bass=($stroke->"B") hit=40ms gap=40ms slot=($unit * 2)]158 :delay [$graced tone=230ms slot=($unit * 2)]159}On the router: paste the script into a terminal, or upload the file and run it.
Script output
Write your own
Ask for a tune you may arrange: your own, one out of copyright, or one you are licensed to use.
Have a MIDI file? altucor’s converter turns it into a script.
How it works
One command sounds one tone: :beep frequency=<hertz> length=<time>; the beeper plays one note at a time.
:delay is the clock. A beep starts the tone and returns at once, so every note is a beep followed by a delay of the same length and a small gap.
Most tunes here are written out note by note, a beep and a delay each; some also come as code, with loops, tables and functions, that plays the very same notes. Download any of these and run it in a terminal.