Midi to Csound code for Charles Cave as promised

[email protected] (Dave Turner) Fri, 20 Jun 2003 20:37:41 +0000
Newsgroups perl.midi
Message-ID <a05100304bb191df6a821@[81.174.192.245]>
Charles,

the code below works, and with more effort on my part would need no 
human intervention on the csound-ish file it produces. Great minds 
think alike, so far a number of years now I have been happily using 
note names in exactly the same way that Sean has in my csound include 
files so MIDI::number2note does exactly what I need it to.

I have no idea what a MUP file looks like, but now you have seen what 
I have done you should be able to work out what you need to do.

DaveT

#!perl
# midi2csound this converts the midi track to a Csound score
# and might in the future create a crude orc file to go with it
# using MacPerl 5.6.1r2 for Mac OS 9.2.2
  use warnings;
  use strict;
  use MIDI;

  my $DRIVE = 'Stuff:';
  my $PATH = 'temptemp:';
  my $MIDI = 'old_100th0.mid'; # I had to convert the type 1 midi file 
to a Type 0 midi file
  my $SCO = $MIDI.'.sco'; # needs code to remove the .mid and replace 
it with .sco
  my $BUF;

  my $IN_FILE = $DRIVE.$PATH.$MIDI;
  my $opus = MIDI::Opus->new({ 'from_file' => $IN_FILE });

  my $event_r = $opus->tracks_r->[0]->events_r;

  my $score_r = MIDI::Score::events_r_to_score_r($event_r);

=item MIDI vs Csound
the notes look like this:-
  ['note', 1006, 93, 2, 83, 123],
   'note', start_time, duration, channel, midi_note, velocity

csound looks like this:-
i1         0.17083      0.1500     220.00000    32131
instrument  start_time, duration, frequency, loudness


1) each channel is deemed to be one instrument, worry about patch changes later
2) we need to convert the midi note number to a frequency
    use the array @MIDI::number2note from MIDI.pm
			12_TET.sco will convert the note name to 
frequency for us
3) we need the number of ticks to calculate note durations
4) 32131 / 127 = 253
    so multiply the velocity by 253 to get loudness

the above line from MIDI score would become:-
i2    1006/ticks    93/ticks    83=B6    123*253

  $score_r IS the score I want to mess with.
  How do I get at it, 1 line at a time?

=cut
  $BUF = dump_score_to_file( $score_r);
  print "file $DRIVE$PATH$SCO created \n";


###########################################################################
sub dump_score_to_file {
   my $score_r = $_[0];
   open(OUT,">>", $DRIVE.$PATH.$SCO); # create or append newfile
   print OUT ";produced from $DRIVE$PATH$MIDI using midi2csound.pl \n" ;
   print OUT ";\@notes =    # ", scalar(@$score_r), " notes...\n";
   foreach my $note_r (@$score_r) {
     if ( ${ $note_r } [0] eq 'note' ) { # it is a note - deal with it
        print OUT 'i' ;
        print OUT ${ $note_r } [3] + 1; # channel number becomes 
instrument number
        print OUT '   ';
        print OUT ${ $note_r } [1] / 384; # note start time (yes 384 
is a 'magic' number!)
        print OUT '   ';
        print OUT ${ $note_r } [2] / 384; # note duration
        print OUT '   ';
        print OUT ( $MIDI::number2note{ ${ $note_r } [4] } ) ; # the actual note
        print OUT '   ';
        print OUT (${ $note_r } [5] * 253) ; # note loudness
        print OUT "\n";
     }
     else { # comment out anything not a note
        print OUT ';' ;
        print OUT " [", &MIDI::_dump_quote(@$note_r), "],\n" if @$note_r;
     }

   } # end of foreach
   print OUT "e \n";
   close(OUT);
   return;

} # end of sub dump_score_to_file
###########################################################################

  exit;