From 4a4ea3553bcbed0089c95e25e3656f6c044ad4fa Mon Sep 17 00:00:00 2001 From: fred Date: Mon, 10 Mar 1997 16:45:41 +0000 Subject: [PATCH] lilypond-0.0.40 --- mi2mu/.version | 6 + mi2mu/include/Makefile | 23 ++ mi2mu/include/lily-stream.hh | 35 +++ mi2mu/include/midi-event.hh | 96 ++++++++ mi2mu/include/midi-global.hh | 34 +++ mi2mu/include/midi-score.hh | 28 +++ mi2mu/include/midi-track.hh | 38 +++ mi2mu/include/midi-voice.hh | 26 ++ mi2mu/include/my-midi-lexer.hh | 43 ++++ mi2mu/include/my-midi-parser.hh | 63 +++++ mi2mu/include/track-column.hh | 23 ++ mi2mu/lily-stream.cc | 141 +++++++++++ mi2mu/midi-event.cc | 223 +++++++++++++++++ mi2mu/midi-lexer.l | 410 ++++++++++++++++++++++++++++++++ mi2mu/midi-parser.y | 303 +++++++++++++++++++++++ mi2mu/midi-score.cc | 79 ++++++ mi2mu/midi-track.cc | 200 ++++++++++++++++ mi2mu/midi-voice.cc | 62 +++++ mi2mu/my-midi-lexer.cc | 78 ++++++ mi2mu/my-midi-parser.cc | 160 +++++++++++++ mi2mu/track-column.cc | 23 ++ 21 files changed, 2094 insertions(+) create mode 100644 mi2mu/.version create mode 100644 mi2mu/include/Makefile create mode 100644 mi2mu/include/lily-stream.hh create mode 100644 mi2mu/include/midi-event.hh create mode 100644 mi2mu/include/midi-global.hh create mode 100644 mi2mu/include/midi-score.hh create mode 100644 mi2mu/include/midi-track.hh create mode 100644 mi2mu/include/midi-voice.hh create mode 100644 mi2mu/include/my-midi-lexer.hh create mode 100644 mi2mu/include/my-midi-parser.hh create mode 100644 mi2mu/include/track-column.hh create mode 100644 mi2mu/lily-stream.cc create mode 100644 mi2mu/midi-event.cc create mode 100644 mi2mu/midi-lexer.l create mode 100644 mi2mu/midi-parser.y create mode 100644 mi2mu/midi-score.cc create mode 100644 mi2mu/midi-track.cc create mode 100644 mi2mu/midi-voice.cc create mode 100644 mi2mu/my-midi-lexer.cc create mode 100644 mi2mu/my-midi-parser.cc create mode 100644 mi2mu/track-column.cc diff --git a/mi2mu/.version b/mi2mu/.version new file mode 100644 index 0000000000..1726cf2dd7 --- /dev/null +++ b/mi2mu/.version @@ -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 index 0000000000..cb4f4ea6d1 --- /dev/null +++ b/mi2mu/include/Makefile @@ -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 index 0000000000..8c6622d324 --- /dev/null +++ b/mi2mu/include/lily-stream.hh @@ -0,0 +1,35 @@ +// +// lily-stream.hh -- part of LilyPond +// +// copyright 1997 Jan Nieuwenhuizen + +// 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 index 0000000000..3f06353c4a --- /dev/null +++ b/mi2mu/include/midi-event.hh @@ -0,0 +1,96 @@ +// +// midi-event.hh -- declare midi_event +// +// copyright 1997 Jan Nieuwenhuizen + +#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 index 0000000000..29ba252a83 --- /dev/null +++ b/mi2mu/include/midi-global.hh @@ -0,0 +1,34 @@ +// +// midi-global.hh -- declare global (sic) stuff for mi2mu +// +// copyright 1997 Jan Nieuwenhuizen + +#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 index 0000000000..08cd69b845 --- /dev/null +++ b/mi2mu/include/midi-score.hh @@ -0,0 +1,28 @@ +// +// midi-score.hh -- declare midi_score +// +// copyright 1997 Jan Nieuwenhuizen + +#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_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 index 0000000000..22e110b2e5 --- /dev/null +++ b/mi2mu/include/midi-track.hh @@ -0,0 +1,38 @@ +// +// midi-track.hh -- declare midi_track +// +// copyright 1997 Jan Nieuwenhuizen + +#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& open_voices_r, Moment mom ); + Midi_voice* get_free_midi_voice_l( Moment mom ); + void remove_end_at( PointerList& open_voices_r, Moment mom ); + IPointerList tcol_p_list_; + IPointerList 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 index 0000000000..cf3df84171 --- /dev/null +++ b/mi2mu/include/midi-voice.hh @@ -0,0 +1,26 @@ +// +// midi-voice.hh -- declare midi_voice +// +// copyright 1997 Jan Nieuwenhuizen + +/// (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_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 index 0000000000..032bf6752b --- /dev/null +++ b/mi2mu/include/my-midi-lexer.hh @@ -0,0 +1,43 @@ +// +// my-midi-lexer.hh -- declare My_midi_lexer +// +// copyright 1997 Jan Nieuwenhuizen + +#ifndef MY_MIDI_LEXER_HH +#define MY_MIDI_LEXER_HH + +#include +#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 index 0000000000..66de991259 --- /dev/null +++ b/mi2mu/include/my-midi-parser.hh @@ -0,0 +1,63 @@ +// +// my-midi-parser.hh -- declare My_midi_parser +// +// copyright 1997 Jan Nieuwenhuizen + +#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 index 0000000000..0ed0323a97 --- /dev/null +++ b/mi2mu/include/track-column.hh @@ -0,0 +1,23 @@ +// +// track-column.hh -- declare Track_column +// +// copyright 1997 Jan Nieuwenhuizen + +#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_p_list_; + Moment mom_; +}; + +#endif // TRACK_COLUMN_HH + diff --git a/mi2mu/lily-stream.cc b/mi2mu/lily-stream.cc new file mode 100644 index 0000000000..244e36f43b --- /dev/null +++ b/mi2mu/lily-stream.cc @@ -0,0 +1,141 @@ +// +// lily-stream.cc +// +// source file of the LilyPond music typesetter +// +// (c) 1997 Jan Nieuwenhuizen + +// 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 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 index 0000000000..2317fdb695 --- /dev/null +++ b/mi2mu/midi-event.cc @@ -0,0 +1,223 @@ +// +// midi-event.cc -- implement Midi_event +// +// copyright 1997 Jan Nieuwenhuizen + +#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 index 0000000000..f83258789f --- /dev/null +++ b/mi2mu/midi-lexer.l @@ -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} { // 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} { // 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} { + dtor << "lex: i8" << endl; + assert( YYLeng() == 1 ); +// yylval.byte = *(signed char*)YYText(); + yylval.i = *(signed char*)YYText(); + yy_pop_state(); + return I8; +} +{U8} { + dtor << "lex: u8" << endl; + assert( YYLeng() == 1 ); +// yylval.byte = *(Byte*)YYText(); + yylval.i = *(Byte*)YYText(); + yy_pop_state(); + return U8; +} + +{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; +} +{U8} { + error( String( "track: illegal byte: " ) + + String_convert::bin2hex_str( String( *YYText() ) ) ); + exit( 1 ); +} +{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; +} +{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; +} +{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; +} +{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; +} +{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; +} +{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; +} +{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; +} +{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; +} +{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; +} +{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; +} +{SYSEX_EVENT1} { // len data + dtor << "lex: sysex1" << endl; + yy_pop_state(); + yy_push_state( data ); + return SYSEX_EVENT1; +} +{SYSEX_EVENT2} { // len data + dtor << "lex: sysex2" << endl; + yy_pop_state(); +// yy_push_state( u8 ); //? + yy_push_state( data ); + return SYSEX_EVENT2; +} +{META_EVENT} { + dtor << "lex: meta" << endl; + yy_push_state( meta_event ); + return META_EVENT; +} +{U8} { + error( String( "event: illegal byte: " ) + + String_convert::bin2hex_str( String( *YYText() ) ) ); + exit( 1 ); +} +{SEQUENCE} { // ssss sequence number + dtor << "lex: sequence" << endl; + yy_pop_state(); + yy_pop_state(); + yy_push_state( int16 ); + return SEQUENCE; +} +{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; +} +{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; +} +{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; +} +{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; +} +{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; +} +{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; +} +{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; +} +{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; +} +{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; +} +{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; +} +{KEY} { // sf mi + dtor << "lex: key" << endl; + yy_pop_state(); + yy_pop_state(); + yy_push_state( i8 ); + yy_push_state( i8 ); + return KEY; +} +{SSME} { // len data + dtor << "lex: smme" << endl; + yy_pop_state(); + yy_pop_state(); + yy_push_state( data ); + return SSME; +} +{END_OF_TRACK} { + dtor << "lex: end of track" << endl; + yy_pop_state(); + yy_pop_state(); + yy_pop_state(); + return END_OF_TRACK; +} +{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; +} + +{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; +} +{U8} { + error( String( "data: illegal byte: " ) + + String_convert::bin2hex_str( String( *YYText() ) ) ); + exit( 1 ); +} + +<> { +// mtor << "<>"; + + 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 index 0000000000..e8bb5e9d35 --- /dev/null +++ b/mi2mu/midi-parser.y @@ -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 I8 U8 INT16 INT32 INT7_8UNSET INT7_8SET VARINT +%token RUNNING_STATUS DATA_ENTRY ALL_NOTES_OFF +%token NOTE_OFF NOTE_ON +%token POLYPHONIC_AFTERTOUCH CONTROLMODE_CHANGE PROGRAM_CHANGE +%token CHANNEL_AFTERTOUCH PITCHWHEEL_RANGE +%token YYTEXT YYCOPYRIGHT YYTRACK_NAME YYINSTRUMENT_NAME YYLYRIC YYMARKER YYCUE_POINT +%token DATA + +%type varint +%type header midi_score +%type track +%type event +%type the_event meta_event the_meta_event text_event midi_event sysex_event +%type running_status data_entry all_notes_off +%type note_off note_on +%type polyphonic_aftertouch controlmode_change program_change +%type 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 index 0000000000..ce4e230a23 --- /dev/null +++ b/mi2mu/midi-score.cc @@ -0,0 +1,79 @@ +// +// midi-score.cc -- implement Midi_score +// +// copyright 1997 Jan Nieuwenhuizen + +#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 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 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 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 index 0000000000..f94720cf2a --- /dev/null +++ b/mi2mu/midi-track.cc @@ -0,0 +1,200 @@ +// +// midi-track.cc -- implement Midi_track +// +// copyright 1997 Jan Nieuwenhuizen + +#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& open_voices_r, Moment mom ) +{ + for ( PCursor 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 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 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 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 begin_mom(); + return begin_mom; +} + +Moment +Midi_track::next_end_mom( Moment now_mom ) +{ + Moment end_mom = Midi_track::end_mom(); + for ( PCursor i( midi_voice_p_list_.top() ); i.ok(); i++ ) + if ( i->end_mom() > now_mom ) + end_mom = end_mom 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 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 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 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 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& open_voices_r, Moment mom ) +{ + for ( PCursor 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 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 index 0000000000..e963be2f1c --- /dev/null +++ b/mi2mu/midi-voice.cc @@ -0,0 +1,62 @@ +// +// midi-voice.cc -- implement midi_voice +// +// copyright 1997 Jan Nieuwenhuizen + +#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 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 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 index 0000000000..843899567b --- /dev/null +++ b/mi2mu/my-midi-lexer.cc @@ -0,0 +1,78 @@ +// +// my-midi-lexer.cc -- implement My_midi_lexer +// +// copyright 1997 Jan Nieuwenhuizen + +#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 index 0000000000..e35369abfd --- /dev/null +++ b/mi2mu/my-midi-parser.cc @@ -0,0 +1,160 @@ +// +// my-midi-parser.cc -- implement My_midi_parser +// +// copyright 1997 Jan Nieuwenhuizen + +#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 index 0000000000..57b072b3b9 --- /dev/null +++ b/mi2mu/track-column.cc @@ -0,0 +1,23 @@ +// +// track-column.cc -- implement Track_column +// +// copyright 1997 Jan Nieuwenhuizen + +#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_; +} -- 2.39.5