#!/usr/bin/perl # echo __ ___ ._. ... . _._. ___ _.. . | morse2midi.pl > out.mid $input = join /\|/, <>; binmode (STDOUT); # Variable length values are split to 7-bit parts. If byte is greater or # equal to 0x80 (128 decimal) then the next byte is also part of the VLV, # else byte is the last byte in a VLV. # Conversion examples: # perl -e 'my $num=360; printf("0x%02X 0x%02X\n",(0x80|($num>>7)),(0x7F&$num));' # perl -e 'printf("%u\n",(((0x81 & 0x7F) << 7) | (0x68 & 0x7F)));' $dottime = pack ('C1', 0x78); # 120 $dashtime = pack ('C2', 0x82, 0x68); # 360 $interword = pack ('C2', 0x86, 0x48); # 840 $interletter = $dashtime; $intersymbol = $dottime; $sound = pack ('C3', 0x90, 0x4E, 0x7F); $nosound = pack ('C3', 0x80, 0x4E, 0x7F); # start making raw track: text, tempo meta events # first, time signature: $track = pack('C8', 0xFF, 0x58, 0x04, 0x01, 0x02, 0x18, 0x08, 0x00); # set tempo 0x0249f0 == 150000 $track .= pack('C7', 0xFF, 0x51, 0x03, 0x02, 0x49, 0xF0, 0x00); # set instrument name to "Sqrwave" $track .= (pack('C3', 0xFF, 0x04, 0x07) . "Sqrwave" . pack('C1', 0x00)); # change instrument to 0x50 $track .= pack('C2', 0xC0, 0x50); # no 0x00 delimiter! $etime = $interletter; foreach (split(//, $input)) { /\./ && (($track .= ($etime . $sound . $dottime . $nosound)), $etime = $intersymbol); /[_\-]/ && (($track .= ($etime . $sound . $dashtime . $nosound)), $etime = $intersymbol); / / && ($etime = $interletter); /\|/ && ($etime = $interword); } $track .= ($interword . $nosound); $track .= pack('C4', 0, 0xFF, 0x2F, 0); # write header print "MThd", # signature pack('Nn3', 6, # len 0x00000006 0, # format 0x0000 - single multi-channel track 1, # 0x0001 track(s) 0xF0); # number of delay ticks in a quarter-note # track header, raw track print "MTrk", # signature pack('NC1', length($track), 0), # track length and delimiter $track;