Skip to main content
2 of 6
Shaved off 1 byte
Matteo Italia
  • 3.8k
  • 1
  • 16
  • 22

x86 machine code (.COM file): 121 120 bytes

Hexdump:

00000000  b4 3e bb 01 00 cd 21 b4  3c 31 c9 ba 47 01 cd 21  |.>....!.<1..G..!|
00000010  42 b4 09 cd 21 be 61 01  81 fe 78 01 0f 84 e0 fe  |B...!.a...x.....|
00000020  31 c0 8a 04 46 88 c3 80  e3 03 89 c1 c1 e1 05 e8  |1...F...........|
00000030  0a 00 30 db b9 40 06 e8  02 00 eb dc 30 d2 b4 02  |[email protected]...|
00000040  00 da cd 21 e2 fa c3 61  2e 73 6e 64 00 00 00 18  |...!...a.snd....|
00000050  ff ff ff ff 00 00 00 02  00 00 1f 40 00 00 00 01  |...........@....|
00000060  24 33 33 97 97 97 64 97  97 97 97 97 64 33 97 97  |$33...d.....d3..|
00000070  97 97 64 33 33 33 33 33                           |..d33333|

Can be easily run under DosBox; the output is a .SND file named a.snd. Here is a FLAC version of its output (and here the .COM file).

Commented assembly:

    org 100h

start:
    ; close stdout
    mov ah,3eh
    mov bx,1
    int 21h
    ; open a.snd
    mov ah,3ch
    xor cx,cx
    mov dx,filename
    int 21h
    ; write the header
    inc dx
    mov ah,9h
    int 21h
    mov si,data
.l:
    ; data read cycle
    ; quit if we reached the end of data
    cmp si,eof
    je 0
    ; read the current byte in ax (zero-extending to 16-bit)
    xor ax,ax
    mov al,[si]
    ; move to next byte
    inc si
    ; bl: ramp increment per sample; take the low 2 bits
    mov bl,al
    and bl,3
    ; cx: length of the wave in # samples; high 6 bits, right shifted of 5
    mov cx,ax
    shl cx,5
    ; generate the tone
    call gen
    ; generate the pause
    xor bl,bl
    mov cx,1600
    call gen
    ; rinse and repeat
    jmp .l

gen:
    ; generate a sawtooth wave
    ; receives length (in samples) in cx, ramp increment in bl
    xor dl,dl
    mov ah,2h
.l:
    ; increment the signal
    add dl,bl
    ; write it
    int 21h
    ; decrement iteration count and loop
    loop .l
    ret

    ; here be the data
    ; used for the file name; we recycle the .snd from the beginning
    ; of the file header, exploiting the fact that it starts with a zero
filename:
    db "a"
header:
    ; .SND file header (8000 samples, mono, PCM)
    db ".snd",0,0,0,24,0xff,0xff,0xff,0xff,0,0,0,2,0,0,0x1f,0x40,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 2 bits: sawtooth wave increment per sample, upper 6 bits: sound length in samples >> 5) generated by a Python script:

#!/usr/bin/env python2
import sys

# source string
s = "..--- ----- .---- ....."
# samples
sr = 8000
conv =  {
            '.': 3 | (((sr/5) >> 5) & ~3),    # dot:   1/5 second, dI/dt=3
            '-': 3 | (((sr/5*3) >> 5) & ~3),  # line:  3/5 second, dI/dt=3
            ' ':     ((sr/5*2) >> 5) & ~3     # 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))
Matteo Italia
  • 3.8k
  • 1
  • 16
  • 22