]> git.donarmstrong.com Git - lilypond.git/commitdiff
lilypond-0.0.40
authorfred <fred>
Mon, 10 Mar 1997 16:45:41 +0000 (16:45 +0000)
committerfred <fred>
Mon, 10 Mar 1997 16:45:41 +0000 (16:45 +0000)
21 files changed:
mi2mu/.version [new file with mode: 0644]
mi2mu/include/Makefile [new file with mode: 0644]
mi2mu/include/lily-stream.hh [new file with mode: 0644]
mi2mu/include/midi-event.hh [new file with mode: 0644]
mi2mu/include/midi-global.hh [new file with mode: 0644]
mi2mu/include/midi-score.hh [new file with mode: 0644]
mi2mu/include/midi-track.hh [new file with mode: 0644]
mi2mu/include/midi-voice.hh [new file with mode: 0644]
mi2mu/include/my-midi-lexer.hh [new file with mode: 0644]
mi2mu/include/my-midi-parser.hh [new file with mode: 0644]
mi2mu/include/track-column.hh [new file with mode: 0644]
mi2mu/lily-stream.cc [new file with mode: 0644]
mi2mu/midi-event.cc [new file with mode: 0644]
mi2mu/midi-lexer.l [new file with mode: 0644]
mi2mu/midi-parser.y [new file with mode: 0644]
mi2mu/midi-score.cc [new file with mode: 0644]
mi2mu/midi-track.cc [new file with mode: 0644]
mi2mu/midi-voice.cc [new file with mode: 0644]
mi2mu/my-midi-lexer.cc [new file with mode: 0644]
mi2mu/my-midi-parser.cc [new file with mode: 0644]
mi2mu/track-column.cc [new file with mode: 0644]

