# Some constants from the BBC executable my $melodyoffset=0x4F00; my $melodyrefs=0x4E5D; my $endmelrefs=0x4E90; my $bbcbase=0x1100; # The melody is a set of segments define as the addresses listed at $melodyrefs. There is # a segment before those defined starting at the initial value of $melodyoffset # Within the segments are a set of value pairs # The first value is the BBC pitch value (which we'll convert to a midi value (see below) # The second is a duration # The end of segments is defined by the pitch value being 0xFF my $track1offset=0x4D00; my $track1parts=0x4e92; # One more than it appears since it's pre incremented open (INFILE,">24) & 0xFF); substr($trkbuffer,5,1)=chr(($tracklen>>16) & 0xFF); substr($trkbuffer,6,1)=chr(($tracklen>>8) & 0xFF); substr($trkbuffer,7,1)=chr(($tracklen) & 0xFF); $outbuffer=$outbuffer.$trkbuffer; # Track 2 header, we don't know the length now so set it to 0 $trkbuffer="MTrk".chr(0).chr(0).chr(0).chr(0); $tracklen=0; $count=0; $track1offset=0x4D00; # We don't use this for the sound but we do so we know when to reset $track1parts=0x4E92; # This is a very simple track my $track2offset=0x4D04; while ($track1offset != 0x4D50) { $bbcpitch=ord(substr($buffer,$track2offset-$bbcbase,1)); $bbcduration=2; #keydown, wait no ticks before doing it velocity of 0x50 (Made up value) $trkbuffer=$trkbuffer.chr(0); $trkbuffer=$trkbuffer.chr(0x90).chr($bbctomidi{$bbcpitch}).chr(0x50); #keyup, wait the duration before doing it $trkbuffer=$trkbuffer.chr($bbcduration*2).chr(0x80).chr($bbctomidi{$bbcpitch}).chr(0x50); $tracklen=$tracklen+8; $track2offset=$track2offset+1; #print $bbcpitch." ".$bbcduration."\n"; $count++; if ($count == 6 ) { $track1offset=0x4D00 + ord(substr($buffer,$track1parts-$bbcbase,1)); $track1parts=$track1parts+1; $count=0; $track2offset=0x4D04; } } substr($trkbuffer,4,1)=chr(($tracklen>>24) & 0xFF); substr($trkbuffer,5,1)=chr(($tracklen>>16) & 0xFF); substr($trkbuffer,6,1)=chr(($tracklen>>8) & 0xFF); substr($trkbuffer,7,1)=chr(($tracklen) & 0xFF); $outbuffer=$outbuffer.$trkbuffer; # Now the melody track $trkbuffer="MTrk".chr(0).chr(0).chr(0).chr(0); $tracklen=0; $count=0; while ($melodyrefs < $endmelrefs+2 ) { $bbcpitch=ord(substr($buffer,$melodyoffset-$bbcbase,1)); $bbcduration=ord(substr($buffer,($melodyoffset-$bbcbase)+1,1)); if ($bbcpitch != 0xFF) { #keydown, wait no ticks before doing it velocity of 0x50 (Made up value) if ($count !=0) { $trkbuffer=$trkbuffer.chr(0); } else { $trkbuffer=$trkbuffer.chr(24*2); # Pause before first note on this track } $trkbuffer=$trkbuffer.chr(0x90).chr($bbctomidi{$bbcpitch}).chr(0x50); #keyup, wait the duration before doing it $trkbuffer=$trkbuffer.chr($bbcduration*2).chr(0x80).chr($bbctomidi{$bbcpitch}).chr(0x50); $tracklen=$tracklen+8; $melodyoffset=$melodyoffset+2; $count++; } else { #print "Updating ref\n"; my $lb=ord(substr($buffer,$melodyrefs-$bbcbase,1)); my $hb=ord(substr($buffer,$melodyrefs-$bbcbase+1,1)); $melodyoffset= ($hb<<8) + $lb; #print $melodyoffset."\n"; $melodyrefs=$melodyrefs+2; } } substr($trkbuffer,4,1)=chr(($tracklen>>24) & 0xFF); substr($trkbuffer,5,1)=chr(($tracklen>>16) & 0xFF); substr($trkbuffer,6,1)=chr(($tracklen>>8) & 0xFF); substr($trkbuffer,7,1)=chr(($tracklen) & 0xFF); $outbuffer=$outbuffer.$trkbuffer; open (OUTFILE,">xor.mid"); binmode OUTFILE; print OUTFILE $outbuffer ; close OUTFILE;