# The 56k dial-up handshake, for one RouterOS beeper # https://lab.glossema.dev/play/dial-up # Timed off William Termini's iMac G3 recording (2008), as Oona Raisanen charted it # in "The sound of the dialup, pictured" (windytan.com, 2012). Signals per ITU-T # V.8bis, V.8, V.21, V.34 and V.90. About 27 seconds; needs a RouterOS with :timestamp. { :local t0 [:tonsec [:timestamp]]; :local hold 60ms; # Every wait sleeps in 10ms steps and stops 10ms before its mark, so an # event lands within about 10ms either side of its time. No wait ever spins # without a :delay, so an emulator whose clock only moves on :delay still # finishes. # One steady tone from start to stop (ms on the recording's clock). tail # lets it ring on into whatever follows at once, 0 before a silence. :local tone do={ :local a [:tonum $start]; :local b [:tonum $stop]; :while ((([:tonsec [:timestamp]] - $t0) / 1000000) < ($a - 10)) do={ :delay 10ms; } :local left ($b - (([:tonsec [:timestamp]] - $t0) / 1000000)); :if ($left > 0) do={ :beep frequency=[:tonum $hz] length=(1ms * ($left + [:tonum $tail])); } :while ((([:tonsec [:timestamp]] - $t0) / 1000000) < ($b - 10)) do={ :delay 10ms; } }; # Several signals at once, taken in turn, one per step. A voice is a fixed # tone "1800", a random pick of two "980|1180" (FSK bits), or anywhere in a # band "800~1600". tail: how long the last beep may ring - short before a # silence, longer when the next section follows straight on. :local mix do={ :local lo [:toarray ""]; :local sp [:toarray ""]; :local kd [:toarray ""]; :foreach e in=[:toarray $voices] do={ :local v [:tostr $e]; :local r [:find $v "~"]; :local c [:find $v "|"]; :local k 0; :local x $v; :local y $v; :if ([:typeof $r] = "num") do={ :set k 1; :set x [:pick $v 0 $r]; :set y [:pick $v ($r + 1) [:len $v]]; } :if ([:typeof $c] = "num") do={ :set k 2; :set x [:pick $v 0 $c]; :set y [:pick $v ($c + 1) [:len $v]]; } :set lo ($lo, [:tonum $x]); :set sp ($sp, ([:tonum $y] - [:tonum $x])); :set kd ($kd, $k); } :local n [:len $lo]; :local s [:tonum $seed]; :local i 0; :local f ($lo->0); :local a [:tonum $start]; :local b [:tonum $stop]; :while ((([:tonsec [:timestamp]] - $t0) / 1000000) < ($a - 10)) do={ :delay 10ms; } :while ((([:tonsec [:timestamp]] - $t0) / 1000000) < $b) do={ :local j ($i % $n); :set s ((75 * $s) % 65537); :set f ($lo->$j); :if (($kd->$j) = 1) do={ :set f ($f + ($s % ($sp->$j))); } :if (($kd->$j) = 2) do={ :set f ($f + (($s % 2) * ($sp->$j))); } :beep frequency=$f length=$hold; :delay 10ms; :set i ($i + 1); } :beep frequency=$f length=(1ms * [:tonum $tail]); }; # A low buzz, re-struck every period ms with a one-step accent - the DIL's # flutter. :local buzz do={ :local a [:tonum $start]; :local b [:tonum $stop]; :local p [:tonum $period]; :while ((([:tonsec [:timestamp]] - $t0) / 1000000) < ($a - 10)) do={ :delay 10ms; } :local nx $a; :while ($nx < $b) do={ :beep frequency=[:tonum $accent] length=$hold; :delay 10ms; :beep frequency=[:tonum $hz] length=(1ms * ($p + 40)); :set nx ($nx + $p); :if ($nx > $b) do={ :set nx $b; } :while ((([:tonsec [:timestamp]] - $t0) / 1000000) < ($nx - 10)) do={ :delay 10ms; } } }; # DTMF keypad, and the seven digits dialed in the recording. :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}; :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}; :local number "3440208"; # 0.0 s - off hook. The copy starts partway into the dial tone. :put "Dial tone - 350 + 440 Hz"; $mix t0=$t0 hold=$hold start=0 stop=500 voices="350,440" seed=1 tail=10; # 0.5 s - a digit every 168ms, 115ms of row and column tone together. :put "Dialing"; :for i from=0 to=([:len $number] - 1) do={ :local d ("k" . [:pick $number $i]); :local ds (507 + (168 * $i)); $mix t0=$t0 hold=$hold start=$ds stop=($ds + 115) voices=(($row->$d) . "," . ($col->$d)) seed=($i + 2) tail=10; } # 2.6 s - one crackle on the line, then a second of nothing. $mix t0=$t0 hold=$hold start=2574 stop=2659 voices="150~700,1800~3700" seed=11 tail=10; # 3.6 s - V.8bis. Tone pair + tag, then 300 baud messages both ways. :put "V.8bis - CRe: 1375 + 2002 Hz, then 400 Hz"; $mix t0=$t0 hold=$hold start=3631 stop=3913 voices="1375,2002" seed=12 tail=40; $tone t0=$t0 start=3913 stop=4012 hz=400 tail=40; $tone t0=$t0 start=4012 stop=4100 hz=1650 tail=40; $mix t0=$t0 hold=$hold start=4100 stop=4443 voices="1650|1850" seed=13 tail=10; :put "V.8bis - CRd: 1529 + 2225 Hz, then 1900 Hz"; $mix t0=$t0 hold=$hold start=5000 stop=5400 voices="1529,2225" seed=14 tail=40; $tone t0=$t0 start=5400 stop=5543 hz=1900 tail=0; :put "V.8bis - messages at 300 baud"; $tone t0=$t0 start=5809 stop=5950 hz=980 tail=40; $mix t0=$t0 hold=$hold start=5950 stop=6689 voices="980|1180" seed=15 tail=10; $tone t0=$t0 start=6724 stop=6860 hz=1650 tail=40; $mix t0=$t0 hold=$hold start=6860 stop=7306 voices="1650|1850" seed=16 tail=10; $tone t0=$t0 start=7457 stop=7600 hz=980 tail=40; $mix t0=$t0 hold=$hold start=7600 stop=7937 voices="980|1180" seed=17 tail=10; # 8.2 s - ANSam. The 10ms breaks are its phase reversals, 450ms apart. :put "ANSam - 2100 Hz"; $tone t0=$t0 start=8186 stop=8626 hz=2100 tail=0; $tone t0=$t0 start=8636 stop=9076 hz=2100 tail=0; $tone t0=$t0 start=9086 stop=9332 hz=2100 tail=40; :put "CM - the calling menu, under the answer tone"; $mix t0=$t0 hold=$hold start=9332 stop=10450 voices="2100,980|1180" seed=18 tail=40; :put "JM - both menus at once"; $mix t0=$t0 hold=$hold start=10450 stop=11640 voices="980|1180,1650|1850" seed=19 tail=40; $mix t0=$t0 hold=$hold start=11640 stop=11698 voices="1650|1850" seed=20 tail=10; # 11.7 s - phase 2 under an 1800 Hz guard tone. :put "Phase 2 - INFO0, tone A 2400, tone B 1200"; $mix t0=$t0 hold=$hold start=11705 stop=11775 voices="1800,2000~2800" seed=21 tail=40; $mix t0=$t0 hold=$hold start=11775 stop=12050 voices="1800,2400,800~1600" seed=22 tail=40; $mix t0=$t0 hold=$hold start=12050 stop=12251 voices="1800,800~1600,2000~2800" seed=23 tail=40; $mix t0=$t0 hold=$hold start=12251 stop=12454 voices="1800,1200,2400" seed=24 tail=40; :put "L1/L2 - probing the line"; $tone t0=$t0 start=12454 stop=12861 hz=150 tail=40; $mix t0=$t0 hold=$hold start=12861 stop=12936 voices="1800,2400,1200" seed=25 tail=40; $tone t0=$t0 start=12936 stop=13028 hz=1200 tail=40; $tone t0=$t0 start=13028 stop=13480 hz=150 tail=40; :put "INFO1 - the results"; $mix t0=$t0 hold=$hold start=13480 stop=13600 voices="1800,2400,800~1600" seed=26 tail=40; $mix t0=$t0 hold=$hold start=13600 stop=13857 voices="1800,2400,800~1600,2000~2800" seed=27 tail=10; # 13.9 s - phase 3. A low square for rasp against a high tone for hiss. :put "Phase 3 - training"; $mix t0=$t0 hold=$hold start=13943 stop=14780 voices="150~700,1800~3700" seed=28 tail=40; $mix t0=$t0 hold=$hold start=14780 stop=16720 voices="150~600,1500~3300" seed=29 tail=40; $mix t0=$t0 hold=$hold start=16720 stop=20950 voices="150~700,1800~3700" seed=30 tail=40; # 21.0 s - the DIL, then a 111 Hz buzz and a 1350 Hz blip before phase 4. :put "DIL - the 63.5 Hz buzz"; $buzz t0=$t0 hold=$hold start=20950 stop=22900 hz=63 accent=127 period=79; $tone t0=$t0 start=22900 stop=23240 hz=111 tail=40; $mix t0=$t0 hold=$hold start=23240 stop=23423 voices="1350,150~600" seed=31 tail=40; # 23.4 s - data, until the modem mutes its speaker mid-noise. :put "Phase 4 and data"; $mix t0=$t0 hold=$hold start=23430 stop=26887 voices="150~700,1800~3700" seed=32 tail=10; :put "CONNECT - speaker off"; }