From 760d4d5a0fc89e5b14681879577a80e79795e4a3 Mon Sep 17 00:00:00 2001 From: pepper Date: Mon, 19 Jan 2015 00:02:46 -0800 Subject: first --- midisep.pl | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100755 midisep.pl (limited to 'midisep.pl') diff --git a/midisep.pl b/midisep.pl new file mode 100755 index 0000000..ebd2f9d --- /dev/null +++ b/midisep.pl @@ -0,0 +1,161 @@ +#!/usr/bin/perl +use Data::Dumper; +use Cwd; + +our $DEBUG = 1; + +our $MIDICSV_BIN = Cwd::abs_path("midicsv-1.1/midicsv"); +our $CSVMIDI_BIN = Cwd::abs_path("midicsv-1.1/csvmidi"); + +our $CHANNEL_EVENTS = [ + 'Note_on_c', 'Note_off_c', 'Pitch_bend_c', 'Control_c', + 'Program_c', 'Channel_aftertouch_c', 'Poly_aftertouch_c', +]; + +our $SYSEX_EVENTS = [ + 'System_exclusive', 'System_exclusive_packet' +]; + + +sub usage{ + print STDERR sprintf('$>%s midifile [output_dir]'."\n", $0); + exit 1; +} + + + +sub error{ + my $msg = shift; + print STDERR $msg . "\n"; + exit(1); +} + +sub warn_sysex_found{ + my $event = shift; + my $warning = sprintf("Sysex event found on channel %s\n", $event->{channel}); + print STDERR $warning; +} + + +sub correct_bad_note_ons{ + my $event = shift; + if ($event->{type} =~ /Note_on/i && $event->{data}->[-1] == 0) { + $event->{type} = "Note_off_c"; + $event->{data}->[2] =~ s/on/off/i; + } + return $event; +} + +sub file_to_list{ + my $file = shift; + my $total_channels = shift; + my $csvdata = `$MIDICSV_BIN $file`; + my $list = [ + map { + chomp($_); + my $ctx = {}; + + my $line = [ split(',', $_ ) ]; + $ctx->{data} = $line; + $ctx->{type} = $line->[2]; + if (grep { $ctx->{type} =~ /$_/i } @$CHANNEL_EVENTS ){ + $ctx->{channel} = ($line->[3] =~ m/([0-9]+)/g)[0]; + if (!(grep { $ctx->{channel} == $_ } @$total_channels )){ + push(@$total_channels, $ctx->{channel}); + } + } +# [ @line ]; + $ctx; + } split('\n', $csvdata) ]; + return $list; +} + +sub add_to_all_outputs{ + my $event = shift; + my $output_files = shift; + foreach my $events (values %$output_files){ + push (@$events, join(',' , @{$event->{data}})); + }; +} + +sub add_to_single_output{ + my $event = shift; + my $output_files = shift; + push(@{$output_files->{$event->{channel}}}, join(',', @{$event->{data}})); +} + + +sub process_event_list{ + my $event_list = shift; + my $total_channels = shift; + my $output_data = {}; + + if ($event_list->[0]->{type} !~ /header/i){ + error("Bad header"); + } + #marker header as type0 + $event_list->[0]->{data}->[3] =~ s/[0-9]+/0/g; + + #check if file has more than one track/composition + my $tracks_count = $header->{data}->[4]; + if ($tracks_count > 1){ + error("Multiple tracks in same file, not yet implemented."); + } + foreach my $channel(@$total_channels){ + $output_data->{$channel} = []; + } + + #main loop + foreach $event(@$event_list){ + if ( grep { $event->{type} =~ /$_/i } @$CHANNEL_EVENTS ){ + $event = correct_bad_note_ons($event); + add_to_single_output( $event, $output_data ); + } + elsif ( grep { $event->{type} =~ /$_/i} @$SYSEX_EVENTS ){ + #consider adding special handle for sysex events + #currently just ignores them + warn_sysex_found ($event); + } + else { + add_to_all_outputs( $event, $output_data); + } + }; + + return $output_data; +} + + +sub data_to_files{ + my $output_data = shift; + my $filename_prefix = shift; + foreach my $channel (keys %$output_data){ + my $midi_filename = sprintf("%s-%s.mid", $filename_prefix, $channel); + my $csv_filename = sprintf("/tmp/%s-%s.csv", $filename_prefix, $channel); + open F, ">$csv_filename" or die $!; + print F (join("\n", @{$output_data->{$channel}})); + close(F); + system("$CSVMIDI_BIN $csv_filename $midi_filename"); + unlink($csv_filename); + } +} + +sub main{ + if (scalar(@ARGV) < 1){ + if ($DEBUG){ + print STDERR "DEBUG: using example.mid as default midifile\n"; + }else{ + usage; + } + } + + my $file = $ARGV[0] || "example.mid"; + my $output_dir = $ARGV[2] || "./"; + our $total_channels = []; + + our $filename_prefix = $output_dir . ($file =~ m/^(.+)\./g)[0]; + my $event_list = file_to_list ($file, $total_channels); + my $output_data = process_event_list ($event_list, $total_channels); + data_to_files($output_data, $filename_prefix); +# +}; +main; -- cgit v1.2.3-70-g09d2