--- /dev/null
+%{
+// midi-lexer.l
+
+
+#include "m2m.hh"
+#include "midi-parser.hh"
+
+%}
+
+%option c++
+%option noyywrap
+%option nodefault
+%option yylineno
+%option debug
+%option yyclass="My_midi_lexer"
+%option stack
+
+%x data
+%x event
+%x int8
+%x int16
+%x int32
+%x meta_event
+%x track
+
+INT8 [\x00-\xff]
+INT16 {INT8}{INT8}
+INT32 {INT16}{INT16}
+INT7_8UNSET [\x00-\x7f]
+INT7_8SET [\x80-\xff]
+VARINT {INT7_8SET}{0,3}{INT7_8UNSET}
+
+HEADER MThd
+TRACK MTrk
+
+XRUNNING_STATUS [\x30-\x4f]
+RUNNING_STATUS [\x00-\x5f]
+DATA_ENTRY [\x60-\x79]
+ALL_NOTES_OFF [\x7a-\x7f]
+NOTE_OFF [\x80-\x8f]
+NOTE_ON [\x90-\x9f]
+POLYPHONIC_AFTERTOUCH [\xa0-\xaf]
+CONTROLMODE_CHANGE [\xb0-\xbf]
+PROGRAM_CHANGE [\xc0-\xcf]
+CHANNEL_AFTERTOUCH [\xd0-\xdf]
+PITCHWHEEL_RANGE [\xe0-\xef]
+
+SYSEX_EVENT1 [\xf0]
+SYSEX_EVENT2 [\xf7]
+
+META_EVENT [\xff]
+
+SEQUENCE [\x00][\x02]
+YYTEXT [\x01]
+YYCOPYRIGHT [\x02]
+YYTRACK_NAME [\x03]
+YYINSTRUMENT_NAME [\x04]
+YYLYRIC [\x05]
+YYMARKER [\x06]
+YYCUE_POINT [\x07]
+
+END_OF_TRACK [\x2f][\x00]
+TEMPO [\x51][\x03]
+SMPTE_OFFSET [\x54][\x05]
+TIME [\x58][\x04]
+KEY [\x59][\x02]
+SSME [\0x7f][\x03]
+
+%%
+
+{HEADER}/{INT32} { // using /{INT32}; longer match than {INT32}
+ dtor << "lex: header" << endl;
+ yy_push_state( int16 );
+ yy_push_state( int16 );
+ yy_push_state( int16 );
+ yy_push_state( int32 );
+ return HEADER;
+}
+
+{TRACK}/{INT32} { // using /{INT32}; longer match than {INT32}
+ dtor << "lex: track" << endl;
+ yy_push_state( track );
+ yy_push_state( int32 );
+ return TRACK;
+}
+{INT8} {
+ error( String( "top level: illegal byte: " )
+ + String_convert::bin2hex_str( String( *YYText() ) ) );
+ exit( 1 );
+}
+<int32>{INT32} {
+ dtor << "lex: int32" << endl;
+ assert( YYLeng() == 4 );
+ String str( (Byte const*)YYText(), YYLeng() );
+ yylval.i = String_convert::bin2_i( str );
+ yy_pop_state();
+ return INT32;
+}
+<int16>{INT16} {
+ dtor << "lex: int16" << endl;
+ assert( YYLeng() == 2 );
+ String str( (Byte const*)YYText(), YYLeng() );
+ yylval.i = String_convert::bin2_i( str );
+ yy_pop_state();
+ return INT16;
+}
+<int8>{INT8} {
+ dtor << "lex: int8" << endl;
+ assert( YYLeng() == 1 );
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ return INT8;
+}
+
+<track>{VARINT} {
+ String str( (Byte const*)YYText(), YYLeng() );
+ yylval.i = My_midi_lexer::varint2_i( str );
+ dtor << String( "lex: track: varint(" )
+ + String( yylval.i ) + "): "
+ + String_convert::bin2hex_str( str ) << endl;
+ yy_push_state( event );
+ return VARINT;
+}
+<track>{INT8} {
+ error( String( "track: illegal byte: " )
+ + String_convert::bin2hex_str( String( *YYText() ) ) );
+ exit( 1 );
+}
+<event>{RUNNING_STATUS} {
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ dtor << String ( "lex: running status: " ) + String( yylval.i ) << endl;
+ yy_pop_state();
+// yy_push_state( int8 );
+ yy_push_state( int8 );
+ return RUNNING_STATUS;
+}
+<event>{DATA_ENTRY} {
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ dtor << String ( "lex: undefined data entry: " ) + String( yylval.i ) << endl;
+ yy_pop_state();
+ yy_push_state( int8 );
+ return DATA_ENTRY;
+}
+<event>{ALL_NOTES_OFF} {
+ dtor << "lex: all note off" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ dtor << String ( "lex: all notes off: " ) + String( yylval.i ) << endl;
+ yy_pop_state();
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ return ALL_NOTES_OFF;
+}
+<event>{NOTE_OFF} {
+ dtor << "lex: note off" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ return NOTE_OFF;
+}
+<event>{NOTE_ON} {
+ dtor << "lex: note on" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ return NOTE_ON;
+}
+<event>{POLYPHONIC_AFTERTOUCH} {
+ dtor << "lex: polyphonic aftertouch" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ return POLYPHONIC_AFTERTOUCH;
+}
+<event>{CONTROLMODE_CHANGE} {
+ dtor << "lex: controlmode change" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ return CONTROLMODE_CHANGE;
+}
+<event>{PROGRAM_CHANGE} {
+ dtor << "lex: program change" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_push_state( int8 );
+ return PROGRAM_CHANGE;
+}
+<event>{CHANNEL_AFTERTOUCH} {
+ dtor << "lex: channel aftertouch" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ return CHANNEL_AFTERTOUCH;
+}
+<event>{PITCHWHEEL_RANGE} {
+ dtor << "lex: pitchwheel range" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ return PITCHWHEEL_RANGE;
+}
+<event>{SYSEX_EVENT1} { // len data
+ dtor << "lex: sysex1" << endl;
+ yy_pop_state();
+ yy_push_state( data );
+ return SYSEX_EVENT1;
+}
+<event>{SYSEX_EVENT2} { // len data
+ dtor << "lex: sysex2" << endl;
+ yy_pop_state();
+// yy_push_state( int8 ); //?
+ yy_push_state( data );
+ return SYSEX_EVENT2;
+}
+<event>{META_EVENT} {
+ dtor << "lex: meta" << endl;
+ yy_push_state( meta_event );
+ return META_EVENT;
+}
+<event>{INT8} {
+ error( String( "event: illegal byte: " )
+ + String_convert::bin2hex_str( String( *YYText() ) ) );
+ exit( 1 );
+}
+<meta_event>{SEQUENCE} { // ssss sequence number
+ dtor << "lex: sequence" << endl;
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( int16 );
+ return SEQUENCE;
+}
+<meta_event>{YYTEXT} { // len data
+ dtor << "lex: text" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( data );
+ return YYTEXT;
+}
+<meta_event>{YYCOPYRIGHT} {
+ dtor << "lex: copyright" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( data );
+ return YYCOPYRIGHT;
+}
+<meta_event>{YYTRACK_NAME} {
+ dtor << "lex: track name" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( data );
+ return YYTRACK_NAME;
+}
+<meta_event>{YYINSTRUMENT_NAME} {
+ dtor << "lex: instrument name" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( data );
+ return YYINSTRUMENT_NAME;
+}
+<meta_event>{YYLYRIC} {
+ dtor << "lex: lyric" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( data );
+ return YYLYRIC;
+}
+<meta_event>{YYMARKER} {
+ dtor << "lex: marker" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( data );
+ return YYMARKER;
+}
+<meta_event>{YYCUE_POINT} {
+ dtor << "lex: cue point" << endl;
+// yylval.byte = *(Byte*)YYText();
+ yylval.i = *(Byte*)YYText();
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( data );
+ return YYCUE_POINT;
+}
+<meta_event>{TEMPO} { // tttttt usec
+ dtor << "lex: tempo" << endl;
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ return TEMPO;
+}
+<meta_event>{SMPTE_OFFSET} { // hr mn se fr ff
+ dtor << "lex: smpte offset" << endl;
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ return SMPTE_OFFSET;
+}
+<meta_event>{TIME} { // nn dd cc bb
+ dtor << "lex: time" << endl;
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ return TIME;
+}
+<meta_event>{KEY} { // sf mi
+ dtor << "lex: key" << endl;
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ return KEY;
+}
+<meta_event>{SSME} { // len data
+ dtor << "lex: smme" << endl;
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( data );
+ return SSME;
+}
+<meta_event>{END_OF_TRACK} {
+ dtor << "lex: end of track" << endl;
+ yy_pop_state();
+ yy_pop_state();
+ yy_pop_state();
+ return END_OF_TRACK;
+}
+<meta_event>{INT8} {
+ warning( String( "meta_event: unimplemented event: " )
+ + String_convert::bin2hex_str( String( *YYText() ) ),
+ this->here_ch_c_l() );
+ yy_pop_state();
+ yy_pop_state();
+ yy_push_state( int8 );
+ yy_push_state( int8 );
+ return INT8;
+}
+
+<data>{VARINT} {
+ dtor << "lex: data" << endl;
+ String str( (Byte const*)YYText(), YYLeng() );
+ int i = My_midi_lexer::varint2_i( str );
+ String* str_p = new String;
+ while ( i-- )
+ *str_p += (char)yyinput();
+ yylval.str_p = str_p;
+ yy_pop_state();
+ return DATA;
+}
+<data>{INT8} {
+ error( String( "data: illegal byte: " )
+ + String_convert::bin2hex_str( String( *YYText() ) ) );
+ exit( 1 );
+}
+
+<<EOF>> {
+// mtor << "<<EOF>>";
+
+ if ( !close_i() )
+ yyterminate(); // can't move this, since it actually rets a YY_NULL
+}
+
+%%
+
--- /dev/null
+%{
+
+#include "m2m.hh"
+
+#ifndef NDEBUG
+#define YYDEBUG 1
+#endif
+
+%}
+
+%union {
+ Byte byte;
+ char c;
+ int i;
+ String* str_p;
+ Request* request_p;
+ Midi_event* midi_event_p; // Voice_element* ?
+ Midi_score* midi_score_p; // Input_score* ?
+ Midi_track* midi_track_p; // Input_music* ?
+}
+
+%token HEADER TRACK
+%token SYSEX_EVENT1 SYSEX_EVENT2
+%token META_EVENT
+%token SEQUENCE
+%token END_OF_TRACK TEMPO SMPTE_OFFSET TIME KEY SSME
+
+%token<i> INT8 INT16 INT32 INT7_8UNSET INT7_8SET VARINT
+%token<i> RUNNING_STATUS DATA_ENTRY ALL_NOTES_OFF
+%token<i> NOTE_OFF NOTE_ON
+%token<i> POLYPHONIC_AFTERTOUCH CONTROLMODE_CHANGE PROGRAM_CHANGE
+%token<i> CHANNEL_AFTERTOUCH PITCHWHEEL_RANGE
+%token<i> YYTEXT YYCOPYRIGHT YYTRACK_NAME YYINSTRUMENT_NAME YYLYRIC YYMARKER YYCUE_POINT
+%token<str_p> DATA
+
+%type <i> varint
+%type <midi_score_p> header midi_score
+%type <midi_track_p> track
+%type <midi_event_p> event
+%type <midi_event_p> the_event meta_event the_meta_event text_event midi_event sysex_event
+%type <midi_event_p> running_status data_entry all_notes_off
+%type <midi_event_p> note_off note_on
+%type <midi_event_p> polyphonic_aftertouch controlmode_change program_change
+%type <midi_event_p> channel_aftertouch pitchwheel_range
+
+%%
+
+midi: /* empty */
+ | midi midi_score {
+ midi_parser_l_g->add_score( $2 );
+ }
+ ;
+
+midi_score:
+ header {
+ }
+ | midi_score track {
+ $$->add_track( $2 );
+ if ( midi_parser_l_g->copyright_str_.length_i() )
+ $2->copyright_str_ = midi_parser_l_g->copyright_str_;
+ if ( midi_parser_l_g->track_name_str_.length_i() )
+ $2->name_str_ = midi_parser_l_g->track_name_str_;
+ if ( midi_parser_l_g->instrument_str_.length_i() )
+ $2->instrument_str_ = midi_parser_l_g->instrument_str_;
+ midi_parser_l_g->reset();
+ }
+ ;
+
+header:
+ HEADER INT32 INT16 INT16 INT16 {
+ $$ = new Midi_score( $3, $4, $5 );
+ midi_parser_l_g->set_division_4( $5 );
+ }
+ ;
+
+track:
+ TRACK INT32 {
+ $$ = new Midi_track( midi_parser_l_g->track_i_++,
+ // silly, cause not set yet!
+ midi_parser_l_g->copyright_str_,
+ midi_parser_l_g->track_name_str_,
+ midi_parser_l_g->instrument_str_ );
+ }
+ | track event {
+ $$->add_event( midi_parser_l_g->mom(), $2 );
+ }
+ ;
+
+event:
+ varint the_event {
+ $$ = $2;
+ if ( $2 ) {
+ String str = $2->mudela_str( false );
+ if ( str.length_i() )
+ dtor << str << " " << flush;
+ }
+ }
+ ;
+
+varint:
+ VARINT {
+ midi_parser_l_g->forward( $1 );
+ }
+ ;
+
+the_event:
+ meta_event {
+ }
+ | midi_event {
+ }
+ | sysex_event {
+ }
+ ;
+
+meta_event:
+ META_EVENT the_meta_event {
+ $$ = $2;
+ }
+ |
+ META_EVENT INT8 INT8 INT8 {
+ $$ = 0;
+ }
+ ;
+
+the_meta_event:
+ SEQUENCE INT16 {
+ }
+ | text_event DATA {
+ Midi_text::Type type = (Midi_text::Type)$1;
+ $$ = 0;
+ switch ( type )
+ {
+ case Midi_text::COPYRIGHT:
+ midi_parser_l_g->copyright_str_ = *$2;
+ break;
+ case Midi_text::TRACK_NAME:
+ midi_parser_l_g->track_name_str_ = *$2;
+ while ( midi_parser_l_g->track_name_str_.index_i( ' ' ) != -1 )
+ *(midi_parser_l_g->track_name_str_.ch_l() + midi_parser_l_g->track_name_str_.index_i( ' ' ) ) = '_';
+ break;
+ case Midi_text::INSTRUMENT_NAME:
+ midi_parser_l_g->instrument_str_ = *$2;
+ break;
+ default:
+ $$ = new Midi_text( type, *$2 );
+ break;
+ }
+ dtor << *$2 << endl;
+ delete $2;
+ }
+ | END_OF_TRACK {
+ $$ = 0;
+ }
+ | TEMPO INT8 INT8 INT8 {
+ $$ = new Midi_tempo( ( $2 << 16 ) + ( $3 << 8 ) + $4 );
+ dtor << $$->mudela_str( false ) << endl;
+ midi_parser_l_g->set_tempo( ( $2 << 16 ) + ( $3 << 8 ) + $4 );
+ }
+ | SMPTE_OFFSET INT8 INT8 INT8 INT8 INT8 {
+ $$ = 0;
+ }
+ | TIME INT8 INT8 INT8 INT8 {
+ $$ = new Midi_time( $2, $3, $4, $5 );
+ dtor << $$->mudela_str( true ) << endl;
+ midi_parser_l_g->set_time( $2, $3, $4, $5 );
+ }
+ | KEY INT8 INT8 {
+ $$ = new Midi_key( $2, $3 );
+ midi_parser_l_g->set_key( $2, $3 );
+ }
+ | SSME DATA {
+ $$ = new Midi_text( (Midi_text::Type)0, *$2 );
+ delete $2;
+ }
+ ;
+
+text_event:
+ YYTEXT {
+ dtor << "\n% Text: ";
+ }
+ | YYCOPYRIGHT {
+ dtor << "\n% Copyright: ";
+ }
+ | YYTRACK_NAME {
+ dtor << "\n% Track name: ";
+ }
+ | YYINSTRUMENT_NAME {
+ dtor << "\n% Instrument name: ";
+ }
+ | YYLYRIC {
+ dtor << "\n% Lyric: ";
+ }
+ | YYMARKER {
+ dtor << "\n% Marker: ";
+ }
+ | YYCUE_POINT {
+ dtor << "\n% Cue point: ";
+ }
+ ;
+
+midi_event:
+ running_status {
+ }
+ | data_entry {
+ }
+ | all_notes_off {
+ }
+ | note_off {
+ }
+ | note_on {
+ }
+ | polyphonic_aftertouch {
+ }
+ | controlmode_change {
+ }
+ | program_change {
+ }
+ | channel_aftertouch {
+ }
+ | pitchwheel_range {
+ }
+ ;
+
+running_status:
+ RUNNING_STATUS INT8 { //INT8 {
+ $$ = 0;
+ }
+ ;
+
+data_entry:
+ DATA_ENTRY INT8 {
+ $$ = 0;
+ }
+ ;
+
+all_notes_off:
+ ALL_NOTES_OFF INT8 INT8 {
+ $$ = 0;
+ }
+ ;
+
+note_off:
+ NOTE_OFF INT8 INT8 {
+ int i = $1;
+ i = i & ~0x80;
+ $$ = midi_parser_l_g->note_end_midi_event_p( $1 & ~0x80, $2, $3 );
+ }
+ ;
+
+note_on:
+ NOTE_ON INT8 INT8 {
+ int i = $1;
+ i = i & ~0x90;
+ $$ = 0;
+ midi_parser_l_g->note_begin( $1 & ~0x90, $2, $3 );
+ }
+ ;
+
+polyphonic_aftertouch:
+ POLYPHONIC_AFTERTOUCH INT8 INT8 {
+ $$ = 0;
+ }
+ ;
+
+controlmode_change:
+ CONTROLMODE_CHANGE INT8 INT8 {
+ $$ = 0;
+ }
+ ;
+
+program_change:
+ PROGRAM_CHANGE INT8 {
+ $$ = 0;
+ }
+ ;
+
+channel_aftertouch:
+ CHANNEL_AFTERTOUCH INT8 INT8 {
+ $$ = 0;
+ }
+ ;
+
+pitchwheel_range:
+ PITCHWHEEL_RANGE INT8 INT8 {
+ $$ = 0;
+ }
+ ;
+
+sysex_event:
+ SYSEX_EVENT1 DATA {
+ $$ = 0;
+ }
+ | SYSEX_EVENT2 DATA { // INT8 ?
+ $$ = 0;
+ }
+ ;
--- /dev/null
+//
+// midi-score.cc -- implement Midi_score
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include "m2m.hh"
+
+Midi_score::Midi_score( int format_i, int tracks_i, int tempo_i )
+{
+ format_i_ = format_i;
+ tracks_i_ = tracks_i;
+ tempo_i_ = tempo_i;
+}
+
+Midi_score::~Midi_score()
+{
+}
+
+void
+Midi_score::add_track( Midi_track* midi_track_p )
+{
+ midi_track_p_list_.bottom().add( midi_track_p );
+}
+
+int
+Midi_score::output_mudela( String filename_str )
+{
+ mtor << "Lily output to " << filename_str << " ..." << endl;
+
+ Lily_stream lily_stream( filename_str );
+ for ( PCursor<Midi_track*> midi_track_l_pcur( midi_track_p_list_.top() ); midi_track_l_pcur.ok(); midi_track_l_pcur++ ) {
+ midi_track_l_pcur->output_mudela( lily_stream );
+ lily_stream.newline();
+ }
+
+ lily_stream << "score {";
+ lily_stream.newline();
+
+ for ( PCursor<Midi_track*> midi_track_l_pcur( midi_track_p_list_.top() ); midi_track_l_pcur.ok(); midi_track_l_pcur++ ) {
+ lily_stream << "\tstaff { melodic music { ";
+ lily_stream << midi_track_l_pcur->name_str();
+ lily_stream << " } }";
+ lily_stream.newline();
+ }
+
+ lily_stream.indent();
+ lily_stream << "commands {";
+ lily_stream.indent();
+ midi_parser_l_g->midi_time_p_->output_mudela( lily_stream, true );
+ lily_stream.tnedni();
+ lily_stream << "}";
+ lily_stream.newline();
+ lily_stream << "midi {";
+ lily_stream.indent();
+ midi_parser_l_g->midi_tempo_p_->output_mudela( lily_stream, true );
+ lily_stream.tnedni();
+ lily_stream << "}";
+ lily_stream.tnedni();
+
+ lily_stream << "}";
+ lily_stream.newline();
+
+ return 0;
+}
+
+void
+Midi_score::process()
+{
+ for ( PCursor<Midi_track*> i( midi_track_p_list_.top() ); i.ok(); i++ )
+ i->process();
+}
+
--- /dev/null
+//
+// midi-track.cc -- implement Midi_track
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include "m2m.hh"
+
+Midi_track::Midi_track( int number_i, String copyright_str, String track_name_str, String instrument_str )
+{
+ number_i_ = number_i;
+ copyright_str_ = copyright_str;
+ instrument_str_ = instrument_str;
+ if ( track_name_str.length_i() )
+ name_str_ = track_name_str;
+ else
+ name_str_ = String( "track" ) + String( number_i_ );
+ tcol_p_list_.bottom().add( new Track_column( Moment( 0 ) ) );
+}
+
+void
+Midi_track::add_begin_at( PointerList<Midi_voice*>& open_voices_r, Moment mom )
+{
+ for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
+ if ( i->begin_mom() == mom )
+ open_voices_r.bottom().add( *i );
+}
+
+void
+Midi_track::add_event( Moment mom, Midi_event* midi_event_p )
+{
+ if ( ! midi_event_p )
+ return;
+ tcol_l( mom - midi_event_p->mom() )->add_event( midi_event_p );
+}
+
+// too much red tape?
+String
+Midi_track::name_str()
+{
+ return name_str_;
+}
+
+Moment
+Midi_track::end_mom()
+{
+ // heu..
+ Moment mom = 0.0;
+ for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
+ mom = i->end_mom() >? mom;
+ return mom;
+}
+
+Midi_voice*
+Midi_track::get_free_midi_voice_l( Moment mom )
+{
+ for ( PCursor<Midi_voice*> midi_voice_l_pcur( midi_voice_p_list_.top() ); midi_voice_l_pcur.ok(); midi_voice_l_pcur++ )
+ if ( midi_voice_l_pcur->end_mom() == mom )
+ return *midi_voice_l_pcur;
+
+ Midi_voice* midi_voice_p = new Midi_voice( mom );
+ Midi_voice* midi_voice_l = midi_voice_p;
+ midi_voice_p_list_.bottom().add( midi_voice_p );
+ return midi_voice_l;
+}
+
+Moment
+Midi_track::next_begin_mom( Moment now_mom )
+{
+// Moment begin_mom = Midi_track::end_mom() + 1;
+ Moment begin_mom = Midi_track::end_mom();
+ for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
+// if ( i->begin_mom() >= now_mom )
+ if ( i->begin_mom() > now_mom )
+ begin_mom = begin_mom <? i->begin_mom();
+ return begin_mom;
+}
+
+Moment
+Midi_track::next_end_mom( Moment now_mom )
+{
+ Moment end_mom = Midi_track::end_mom();
+ for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
+ if ( i->end_mom() > now_mom )
+ end_mom = end_mom <? i->end_mom();
+ return end_mom;
+}
+
+void
+Midi_track::process()
+{
+ for ( PCursor<Track_column*> tcol_l_pcur( tcol_p_list_.top() ); tcol_l_pcur.ok(); tcol_l_pcur++ )
+ while ( tcol_l_pcur->midi_event_p_list_.size() )
+ // shit, where has the T* PCursor::remove() gone??
+ // i don-t want to get and delete,
+ // i want to (re)move!
+ // is it renamed: get vs add/insert ?? (put/remove :-)
+ get_free_midi_voice_l( tcol_l_pcur->mom() )->add_event( tcol_l_pcur->midi_event_p_list_.top().remove_p() );
+
+ dtor << "ends: " << endl;
+ int n = 0;
+ for ( PCursor<Midi_voice*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
+ vtor << "voice " << n++ << ": " << i->end_mom() << endl;
+ dtor << ":sdne" << endl;
+}
+
+
+void
+Midi_track::output_mudela( Lily_stream& lily_stream_r )
+{
+ lily_stream_r << name_str_ << " = music { $";
+ lily_stream_r.indent();
+ lily_stream_r << "% midi copyright:" << copyright_str_;
+ lily_stream_r.newline();
+ lily_stream_r << "% instrument:" << instrument_str_;
+ lily_stream_r.newline();
+
+ PointerList<Midi_voice*> open_voices;
+ Moment now_mom = 0.0;
+ Moment then_mom = 0.0;
+ while ( now_mom < end_mom() ) {
+ add_begin_at( open_voices, now_mom );
+
+ Moment begin_mom = next_begin_mom( now_mom );
+ Moment end_mom = next_end_mom( now_mom );
+ if ( ( begin_mom > now_mom ) && ( begin_mom < end_mom ) )
+ then_mom = begin_mom;
+ else
+ then_mom = end_mom;
+
+ dtor << "begin: " << begin_mom << " end: " << end_mom << endl;
+ dtor << "slice: " << now_mom << ", " << then_mom << endl;
+
+ if ( open_voices.size() > 1 )
+ lily_stream_r << "{ ";
+ for ( PCursor<Midi_voice*> i( open_voices.top() ); i.ok(); i++ )
+ lily_stream_r << i->mudela_str( now_mom, then_mom, open_voices.size() - 1 );
+ if ( open_voices.size() > 1 )
+ lily_stream_r << "} ";
+ now_mom = then_mom;
+
+ remove_end_at( open_voices, now_mom );
+ }
+ lily_stream_r.tnedni();
+ lily_stream_r << "$} % " << name_str_;
+ lily_stream_r.newline();
+}
+
+void
+Midi_track::remove_end_at( PointerList<Midi_voice*>& open_voices_r, Moment mom )
+{
+ for ( PCursor<Midi_voice*> i( open_voices_r.top() ); i.ok(); i++ )
+ if ( i->end_mom() == mom ) {
+ i.remove_p(); // remove? // no delete; only a copy
+ if ( !i.ok() )
+ break;
+ }
+// i.del(); // remove? // no delete; only a copy
+// plist is breendet
+// duh, del and get will do a ++, but will fail if they render list empty
+// if ( i->end_mom() == mom ) {
+// if ( i->size() > 1 )
+// i.del();
+// else
+// i.junk(); // what-s in a name? (sic)
+// }
+}
+
+Track_column*
+Midi_track::tcol_l( Moment mom )
+{
+ for ( PCursor<Track_column*> tcol_l_pcur( tcol_p_list_.top() ); tcol_l_pcur.ok(); tcol_l_pcur++ ) {
+ if ( tcol_l_pcur->mom() == mom )
+ return *tcol_l_pcur;
+ if ( tcol_l_pcur->mom() > mom ) {
+ Track_column* tcol_p = new Track_column( mom );
+ tcol_l_pcur.insert( tcol_p );
+ return tcol_p;
+ }
+ }
+
+ Track_column* tcol_p = new Track_column( mom );
+ tcol_p_list_.bottom().add( tcol_p );
+ return tcol_p;
+}
+
--- /dev/null
+//
+// midi-voice.cc -- implement midi_voice
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include "m2m.hh"
+
+Midi_voice::Midi_voice( Moment begin_mom )
+{
+ begin_mom_ = begin_mom;
+}
+
+void
+Midi_voice::add_event( Midi_event* midi_event_p )
+{
+ midi_event_p_list_.bottom().add( midi_event_p );
+}
+
+Moment
+Midi_voice::begin_mom()
+{
+ return begin_mom_;
+}
+
+Moment
+Midi_voice::end_mom()
+{
+ Moment now_mom = begin_mom_;
+ dtor << now_mom << ", ";
+ for ( PCursor<Midi_event*> i( midi_event_p_list_.top() ); i.ok(); i++ ) {
+ dtor << now_mom << ", ";
+ now_mom += i->mom();
+ }
+ dtor << endl;
+ return now_mom;
+}
+
+String
+Midi_voice::mudela_str( Moment from_mom, Moment to_mom, bool multiple_bo )
+{
+ String str;
+
+ if ( begin_mom() >= to_mom )
+ return "";
+ if ( end_mom() <= from_mom )
+ return "";
+
+ Moment now_mom = begin_mom();
+ PCursor<Midi_event*> i( midi_event_p_list_.top() );
+ for ( ; i.ok() && now_mom < from_mom ; i++ )
+ now_mom += i->mom();
+
+ for ( ; i.ok() && now_mom < to_mom ; i++ ) {
+ now_mom += i->mom();
+ str += i->mudela_str( false ) + " ";
+ }
+
+ if ( str.length_i() && multiple_bo )
+ str = "\\music{ " + str + "} ";
+ return str;
+}
+
--- /dev/null
+//
+// my-midi-lexer.cc -- implement My_midi_lexer
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include "m2m.hh"
+
+int
+yylex()
+{
+ return midi_lexer_l_g->yylex();
+}
+
+My_midi_lexer* midi_lexer_l_g = 0;
+
+My_midi_lexer::My_midi_lexer( String filename_str )
+{
+ midi_lexer_l_g = this;
+ input_file_p_ = new Input_file( filename_str );
+ switch_streams( input_file_p_->is );
+ errorlevel_i_ = 0;
+}
+
+My_midi_lexer::~My_midi_lexer()
+{
+ delete input_file_p_;
+ midi_lexer_l_g = 0;
+}
+
+void
+My_midi_lexer::error( char const* sz_l )
+{
+ if ( !input_file_p_ ) {
+// *mlog << "error at EOF" << sz_l << '\n';
+ cerr << "error at EOF" << sz_l << '\n';
+ } else {
+ char const* ch_c_l = here_ch_c_l();
+ if ( ch_c_l ) {
+ ch_c_l--;
+ while ( ( *ch_c_l == ' ' ) || ( *ch_c_l == '\t' ) || ( *ch_c_l == '\n' ) )
+ ch_c_l--;
+ ch_c_l++;
+ }
+ errorlevel_i_ |= 1;
+// ::error( sz_l, ch_c_l );
+ ::error( sz_l, ch_c_l );
+ }
+}
+
+char const*
+My_midi_lexer::here_ch_c_l()
+{
+ return input_file_p_->sourcefile_l_->ch_c_l() + yyin->tellg();
+}
+
+int
+My_midi_lexer::varint2_i( String str )
+{
+ int var_i = 0;
+
+ for ( int i = 0; i < str.length_i(); i++ ) {
+ Byte byte = str[ i ];
+ var_i <<= 7;
+ var_i += byte & 0x7f;
+ if ( ! ( byte & 0x80 ) )
+ return var_i;
+ }
+ cout << "\nvarint2_i:" << String_convert::bin2hex_str( str ) << endl;
+ assert( 0 ); // illegal varint
+ return 0;
+}
+
+int
+My_midi_lexer::close_i()
+{
+ return 0;
+}
+
--- /dev/null
+//
+// my-midi-parser.cc -- implement My_midi_parser
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include "m2m.hh"
+
+void
+yyerror(char const* sz_l )
+{
+ midi_parser_l_g->error( sz_l );
+}
+
+
+My_midi_parser* midi_parser_l_g = 0;
+
+My_midi_parser::My_midi_parser( String filename_str )
+{
+ midi_parser_l_g = this;
+ filename_str_ = filename_str;
+ midi_lexer_p_ = new My_midi_lexer( filename_str_ );
+ defined_ch_c_l_ = 0;
+ fatal_error_i_ = 0;
+ midi_key_p_ = 0;
+ midi_score_p_ = 0;
+ midi_tempo_p_ = 0;
+ midi_time_p_ = 0;
+ track_i_ = 0;
+ reset();
+}
+
+My_midi_parser::~My_midi_parser()
+{
+ delete midi_lexer_p_;
+ midi_parser_l_g = 0;
+ delete midi_key_p_;
+ delete midi_tempo_p_;
+ delete midi_time_p_;
+ delete midi_score_p_;
+}
+
+void
+My_midi_parser::reset()
+{
+ delete midi_key_p_;
+ midi_key_p_ = new Midi_key( 0, 0 );
+ // useconds per 4: 250000 === 60 4 per minute
+ delete midi_tempo_p_;
+ midi_tempo_p_ = new Midi_tempo( 250000 );
+ delete midi_time_p_;
+ midi_time_p_ = new Midi_time( 4, 4, 384, 8 );
+ now_i64_ = 0;
+
+ copyright_str_ = "";
+ track_name_str_ = "";
+ instrument_str_ = "";
+
+ for ( int i = 0; i < CHANNELS_i; i++ )
+ for ( int j = 0; j < PITCHES_i; j++ )
+// running_i64_i64_a_[ i ][ j ] = -1;
+ running_i64_i64_a_[ i ][ j ] = 0;
+}
+
+void
+My_midi_parser::add_score( Midi_score* midi_score_p )
+{
+ assert( !midi_score_p_ );
+ midi_score_p_ = midi_score_p;
+ track_i_ = 0;
+}
+
+void
+My_midi_parser::error( char const* sz_l )
+{
+ midi_lexer_l_g->error( sz_l );
+
+ if ( fatal_error_i_ )
+ exit( fatal_error_i_ );
+}
+
+void
+My_midi_parser::forward( int i )
+{
+ now_i64_ += i;
+}
+
+Moment
+My_midi_parser::mom()
+{
+ return Duration_convert::i2_mom( now_i64_, division_1_i_ );
+}
+
+void
+My_midi_parser::note_begin( int channel_i, int pitch_i, int dyn_i )
+{
+ // one pitch a channel at time!
+ // heu, what about { < c2 > < c4 d4 > }
+// assert( running_i64_i64_a_[ channel_i ][ pitch_i ] == -1 );
+ running_i64_i64_a_[ channel_i ][ pitch_i ] = now_i64_;
+}
+
+Midi_event*
+My_midi_parser::note_end_midi_event_p( int channel_i, int pitch_i, int dyn_i )
+{
+ Int64 start_i64 = running_i64_i64_a_[ channel_i ][ pitch_i ];
+
+// running_i64_i64_a_[ channel_i ][ pitch_i ] = -1;
+// assert( start_i64 != -1 ); // did we start?
+
+ return new Midi_note( midi_key_p_->notename_str( pitch_i ), midi_time_p_->i2_dur( now_i64_ - start_i64, division_1_i_ ) );
+}
+
+int
+My_midi_parser::output_mudela( String filename_str )
+{
+ assert( midi_score_p_ );
+ midi_score_p_->process();
+ return midi_score_p_->output_mudela( filename_str );
+}
+
+int
+My_midi_parser::parse()
+{
+ return ::yyparse();
+}
+
+void
+My_midi_parser::set_division_4( int division_4_i )
+{
+ division_1_i_ = division_4_i * 4;
+ if ( division_4_i < 0 )
+ warning( "seconds iso metrical time" , 0 );
+}
+
+void
+My_midi_parser::set_key( int accidentals_i, int minor_i )
+{
+ delete midi_key_p_;
+ midi_key_p_ = new Midi_key( accidentals_i, minor_i );
+}
+
+void
+My_midi_parser::set_tempo( int useconds_i )
+{
+ delete midi_tempo_p_;
+ midi_tempo_p_ = new Midi_tempo( useconds_i );
+}
+
+void
+My_midi_parser::set_time( int num_i, int den_i, int clocks_i, int count_32_i )
+{
+ delete midi_time_p_;
+ midi_time_p_ = new Midi_time( num_i, den_i, clocks_i, count_32_i );
+}
+
--- /dev/null
+//
+// track-column.cc -- implement Track_column
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include "m2m.hh"
+
+Track_column::Track_column( Moment mom )
+{
+ mom_ = mom;
+}
+
+void
+Track_column::add_event( Midi_event* midi_event_p )
+{
+ midi_event_p_list_.bottom().add( midi_event_p );
+}
+
+Moment
+Track_column::mom()
+{
+ return mom_;
+}