# x86 machine code (.COM file): <del>121</del> <del>120</del> <del>113</del> 109 bytes

Hexdump:

    00000000  b4 3e bb 01 00 cd 21 b4  3c 31 c9 ba 3e 01 cd 21  |.>....!.<1..>..!|
    00000010  4a b4 09 cd 21 be 56 01  8a 0c 46 e8 0c 00 b1 32  |J...!.V...F....2|
    00000020  e8 07 00 81 fe 6d 01 75  ef c3 88 cb c0 e3 07 c1  |.....m.u........|
    00000030  e1 04 30 d2 b4 02 00 da  cd 21 e2 fa c3 2e 73 6e  |..0......!....sn|
    00000040  64 00 00 00 18 ff ff ff  ff 00 00 00 02 00 00 10  |d...............|
    00000050  00 00 00 00 01 24 33 33  99 99 99 66 99 99 99 99  |.....$33...f....|
    00000060  99 66 33 99 99 99 99 66  33 33 33 33 33           |.f3....f33333|
    0000006d

Can be easily run under DosBox; the output is a [.SND file][1] named `SND`. [Here is a FLAC version][2] of its output (and [here][3] the .COM file).

Commented assembly:

        org 100h
    
    start:
        ; close stdout
        mov ah,3eh
        mov bx,1
        int 21h
        ; open snd
        mov ah,3ch
        xor cx,cx
        mov dx,filename
        int 21h
        ; write the header
        ; we used the `snd` part of the header as file name, back off one byte
        dec dx
        mov ah,9h
        int 21h
        mov si,data
    .l:
        ; data read cycle
        ; read the current byte in cl (zero-extending to 16-bit)
        ; notice that ch is already zero (at the first iteration it's 0 from the
        ; int 21h/3ch, then we are coming from gen, which leaves cx to zero)
        mov cl,[si]
        ; move to next byte
        inc si
        ; generate the tone
        call gen
        ; generate the pause
        mov cl,50
        call gen
        ; repeat until we reach the end of data
        cmp si,eof
        jne .l
        ; quit
        ret
    
    gen:
        ; generate a sawtooth wave at sampling frequency/2 Hz
        ; receives length (in samples>>4) in cx, with lowest bit indicating if
        ; it has to write a wave or a pause
        mov bl,cl
        ; shift the rightmost bit all the way to the left; this kills the
        ; unrelated data and puts a 128 in bl (if cx & 1 != 0)
        shl bl,7
        ; rescale the samples number
        shl cx,4
        ; zero the starting signal
        xor dl,dl
        ; prepare the stuff for int 21h
        mov ah,2h
    .l:
        ; increment the signal
        add dl,bl
        ; write it
        int 21h
        ; decrement iteration count and loop
        loop .l
        ret
    
        ; .SND file header (4096 samples, mono, PCM)
    header:
        db "."
        ; we also use "snd" as the file name
    filename:
        db "snd",0,0,0,24,0xff,0xff,0xff,0xff,0,0,0,2,0,0,0x10,0,0,0,0,1
        ; terminator for int 21h/ah=9h
        db '$'
    data:
        ; generated by gendata.py
        incbin "data.dat"
    eof:

The `data.dat` included above is an easy-to-use representation of the morse string (lower bit: sound on/sound off, upper 7 bits: sound length in samples >> 4) generated by a Python script:

    #!/usr/bin/env python2
    import sys
    
    # source string
    s = "..--- ----- .---- ....."
    # samples
    sr = 4096
    conv =  {
                '.': 1 | (((sr/5) >> 4) & ~1),    # dot:   1/5 second, dI/dt=1
                '-': 1 | (((sr/5*3) >> 4) & ~1),  # line:  3/5 second, dI/dt=1
                ' ':     ((sr/5*2) >> 4) & ~1     # space: 2/5 second (+1/5 from the always-present pause), dI/dt=0 (silent)
            }
    sys.stdout.write(''.join(chr(conv[a]) for a in s))


  [1]: http://en.wikipedia.org/wiki/Au_file_format
  [2]: https://bitbucket.org/mitalia/pcg/downloads/morse.flac
  [3]: https://bitbucket.org/mitalia/pcg/downloads/morse.com