Morse code
It has been in use for more than 175 years — longer than any other electronic encoding system.



Task

Send a string as audible Morse code to an audio device   (e.g., the PC speaker).



As the standard Morse code does not contain all possible characters,
you may either ignore unknown characters in the file,
or indicate them somehow   (e.g. with a different pitch).




# This uses the GUI-free part of the Snack library
package require sound
 
# A simple pause while running the event loop, in terms of basic time units
proc pause n {
    global t
    after [expr {$t * $n}] set ok 1
    vwait ok
}
# Generate using a sine-wave filter
proc beep n {
    global frequency
    set f [snack::filter generator $frequency 30000 0.0 sine -1]
    set s [snack::sound -rate 22050]
    $s play -filter $f
    pause $n
    $s stop
    $s destroy
    $f destroy
    pause 1
}
# The dits and the dahs are just beeps of different lengths
interp alias {} dit {} beep 1
interp alias {} dah {} beep 3
 
set MORSE_CODE {
    "!" "---."	 "\"" ".-..-."	"$" "...-..-"	"'" ".----."
    "(" "-.--."	 ")" "-.--.-"	"+" ".-.-."	"," "--..--"
    "-" "-....-" "." ".-.-.-"	"/" "-..-."
    ":" "---..." ";" "-.-.-."	"=" "-...-"	"?" "..--.."
    "@" ".--.-." "[" "-.--."	"]" "-.--.-"	"_" "..--.-"
    "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" "--.."
}
 
# The code to translate text to morse code and play it
proc morse {str wpm} {
    global t MORSE_CODE
    set t [expr {1200 / $wpm}]
    # Backslash and space are special cases in various ways
    set map {"\\" {} " " {[pause 4]}}
    # Append each item in the code to the map, with an inter-letter pause after
    foreach {from to} $MORSE_CODE {lappend map $from "$to\[pause 3\]"}
    # Convert to dots and dashes
    set s [string map $map [string toupper $str]]
    # Play the dots and dashes by substituting commands for them
    subst [string map {"." [dit] "-" [dah]} $s]
    return
}
 
# We'll play at a fairly high pitch 
set frequency 700
 
morse "Morse code with Tcl and Snack." 20