diff --git a/mi2mu/.version b/mi2mu/.version
new file mode 100644 (file)
index 0000000..1726cf2
--- /dev/null
@@ -0,0 +1,6 @@
+MAJOR_VERSION = 0
+MINOR_VERSION = 0
+PATCH_LEVEL = 2
+# use to send patches, always empty for released version:
+MY_PATCH_LEVEL = # include separator: "-1" or ".a"
+#
diff --git a/mi2mu/include/Makefile b/mi2mu/include/Makefile
new file mode 100644 (file)
index 0000000..cb4f4ea
--- /dev/null
@@ -0,0 +1,23 @@
+# lib/include/Makefile
+
+# subdir level:
+#
+depth = ../..
+#
+
+# identify module:
+#
+MODULE_NAME = lilypond
+MAJOR_VERSION = $(TOPLEVEL_MAJOR_VERSION)
+MINOR_VERSION = $(TOPLEVEL_MINOR_VERSION)
+PATCH_LEVEL = $(TOPLEVEL_PATCH_LEVEL)
+# use to send patches, always empty for released version:
+MY_PATCH_LEVEL = $(TOPLEVEL_MY_PATCH_LEVEL)
+build = ./$(depth)/lily/.build
+#
+
+# generic stuff/Makefile
+#
+include ./$(depth)/make/Include.make
+#
+
diff --git a/mi2mu/include/lily-stream.hh b/mi2mu/include/lily-stream.hh
new file mode 100644 (file)
index 0000000..8c6622d
--- /dev/null
@@ -0,0 +1,35 @@
+//
+//  lily-stream.hh -- part of LilyPond
+//
+//  copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+// should i be named Mudela_stream?
+
+#ifndef LILY_STREAM_HH
+#define LILY_STREAM_HH
+
+/// Lily output
+struct Lily_stream {
+    ostream* os_p_;
+    String filename_str_;
+    int indent_i_;
+    int column_i_;
+    int wrap_column_i_;
+    bool comment_mode_bo_;
+    
+    Lily_stream( String filename_str );
+    ~Lily_stream();
+
+    Lily_stream& operator <<( String str );
+    Lily_stream& operator <<( Midi_event& midi_event_r );
+
+    void check_comment( String str );
+    void header();
+    void indent();
+    void newline();
+    void open();
+    void tnedni();
+};
+
+#endif // LILY_STREAM_HH
+
diff --git a/mi2mu/include/midi-event.hh b/mi2mu/include/midi-event.hh
new file mode 100644 (file)
index 0000000..3f06353
--- /dev/null
@@ -0,0 +1,96 @@
+//
+// midi-event.hh -- declare midi_event
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#ifndef MIDI_EVENT_HH
+#define MIDI_EVENT_HH
+
+
+// should these:
+// * be Midi_items
+// * be Voice_elements/requests
+// * get a name-change
+// ?
+
+/// (midi_event)
+class Midi_event {
+public:
+       Midi_event();
+       
+       virtual String mudela_str( bool command_mode_bo ) = 0;
+       void output_mudela( Lily_stream& lily_stream_r, bool command_mode_bo );
+       virtual Moment mom();
+};
+
+class Midi_key : public Midi_event {
+public:
+       Midi_key( int accidentals_i, int minor_i );
+
+       String notename_str( int pitch_i );
+       virtual String mudela_str( bool command_mode_bo );
+
+private:
+       int accidentals_i_;
+       int minor_i_;
+       int key_i_;
+};
+
+class Midi_note : public Midi_event {
+public:
+       int const c0_pitch_i_c_ = 60;
+
+       Midi_note( String name_str, Duration dur );
+       virtual Moment mom();
+       virtual String mudela_str( bool command_mode_bo );
+       
+private:
+       bool const simple_plet_bo_ = false;
+       Duration dur_;
+       String name_str_;
+};
+
+class Midi_tempo : public Midi_event {
+public:
+       Midi_tempo( int useconds_per_4_i );
+
+       int get_tempo_i( Moment moment );
+       virtual String mudela_str( bool command_mode_bo );
+
+private:
+       int useconds_per_4_i_;
+       Real seconds_per_1_f_;
+};
+
+class Midi_text : public Midi_event {
+public:
+       enum Type { 
+               TEXT = 1, COPYRIGHT, TRACK_NAME, INSTRUMENT_NAME, LYRIC, 
+               MARKER, CUE_POINT
+       };
+       Midi_text( Midi_text::Type type,  String str );
+       virtual String mudela_str( bool command_mode_bo );
+private:
+       Type type_;
+       String text_str_;
+};
+
+class Midi_time : public Midi_event {
+public:
+       Midi_time( int num_i, int den_i, int division_4_i, int count_32_i );
+
+       Duration i2_dur( int time_i, int division_1_i );
+       int clocks_1_i();
+       virtual String mudela_str( bool command_mode_bo );
+       Moment bar_mom();
+
+private:
+       Real sync_f_;
+       Duration sync_dur_;
+       int clocks_1_i_;
+       int num_i_;
+       int den_i_;
+};
+
+#endif // MIDI_EVENT_HH
+
diff --git a/mi2mu/include/midi-global.hh b/mi2mu/include/midi-global.hh
new file mode 100644 (file)
index 0000000..29ba252
--- /dev/null
@@ -0,0 +1,34 @@
+//
+// midi-global.hh -- declare global (sic) stuff for mi2mu
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#ifndef MIDI_GLOBAL_HH
+#define MIDI_GLOBAL_HH
+
+#include "string.hh"
+
+#define monitor_p_g &cout
+enum Verbose { QUIET_ver, BRIEF_ver, NORMAL_ver, VERBOSE_ver, DEBUG_ver };
+extern Verbose level_ver;
+#ifdef NPRINT
+#define dtor if ( 0 ) *monitor_p_g
+#define mtor if ( 0 ) *monitor_p_g
+#else
+#define dtor if ( level_ver >= DEBUG_ver ) *monitor_p_g
+#define vtor if ( level_ver >= VERBOSE_ver ) *monitor_p_g
+#define mtor if ( level_ver >= NORMAL_ver ) *monitor_p_g
+#define btor if ( level_ver >= BRIEF_ver ) *monitor_p_g
+#define qtor if ( level_ver >= QUIET_ver ) *monitor_p_g
+#endif
+
+extern Source* source_l_g;
+extern bool no_triplets_bo_g;
+void message( String message_str, char const* context_ch_c_l );
+void warning( String message_str, char const* context_ch_c_l );
+void error( String message_str, char const* context_ch_c_l );
+
+String version_str();
+
+#endif // MIDI_GLOBAL_HH
+
diff --git a/mi2mu/include/midi-score.hh b/mi2mu/include/midi-score.hh
new file mode 100644 (file)
index 0000000..08cd69b
--- /dev/null
@@ -0,0 +1,28 @@
+//
+// midi-score.hh -- declare midi_score
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#ifndef MIDI_SCORE_HH
+#define MIDI_SCORE_HH
+
+/// (midi_score)
+class Midi_score {
+public:
+       Midi_score( int format_i, int tracks_i, int tempo_i );
+       ~Midi_score();
+
+       void add_track( Midi_track* midi_track_p );
+
+       int output_mudela( String filename_str );
+       void process();
+
+private:
+       IPointerList<Midi_track*> midi_track_p_list_;
+       int format_i_;
+       int tracks_i_;
+       int tempo_i_;
+};
+
+#endif // MIDI_SCORE_HH
+
diff --git a/mi2mu/include/midi-track.hh b/mi2mu/include/midi-track.hh
new file mode 100644 (file)
index 0000000..22e110b
--- /dev/null
@@ -0,0 +1,38 @@
+//
+// midi-track.hh -- declare midi_track
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#ifndef MIDI_TRACK_HH
+#define MIDI_TRACK_HH
+
+/// (midi_track)
+class Midi_track {
+public:
+       Midi_track( int number_i, String copyright_str, String track_name_str, String instrument_str );
+
+       void add_event( Moment mom, Midi_event* midi_event_p );
+       Moment end_mom();
+       String name_str();
+       void output_mudela( Lily_stream& lily_stream_r );
+       Moment next_begin_mom( Moment now_mom );
+       Moment next_end_mom( Moment now_mom );
+       void process();
+       Track_column* tcol_l( Moment mom );
+
+       String copyright_str_;
+       String instrument_str_;
+       String name_str_;
+
+private:
+       void add_begin_at( PointerList<Midi_voice*>& open_voices_r, Moment mom );
+       Midi_voice* get_free_midi_voice_l( Moment mom );
+       void remove_end_at( PointerList<Midi_voice*>& open_voices_r, Moment mom );
+       IPointerList<Track_column*> tcol_p_list_;
+       IPointerList<Midi_voice*> midi_voice_p_list_;
+       int number_i_;
+
+};
+
+#endif // MIDI_TRACK_HH
+
diff --git a/mi2mu/include/midi-voice.hh b/mi2mu/include/midi-voice.hh
new file mode 100644 (file)
index 0000000..cf3df84
--- /dev/null
@@ -0,0 +1,26 @@
+//
+// midi-voice.hh -- declare midi_voice
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+/// (midi_voice)
+#ifndef MIDI_VOICE_HH
+#define MIDI_VOICE_HH
+
+class Midi_voice {
+public:
+       Midi_voice( Moment begin_mom );
+
+       void add_event( Midi_event* midi_event_p );
+       Moment begin_mom();
+       Moment end_mom();
+
+       String mudela_str( Moment from_mom, Moment to_mom, bool multiple_bo );
+
+private:
+       Moment begin_mom_;
+       IPointerList<Midi_event*> midi_event_p_list_;
+};
+
+#endif // MIDI_VOICE_HH
+
diff --git a/mi2mu/include/my-midi-lexer.hh b/mi2mu/include/my-midi-lexer.hh
new file mode 100644 (file)
index 0000000..032bf67
--- /dev/null
@@ -0,0 +1,43 @@
+//
+// my-midi-lexer.hh -- declare My_midi_lexer
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#ifndef MY_MIDI_LEXER_HH
+#define MY_MIDI_LEXER_HH
+
+#include <FlexLexer.h>
+#include "proto.hh"
+// #include "fproto.hh"
+#include "varray.hh"
+#include "string.hh"
+
+int yylex();
+void yyerror(const char *s);
+// bool busy_parsing();
+// void kill_lexer();
+// void set_lexer();
+
+/// (midi_lexer)
+class My_midi_lexer : yyFlexLexer {
+public:
+       My_midi_lexer( String filename_str );
+       ~My_midi_lexer();
+
+       int close_i();
+       void error( char const* sz_l );
+       char const* here_ch_c_l();
+       static int varint2_i( String str );
+       int yylex();
+
+private:
+       Input_file* input_file_p_;
+
+public: // ugh
+       int errorlevel_i_;
+};
+
+extern My_midi_lexer* midi_lexer_l_g;
+
+#endif // MY_MIDI_LEXER_HH
+
diff --git a/mi2mu/include/my-midi-parser.hh b/mi2mu/include/my-midi-parser.hh
new file mode 100644 (file)
index 0000000..66de991
--- /dev/null
@@ -0,0 +1,63 @@
+//
+// my-midi-parser.hh -- declare My_midi_parser
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#ifndef MY_MIDI_PARSER_HH
+#define MY_MIDI_PARSER_HH
+
+// #include "proto.hh"
+// #include "string.hh"
+
+int yyparse();
+
+/// (midi_parser)
+class My_midi_parser {
+public:
+       My_midi_parser( String filename_str );
+       ~My_midi_parser();
+
+       void add_score( Midi_score* midi_score_p );
+       void error( char const* sz_l );
+       int parse();
+       void forward( int i );
+       Moment mom();
+       void note_begin( int channel_i, int pitch_i, int dyn_i );
+       Midi_event* note_end_midi_event_p( int channel_i, int pitch_i, int dyn_i );
+       int output_mudela( String filename_str );
+       void reset();
+       void set_division_4( int division_4_i );
+       void set_key( int accidentals_i, int minor_i );
+       void set_tempo( int useconds_i );
+       void set_time( int num_i, int den_i, int clocks_i, int count_32_i );
+
+       int bar_i_;
+       int track_i_;
+       String filename_str_;
+       String copyright_str_;
+       String instrument_str_;
+       String track_name_str_;
+
+       Midi_key* midi_key_p_;
+       Midi_tempo* midi_tempo_p_;
+       Midi_time* midi_time_p_;
+
+private:
+       I64 now_i64_;   // 31 bits yields tipically about 1000 bars
+
+       static int const CHANNELS_i = 16;
+       static int const PITCHES_i = 128;
+       I64 running_i64_i64_a_[ CHANNELS_i ][ PITCHES_i ];
+
+       Midi_score* midi_score_p_;
+       int division_1_i_;
+
+       char const* defined_ch_c_l_;
+       int fatal_error_i_;
+       My_midi_lexer* midi_lexer_p_;
+};
+
+extern My_midi_parser* midi_parser_l_g;
+
+#endif // MY_MIDI_PARSER_HH
+
diff --git a/mi2mu/include/track-column.hh b/mi2mu/include/track-column.hh
new file mode 100644 (file)
index 0000000..0ed0323
--- /dev/null
@@ -0,0 +1,23 @@
+//
+// track-column.hh -- declare Track_column
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#ifndef TRACK_COLUMN_HH
+#define TRACK_COLUMN_HH
+
+/// (tcol)
+class Track_column {
+public:
+       Track_column( Moment mom );
+
+       void add_event( Midi_event* midi_event_p );
+       Moment mom();
+
+//private:
+       IPointerList<Midi_event*> midi_event_p_list_;
+       Moment mom_;
+};
+
+#endif // TRACK_COLUMN_HH
+
diff --git a/mi2mu/lily-stream.cc b/mi2mu/lily-stream.cc
new file mode 100644 (file)
index 0000000..244e36f
--- /dev/null
@@ -0,0 +1,141 @@
+//
+// lily-stream.cc
+//
+// source file of the LilyPond music typesetter
+//
+// (c) 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+// should i be named Mudela_stream?
+
+#include "mi2mu.hh"
+
+Lily_stream::Lily_stream( String filename_str )
+{
+       filename_str_ = filename_str;
+       os_p_ = 0;
+       indent_i_ = 0;
+       comment_mode_bo_ = false;
+       column_i_ = 0;
+       wrap_column_i_ = 60;
+       open();
+       header();
+}
+
+Lily_stream::~Lily_stream()
+{
+       delete os_p_;
+       if ( indent_i_ )
+               warning( "lily indent level: " + String( indent_i_ ), 0 );
+}
+
+Lily_stream&
+Lily_stream::operator <<( String str )
+{
+       static String nobreak_str = "\\`'_-.^<>*@";
+       while ( str.length_i() ) {
+               int max_i = wrap_column_i_ - column_i_ - 1;
+               int i = str.length_i() - 1 <? max_i;
+               int nl_i = str.left_str( i + 1 ).index_i( '\n' );
+               if ( nl_i != -1 ) {
+                       i = nl_i - 1;
+                       str = str.nomid_str( nl_i, 1 );
+               }
+
+               if ( ( i != str.length_i() - 1 ) && ( nl_i == -1 ) )
+                       while ( i && ( isalnum( str[ i ] ) 
+                               || ( nobreak_str.index_i( str[ i ] ) != -1 ) ) )
+                               i--;
+
+               if ( !i ) { // no room left
+                       if ( column_i_ > 8 * indent_i_ ) {
+                               newline();
+                               if ( comment_mode_bo_ && ( str[ 0 ] != '%' ) )
+                                       str = '%' + str;
+                               continue;
+                       }
+                       else { // cannot break neatly...
+                               i = max_i;
+                       }
+               }
+                       
+               String line = str.left_str( i + 1 ); 
+               str = str.mid_str( i + 1, INT_MAX );
+               *os_p_ << line;
+               if ( nl_i != -1 )
+                        newline();
+               else
+                       check_comment( line );
+               column_i_ += line.length_i();
+               if ( str.length_i() || ( column_i_ >= wrap_column_i_ ) ) {
+                       //brr.
+                       if ( comment_mode_bo_ )
+                               str = "%" + str;
+                       newline();
+               }
+       }       
+       return *this;
+}
+
+Lily_stream&
+Lily_stream::operator <<( Midi_event& midi_event_r )
+{
+       midi_event_r.output_mudela( *this, false );
+       *os_p_ << flush;
+       return *this;
+}
+
+void
+Lily_stream::check_comment( String str )
+{
+       int newline_i = str.index_last_i( '\n' );
+       if ( newline_i != -1 ) {
+               str = str.mid_str( newline_i +1, INT_MAX );
+               comment_mode_bo_ = false;
+       }
+       if ( str.index_i( '%' ) != -1 )
+               comment_mode_bo_ = true;
+}
+
+void
+Lily_stream::header()
+{
+       *os_p_ << "% Creator: " << version_str() << "\n";
+       *os_p_ << "% Automatically generated, at ";
+       time_t t( time( 0 ) );
+       *os_p_ << ctime( &t );
+       *os_p_ << "% from input file: ";
+       *os_p_ << midi_parser_l_g->filename_str_;
+       *os_p_ << "\n\n";    
+}
+
+void
+Lily_stream::indent()
+{
+       indent_i_++;
+       newline();
+}
+
+void
+Lily_stream::newline()
+{
+       *os_p_ << endl << String( '\t', indent_i_ );
+       column_i_ = indent_i_ * 8;
+       comment_mode_bo_ = false;
+}
+
+void
+Lily_stream::open()
+{
+       os_p_ = new ofstream( filename_str_ );
+       if ( !*os_p_ )
+               error ( "can't open `" + filename_str_ + "\'", 0 );
+}
+
+void
+Lily_stream::tnedni()
+{
+       assert( indent_i_ > 0 );
+       indent_i_--;
+       newline();
+}
+
diff --git a/mi2mu/midi-event.cc b/mi2mu/midi-event.cc
new file mode 100644 (file)
index 0000000..2317fdb
--- /dev/null
@@ -0,0 +1,223 @@
+//
+// midi-event.cc -- implement Midi_event
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include "mi2mu.hh"
+
+Midi_event::Midi_event()
+{
+}
+
+Moment
+Midi_event::mom()
+{
+       return Moment( 0 );
+}
+
+void
+Midi_event::output_mudela( Lily_stream& lily_stream_r, bool command_mode_bo )
+{
+       lily_stream_r << mudela_str( command_mode_bo ) << String( " " );
+}
+
+Midi_key::Midi_key( int accidentals_i, int minor_i )
+{
+       accidentals_i_ = accidentals_i;
+       minor_i_ = minor_i;
+       if ( accidentals_i >= 0 )
+               key_i_ = ( ( accidentals_i % 7 )[ "cgdaebf" ] - 'a' - 2 ) % 7;
+       else
+               key_i_ = ( ( -accidentals_i % 7 )[ "cfbeadg" ] - 'a' - 2 ) % 7;
+}
+
+String
+Midi_key::mudela_str( bool command_mode_bo )
+{
+       String str = "key\\";
+       if ( !minor_i_ ) 
+               str += String( (char)( ( key_i_ + 2 ) % 7 + 'A'  ) );
+       else // heu, -2: should be - 1 1/2: A -> fis
+               str += String( (char)( ( key_i_ + 2 - 2 ) % 7 + 'a'  ) );
+       if ( !command_mode_bo )
+           str =  String( '\\' ) + str;
+       str = String( "%" ) + str + "\n"; // "\key\F" not supported yet...
+       return str;
+}
+
+String
+Midi_key::notename_str( int pitch_i )
+{
+       // this may seem very smart,
+       // but it-s only an excuse not to read a notename table
+
+       // major scale: do-do
+       // minor scale: la-la ( = + 5 )
+       static int notename_i_a[ 12 ] = { 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6 };
+       int notename_i = notename_i_a[ ( minor_i_ * 5 + pitch_i ) % 12 ];
+       
+       static int accidentals_i_a[ 12 ] = { 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0 };
+       int accidental_i = accidentals_i_a[ minor_i_ * 5 + pitch_i % 12 ];
+       if ( accidental_i && ( accidentals_i_ < 0 ) ) {
+               accidental_i = - accidental_i;
+               notename_i = ( notename_i + 1 ) % 7;
+       }
+
+       String notename_str = (char)( ( ( notename_i + 2 ) % 7 ) + 'a' );
+       while ( accidental_i-- > 0 )
+               notename_str += "is";
+       accidental_i++;
+       while ( accidental_i++ < 0 )
+               if ( ( notename_str == "a" ) || ( notename_str == "e" ) )
+                       notename_str += "s";
+               else
+                       notename_str += "es";
+       accidental_i--;
+       String octave_str;
+
+       octave_str += String( '\'', ( pitch_i - Midi_note::c0_pitch_i_c_ ) / 12 );
+       octave_str += String( '`', ( Midi_note::c0_pitch_i_c_ + 11 - pitch_i ) / 12 );
+       return octave_str + notename_str;
+}
+
+Midi_note::Midi_note( String name_str, Duration dur )
+{
+       // do i want pitch too?
+       dur_ = dur;
+       name_str_ = name_str;
+}
+
+String
+Midi_note::mudela_str( bool command_mode_bo )
+{
+//     assert( !command_mode_bo );
+// undefined ref to simple_plet_bo_ ??
+//     if ( simple_plet_bo_ )
+//             return name_str_ + Duration_convert::dur2_str( dur_ );
+
+       //ugh
+       String str;
+       if ( dur_.plet_p_ )
+               str += String( "\\plet{ " )
+                       + String_convert::i2dec_str( dur_.plet_p_->iso_i_, 0, 0 )
+                       + "/"
+                       + String_convert::i2dec_str( dur_.plet_p_->type_i_, 0, 0 )
+                       + " } ";
+
+       str += name_str_;
+
+       Duration dur = dur_;
+       dur.set_plet( 0 );
+       str += Duration_convert::dur2_str( dur );
+
+       if ( dur_.plet_p_ )
+               str += String( " \\plet{ 1/1 }" );
+               
+       return str;
+}
+
+Moment
+Midi_note::mom()
+{
+       return Duration_convert::dur2_mom( dur_ );
+}
+
+Midi_tempo::Midi_tempo( int useconds_per_4_i )
+{
+       useconds_per_4_i_ = useconds_per_4_i;
+// huh, is it not per 4?
+//     seconds_per_1_f_ = (Real)useconds_per_4_i_ * 4 / 1e6;
+       seconds_per_1_f_ = (Real)useconds_per_4_i_ * 8 / 1e6;
+}
+
+String
+Midi_tempo::mudela_str( bool command_mode_bo )
+{
+//     assert( command_mode_bo );
+       if ( !command_mode_bo )
+               return "";
+       String str = "tempo 4:";
+       str += String( get_tempo_i( Moment( 1, 4 ) ) );
+       return str;
+}
+
+int
+Midi_tempo::get_tempo_i( Moment moment )
+{
+       return Moment( 60 ) / moment / Moment( seconds_per_1_f_ );
+}
+
+Midi_text::Midi_text( Midi_text::Type type, String text_str )
+{
+       type_ = type;
+       text_str_ = text_str;
+}
+
+String
+Midi_text::mudela_str( bool command_mode_bo )
+{
+       (void)command_mode_bo;
+       if ( !text_str_.length_i() 
+               || ( text_str_.length_i() != (int)strlen( text_str_.ch_c_l() ) ) )
+               return "";
+
+       return "% " + text_str_ + "\n\t";
+}
+
+Midi_time::Midi_time( int num_i, int den_i, int clocks_4_i, int count_32_i )
+       : sync_dur_( 8 )
+{
+       sync_f_ = 1.0;
+       if ( count_32_i != 8 )
+               warning( String( "#32 in quarter: " ) + String( count_32_i ), 0 );
+       num_i_ = num_i;
+       den_i_ = 2 << den_i;
+       clocks_1_i_ = clocks_4_i * 4; 
+}
+
+Moment
+Midi_time::bar_mom()
+{
+       return Moment( num_i_ ) * Duration_convert::dur2_mom( Duration( den_i_ ) );
+}
+
+int
+Midi_time::clocks_1_i()
+{
+       return clocks_1_i_;
+}
+
+Duration
+Midi_time::i2_dur( int time_i, int division_1_i )
+{
+       Moment mom = Duration_convert::i2_mom( time_i, division_1_i );
+       mom /= sync_f_;
+
+       dtor << "\n% (" << time_i << ", " << mom << "): "
+               << sync_f_ << endl;
+
+       Duration dur = Duration_convert::mom2_dur( mom );
+       if ( !dur.type_i_ ) {
+               vtor << "\n% resyncing(" << time_i << ", " << mom << "): "
+                       << sync_f_ << " -> ";
+               mom *= sync_f_;
+               sync_f_ = Duration_convert::sync_f( sync_dur_, mom );
+               vtor << sync_f_ << endl;
+               mom /= sync_f_;
+               dur = Duration_convert::mom2_dur( mom );
+       }
+
+       return dur;
+}
+
+String
+Midi_time::mudela_str( bool command_mode_bo )
+{
+       String str = "meter { "
+               + String( num_i_ ) + "*" + String( den_i_ ) 
+               + " }";
+       if ( !command_mode_bo )
+           str =  String( '\\' ) + str;
+       return str;
+}
+
diff --git a/mi2mu/midi-lexer.l b/mi2mu/midi-lexer.l
new file mode 100644 (file)
index 0000000..f832587
--- /dev/null
@@ -0,0 +1,410 @@
+%{
+// midi-lexer.l
+
+
+#include "mi2mu.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 i8
+%x u8
+%x int16
+%x int32
+%x meta_event
+%x track
+
+U8             [\x00-\xff]
+I8             {U8}
+INT16          {U8}{U8}
+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;
+}
+{U8}   {
+       error( String( "top level: illegal byte: " )
+               + String_convert::bin2hex_str( String( *YYText() ) ) );
+       exit( 1 );
+}
+<int32>{INT32} { // really signed? 
+       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} { // really signed?
+       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;
+}
+<i8>{I8}       {
+       dtor << "lex: i8" << endl;
+       assert( YYLeng() == 1 );
+//     yylval.byte = *(signed char*)YYText();
+       yylval.i = *(signed char*)YYText();
+       yy_pop_state(); 
+       return I8;
+}
+<u8>{U8}       {
+       dtor << "lex: u8" << endl;
+       assert( YYLeng() == 1 );
+//     yylval.byte = *(Byte*)YYText();
+       yylval.i = *(Byte*)YYText();
+       yy_pop_state(); 
+       return U8;
+}
+
+<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>{U8}    {
+       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( u8 );
+       yy_push_state( u8 );
+       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( u8 );
+       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( u8 );
+       yy_push_state( u8 );
+       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( u8 );
+       yy_push_state( u8 );
+       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( u8 );
+       yy_push_state( u8 );
+       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( u8 );
+       yy_push_state( u8 );
+       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( u8 );
+       yy_push_state( u8 );
+       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( u8 );
+       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( u8 );
+       yy_push_state( u8 );
+       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( u8 );
+       yy_push_state( u8 );
+       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( u8 ); //?
+       yy_push_state( data );
+       return SYSEX_EVENT2;
+}
+<event>{META_EVENT}    {
+       dtor << "lex: meta" << endl;
+       yy_push_state( meta_event );
+       return META_EVENT;
+}
+<event>{U8}    {
+       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( u8 );
+       yy_push_state( u8 );
+       yy_push_state( u8 );
+       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( u8 );
+       yy_push_state( u8 );
+       yy_push_state( u8 );
+       yy_push_state( u8 );
+       yy_push_state( u8 );
+       return SMPTE_OFFSET;
+}
+<meta_event>{TIME}     {               // nn dd cc bb
+       dtor << "lex: time" << endl;
+       yy_pop_state();
+       yy_pop_state();
+       yy_push_state( u8 );
+       yy_push_state( u8 );
+       yy_push_state( u8 );
+       yy_push_state( u8 );
+       return TIME;
+}
+<meta_event>{KEY}      {       // sf mi
+       dtor << "lex: key" << endl;
+       yy_pop_state();
+       yy_pop_state();
+       yy_push_state( i8 );
+       yy_push_state( i8 );
+       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>{U8} {
+       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( u8 ); 
+       yy_push_state( u8 );
+       return U8;
+}
+
+<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>{U8}     {
+       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
+}
+
+%%
+
diff --git a/mi2mu/midi-parser.y b/mi2mu/midi-parser.y
new file mode 100644 (file)
index 0000000..e8bb5e9
--- /dev/null
@@ -0,0 +1,303 @@
+%{
+
+#include "mi2mu.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> I8 U8 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 {
+               mtor << "\ntrack " << midi_parser_l_g->track_i_++ << ": " << flush;
+               $$ = 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 );
+               if ( $1 ) {
+                       int bars_i = (int)( midi_parser_l_g->mom() / midi_parser_l_g->midi_time_p_->bar_mom() );
+                       if ( bars_i > midi_parser_l_g->bar_i_ )
+                               mtor << '[' << midi_parser_l_g->bar_i_++ 
+                                       << ']' << flush; 
+               }
+       }
+       ;
+
+the_event: 
+       meta_event { 
+       }
+       | midi_event {
+       }
+       | sysex_event {
+       }
+       ;
+
+meta_event:
+       META_EVENT the_meta_event {
+               $$ = $2;
+       }
+       |
+       META_EVENT U8 U8 U8 {
+               $$ = 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 U8 U8 U8 { 
+               $$ = 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 U8 U8 U8 U8 U8 { 
+               $$ = 0;
+       }
+       | TIME U8 U8 U8 U8 { 
+               $$ = new Midi_time( $2, $3, $4, $5 );
+               dtor << $$->mudela_str( true ) << endl;
+               midi_parser_l_g->set_time( $2, $3, $4, $5 );
+       }
+       | KEY I8 I8 { 
+               $$ = 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 U8 { //U8 {
+               $$ = 0;
+       }
+       ;
+
+data_entry:
+       DATA_ENTRY U8 {
+               $$ = 0;
+       }
+       ;
+
+all_notes_off:
+       ALL_NOTES_OFF U8 U8 {
+               $$ = 0;
+       }
+       ;
+
+note_off:
+       NOTE_OFF U8 U8 {
+               int i = $1;
+               i = i & ~0x80;
+               $$ = midi_parser_l_g->note_end_midi_event_p( $1 & ~0x80, $2, $3 );
+       }
+       ;
+
+note_on:
+       NOTE_ON U8 U8 {
+               int i = $1;
+               i = i & ~0x90;
+               $$ = 0;
+               midi_parser_l_g->note_begin( $1 & ~0x90, $2, $3 );
+       }
+       ;
+
+polyphonic_aftertouch:
+       POLYPHONIC_AFTERTOUCH U8 U8 {
+               $$ = 0;
+       }
+       ;
+
+controlmode_change:
+       CONTROLMODE_CHANGE U8 U8 {
+               $$ = 0;
+       }
+       ;
+
+program_change:
+       PROGRAM_CHANGE U8 {
+               $$ = 0;
+       }
+       ;
+
+channel_aftertouch:
+       CHANNEL_AFTERTOUCH U8 U8 {
+               $$ = 0;
+       }
+       ;
+
+pitchwheel_range:
+       PITCHWHEEL_RANGE U8 U8 {
+               $$ = 0;
+       }
+       ;
+
+sysex_event:
+       SYSEX_EVENT1 DATA {
+               $$ = 0;
+       }
+       | SYSEX_EVENT2 DATA { // U8 ?
+               $$ = 0;
+       }
+       ;
diff --git a/mi2mu/midi-score.cc b/mi2mu/midi-score.cc
new file mode 100644 (file)
index 0000000..ce4e230
--- /dev/null
@@ -0,0 +1,79 @@
+//
+// midi-score.cc -- implement Midi_score
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include "mi2mu.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;
+
+       int track_i = 0;
+       Lily_stream lily_stream( filename_str );
+       for ( PCursor<Midi_track*> i( midi_track_p_list_.top() ); i.ok(); i++ ) {
+               mtor << "track " << track_i++ << ": " << flush;
+               i->output_mudela( lily_stream );
+               lily_stream.newline();
+               mtor << endl;
+       }
+
+       lily_stream << "score {";
+       lily_stream.newline();
+
+       for ( PCursor<Midi_track*> i( midi_track_p_list_.top() ); i.ok(); i++ ) {
+               lily_stream << "\tstaff { melodic music { ";
+               lily_stream << i->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()
+{
+       int track_i = 0;
+       for ( PCursor<Midi_track*> i( midi_track_p_list_.top() ); i.ok(); i++ )  {
+               mtor << "track " << track_i++ << ": " << flush;
+               i->process();
+               mtor << endl;
+       }
+}
+
diff --git a/mi2mu/midi-track.cc b/mi2mu/midi-track.cc
new file mode 100644 (file)
index 0000000..f94720c
--- /dev/null
@@ -0,0 +1,200 @@
+//
+// midi-track.cc -- implement Midi_track
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include "mi2mu.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 ) {
+                       dtor << "open_voices (" << open_voices_r.size() << "): +1\n";
+                       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*> i( midi_voice_p_list_.top() ); i.ok(); i++ )
+               if ( i->end_mom() == mom )
+                       return *i;
+
+       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()
+{
+       int bar_i = 1;
+       Moment bar_mom = midi_parser_l_g->midi_time_p_->bar_mom();
+
+       for ( PCursor<Track_column*> i( tcol_p_list_.top() ); i.ok(); i++ ) {
+               int bars_i = (int)( i->mom() / bar_mom );
+               if ( bars_i > bar_i )
+                       mtor << '[' << bar_i << flush; 
+               while ( i->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( i->mom() )->add_event( i->midi_event_p_list_.top().remove_p() );
+               if ( bars_i > bar_i ) {
+                       bar_i++;
+                       mtor << ']' << flush; 
+               }
+       }
+
+       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();
+
+       int bar_i = 1;
+       Moment bar_mom = midi_parser_l_g->midi_time_p_->bar_mom();
+
+       PointerList<Midi_voice*> open_voices;
+       Moment now_mom = 0.0;
+       Moment then_mom = 0.0;
+       while ( now_mom < end_mom() ) {
+               int bars_i = (int)( now_mom / bar_mom );
+               if ( bars_i > bar_i )
+                       mtor << '[' << bar_i << flush; 
+               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 );
+               if ( bars_i > bar_i ) {
+                       bar_i++;
+                       mtor << ']' << flush; 
+               }
+       }
+       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 ) {
+                       dtor << "open_voices (" << open_voices_r.size() << "): -1\n";
+                       i.remove_p();  // remove? // no delete; only a copy
+                       if ( !i.ok() )
+                               break;
+               }
+}
+
+Track_column*
+Midi_track::tcol_l( Moment mom )
+{
+       for ( PCursor<Track_column*> i( tcol_p_list_.top() ); i.ok(); i++ ) {
+               if ( i->mom() == mom )
+                       return *i;
+               if ( i->mom() > mom ) {
+                       Track_column* tcol_p = new Track_column( mom );
+                       i.insert( tcol_p );
+                       return tcol_p;
+               }
+       }
+
+       Track_column* tcol_p = new Track_column( mom );
+       tcol_p_list_.bottom().add( tcol_p );
+       return tcol_p;
+}
+
diff --git a/mi2mu/midi-voice.cc b/mi2mu/midi-voice.cc
new file mode 100644 (file)
index 0000000..e963be2
--- /dev/null
@@ -0,0 +1,62 @@
+//
+// midi-voice.cc -- implement midi_voice
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include "mi2mu.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;
+}
+
diff --git a/mi2mu/my-midi-lexer.cc b/mi2mu/my-midi-lexer.cc
new file mode 100644 (file)
index 0000000..8438995
--- /dev/null
@@ -0,0 +1,78 @@
+//
+// my-midi-lexer.cc -- implement My_midi_lexer
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include "mi2mu.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;
+}
+
diff --git a/mi2mu/my-midi-parser.cc b/mi2mu/my-midi-parser.cc
new file mode 100644 (file)
index 0000000..e35369a
--- /dev/null
@@ -0,0 +1,160 @@
+//
+// my-midi-parser.cc -- implement My_midi_parser
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include "mi2mu.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;
+       bar_i_ = 1;
+       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;
+       bar_i_ = 1;
+
+       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;
+       bar_i_ = 1;
+}
+
+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 )
+{
+       I64 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_ );
+       mtor << "\nProcessing..." << endl;
+       midi_score_p_->process();
+       return midi_score_p_->output_mudela( filename_str );
+}
+
+int
+My_midi_parser::parse()
+{
+       mtor << "\nParsing..." << flush;
+       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 );
+}
+
diff --git a/mi2mu/track-column.cc b/mi2mu/track-column.cc
new file mode 100644 (file)
index 0000000..57b072b
--- /dev/null
@@ -0,0 +1,23 @@
+//
+// track-column.cc -- implement Track_column
+//
+// copyright 1997 Jan Nieuwenhuizen <jan@digicash.com>
+
+#include "mi2mu.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_;
+}