RouterOS beeper player
Dial-up
A modem calls, the other answers, and the two whistle and hiss until they agree how to talk.
Your scorePick a tune
:beepSound starts with a script.
1# The 56k dial-up handshake, for one RouterOS beeper2# https://lab.glossema.dev/play/dial-up3# Timed off William Termini's iMac G3 recording (2008), as Oona Raisanen charted it4# in "The sound of the dialup, pictured" (windytan.com, 2012). Signals per ITU-T5# V.8bis, V.8, V.21, V.34 and V.90. About 27 seconds; needs a RouterOS with :timestamp.67{8 :local t0 [:tonsec [:timestamp]];9 :local hold 60ms;1011 # Every wait sleeps in 10ms steps and stops 10ms before its mark, so an12 # event lands within about 10ms either side of its time. No wait ever spins13 # without a :delay, so an emulator whose clock only moves on :delay still14 # finishes.1516 # One steady tone from start to stop (ms on the recording's clock). tail17 # lets it ring on into whatever follows at once, 0 before a silence.18 :local tone do={19 :local a [:tonum $start];20 :local b [:tonum $stop];21 :while ((([:tonsec [:timestamp]] - $t0) / 1000000) < ($a - 10)) do={ :delay 10ms; }22 :local left ($b - (([:tonsec [:timestamp]] - $t0) / 1000000));23 :if ($left > 0) do={ :beep frequency=[:tonum $hz] length=(1ms * ($left + [:tonum $tail])); }24 :while ((([:tonsec [:timestamp]] - $t0) / 1000000) < ($b - 10)) do={ :delay 10ms; }25 };2627 # Several signals at once, taken in turn, one per step. A voice is a fixed28 # tone "1800", a random pick of two "980|1180" (FSK bits), or anywhere in a29 # band "800~1600". tail: how long the last beep may ring - short before a30 # silence, longer when the next section follows straight on.31 :local mix do={32 :local lo [:toarray ""];33 :local sp [:toarray ""];34 :local kd [:toarray ""];35 :foreach e in=[:toarray $voices] do={36 :local v [:tostr $e];37 :local r [:find $v "~"];38 :local c [:find $v "|"];39 :local k 0;40 :local x $v;41 :local y $v;42 :if ([:typeof $r] = "num") do={ :set k 1; :set x [:pick $v 0 $r]; :set y [:pick $v ($r + 1) [:len $v]]; }43 :if ([:typeof $c] = "num") do={ :set k 2; :set x [:pick $v 0 $c]; :set y [:pick $v ($c + 1) [:len $v]]; }44 :set lo ($lo, [:tonum $x]);45 :set sp ($sp, ([:tonum $y] - [:tonum $x]));46 :set kd ($kd, $k);47 }48 :local n [:len $lo];49 :local s [:tonum $seed];50 :local i 0;51 :local f ($lo->0);52 :local a [:tonum $start];53 :local b [:tonum $stop];54 :while ((([:tonsec [:timestamp]] - $t0) / 1000000) < ($a - 10)) do={ :delay 10ms; }55 :while ((([:tonsec [:timestamp]] - $t0) / 1000000) < $b) do={56 :local j ($i % $n);57 :set s ((75 * $s) % 65537);58 :set f ($lo->$j);59 :if (($kd->$j) = 1) do={ :set f ($f + ($s % ($sp->$j))); }60 :if (($kd->$j) = 2) do={ :set f ($f + (($s % 2) * ($sp->$j))); }61 :beep frequency=$f length=$hold;62 :delay 10ms;63 :set i ($i + 1);64 }65 :beep frequency=$f length=(1ms * [:tonum $tail]);66 };6768 # A low buzz, re-struck every period ms with a one-step accent - the DIL's69 # flutter.70 :local buzz do={71 :local a [:tonum $start];72 :local b [:tonum $stop];73 :local p [:tonum $period];74 :while ((([:tonsec [:timestamp]] - $t0) / 1000000) < ($a - 10)) do={ :delay 10ms; }75 :local nx $a;76 :while ($nx < $b) do={77 :beep frequency=[:tonum $accent] length=$hold;78 :delay 10ms;79 :beep frequency=[:tonum $hz] length=(1ms * ($p + 40));80 :set nx ($nx + $p);81 :if ($nx > $b) do={ :set nx $b; }82 :while ((([:tonsec [:timestamp]] - $t0) / 1000000) < ($nx - 10)) do={ :delay 10ms; }83 }84 };8586 # DTMF keypad, and the seven digits dialed in the recording.87 :local row {"k1"=697; "k2"=697; "k3"=697; "k4"=770; "k5"=770; "k6"=770; "k7"=852; "k8"=852; "k9"=852; "k*"=941; "k0"=941; "k#"=941};88 :local col {"k1"=1209; "k4"=1209; "k7"=1209; "k*"=1209; "k2"=1336; "k5"=1336; "k8"=1336; "k0"=1336; "k3"=1477; "k6"=1477; "k9"=1477; "k#"=1477};89 :local number "3440208";9091 # 0.0 s - off hook. The copy starts partway into the dial tone.92 :put "Dial tone - 350 + 440 Hz";93 $mix t0=$t0 hold=$hold start=0 stop=500 voices="350,440" seed=1 tail=10;9495 # 0.5 s - a digit every 168ms, 115ms of row and column tone together.96 :put "Dialing";97 :for i from=0 to=([:len $number] - 1) do={98 :local d ("k" . [:pick $number $i]);99 :local ds (507 + (168 * $i));100 $mix t0=$t0 hold=$hold start=$ds stop=($ds + 115) voices=(($row->$d) . "," . ($col->$d)) seed=($i + 2) tail=10;101 }102103 # 2.6 s - one crackle on the line, then a second of nothing.104 $mix t0=$t0 hold=$hold start=2574 stop=2659 voices="150~700,1800~3700" seed=11 tail=10;105106 # 3.6 s - V.8bis. Tone pair + tag, then 300 baud messages both ways.107 :put "V.8bis - CRe: 1375 + 2002 Hz, then 400 Hz";108 $mix t0=$t0 hold=$hold start=3631 stop=3913 voices="1375,2002" seed=12 tail=40;109 $tone t0=$t0 start=3913 stop=4012 hz=400 tail=40;110 $tone t0=$t0 start=4012 stop=4100 hz=1650 tail=40;111 $mix t0=$t0 hold=$hold start=4100 stop=4443 voices="1650|1850" seed=13 tail=10;112 :put "V.8bis - CRd: 1529 + 2225 Hz, then 1900 Hz";113 $mix t0=$t0 hold=$hold start=5000 stop=5400 voices="1529,2225" seed=14 tail=40;114 $tone t0=$t0 start=5400 stop=5543 hz=1900 tail=0;115 :put "V.8bis - messages at 300 baud";116 $tone t0=$t0 start=5809 stop=5950 hz=980 tail=40;117 $mix t0=$t0 hold=$hold start=5950 stop=6689 voices="980|1180" seed=15 tail=10;118 $tone t0=$t0 start=6724 stop=6860 hz=1650 tail=40;119 $mix t0=$t0 hold=$hold start=6860 stop=7306 voices="1650|1850" seed=16 tail=10;120 $tone t0=$t0 start=7457 stop=7600 hz=980 tail=40;121 $mix t0=$t0 hold=$hold start=7600 stop=7937 voices="980|1180" seed=17 tail=10;122123 # 8.2 s - ANSam. The 10ms breaks are its phase reversals, 450ms apart.124 :put "ANSam - 2100 Hz";125 $tone t0=$t0 start=8186 stop=8626 hz=2100 tail=0;126 $tone t0=$t0 start=8636 stop=9076 hz=2100 tail=0;127 $tone t0=$t0 start=9086 stop=9332 hz=2100 tail=40;128 :put "CM - the calling menu, under the answer tone";129 $mix t0=$t0 hold=$hold start=9332 stop=10450 voices="2100,980|1180" seed=18 tail=40;130 :put "JM - both menus at once";131 $mix t0=$t0 hold=$hold start=10450 stop=11640 voices="980|1180,1650|1850" seed=19 tail=40;132 $mix t0=$t0 hold=$hold start=11640 stop=11698 voices="1650|1850" seed=20 tail=10;133134 # 11.7 s - phase 2 under an 1800 Hz guard tone.135 :put "Phase 2 - INFO0, tone A 2400, tone B 1200";136 $mix t0=$t0 hold=$hold start=11705 stop=11775 voices="1800,2000~2800" seed=21 tail=40;137 $mix t0=$t0 hold=$hold start=11775 stop=12050 voices="1800,2400,800~1600" seed=22 tail=40;138 $mix t0=$t0 hold=$hold start=12050 stop=12251 voices="1800,800~1600,2000~2800" seed=23 tail=40;139 $mix t0=$t0 hold=$hold start=12251 stop=12454 voices="1800,1200,2400" seed=24 tail=40;140 :put "L1/L2 - probing the line";141 $tone t0=$t0 start=12454 stop=12861 hz=150 tail=40;142 $mix t0=$t0 hold=$hold start=12861 stop=12936 voices="1800,2400,1200" seed=25 tail=40;143 $tone t0=$t0 start=12936 stop=13028 hz=1200 tail=40;144 $tone t0=$t0 start=13028 stop=13480 hz=150 tail=40;145 :put "INFO1 - the results";146 $mix t0=$t0 hold=$hold start=13480 stop=13600 voices="1800,2400,800~1600" seed=26 tail=40;147 $mix t0=$t0 hold=$hold start=13600 stop=13857 voices="1800,2400,800~1600,2000~2800" seed=27 tail=10;148149 # 13.9 s - phase 3. A low square for rasp against a high tone for hiss.150 :put "Phase 3 - training";151 $mix t0=$t0 hold=$hold start=13943 stop=14780 voices="150~700,1800~3700" seed=28 tail=40;152 $mix t0=$t0 hold=$hold start=14780 stop=16720 voices="150~600,1500~3300" seed=29 tail=40;153 $mix t0=$t0 hold=$hold start=16720 stop=20950 voices="150~700,1800~3700" seed=30 tail=40;154155 # 21.0 s - the DIL, then a 111 Hz buzz and a 1350 Hz blip before phase 4.156 :put "DIL - the 63.5 Hz buzz";157 $buzz t0=$t0 hold=$hold start=20950 stop=22900 hz=63 accent=127 period=79;158 $tone t0=$t0 start=22900 stop=23240 hz=111 tail=40;159 $mix t0=$t0 hold=$hold start=23240 stop=23423 voices="1350,150~600" seed=31 tail=40;160161 # 23.4 s - data, until the modem mutes its speaker mid-noise.162 :put "Phase 4 and data";163 $mix t0=$t0 hold=$hold start=23430 stop=26887 voices="150~700,1800~3700" seed=32 tail=10;164 :put "CONNECT - speaker off";165}/
Space to play / stopNoteFreqLine
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.
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.
A tune is a script: a note table, a melody as an array, one function that plays a note. Download any of these and run it in a terminal.