From d87d38f1d944bc3934a16e43982814181c3f5267 Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Tue, 25 Feb 1997 21:56:16 +0100 Subject: [PATCH] release: 0.0.36 --- Documentation/README.pod | 27 +---- Documentation/faq.pod | 30 +++++- NEWS | 17 +++ Sources.make | 6 +- Variables.make | 4 +- flower/string-convert.cc | 141 +++++++++++++++++++++++++ flower/string-convert.hh | 34 ++++++ hdr/midi-event.hh | 61 ++++++++++- hdr/midi-main.hh | 16 ++- hdr/midiitem.hh | 16 ++- hdr/midioutput.hh | 2 + hdr/midistream.hh | 4 +- hdr/midiwalker.hh | 2 + hdr/my-midi-parser.hh | 21 +++- hdr/proto.hh | 5 + hdr/sourcefile.hh | 13 ++- input/Makefile | 4 +- input/midi.ly | 6 +- input/pavane.ly | 118 --------------------- input/pavane.tex | 12 --- input/standchen.ly | 2 +- input/wohltemperirt.ly | 2 +- src/binary-source-file.cc | 58 ++++++++++ src/inputfile.cc | 8 +- src/midi-event.cc | 216 ++++++++++++++++++++++++++++++++++++++ src/midi-lexer.l | 185 +++++++++++++++++++++++++++----- src/midi-main.cc | 116 +++++++++++++++++++- src/midi-parser.y | 144 +++++++++++++++++++++---- src/midi-track.cc | 2 + src/midiitem.cc | 34 +++--- src/midioutput.cc | 9 +- src/midistream.cc | 6 +- src/midiwalker.cc | 27 +++-- src/my-midi-lexer.cc | 21 ++-- src/my-midi-parser.cc | 94 ++++++++++++++++- src/sourcefile.cc | 19 +++- 36 files changed, 1209 insertions(+), 273 deletions(-) create mode 100644 flower/string-convert.cc create mode 100644 flower/string-convert.hh delete mode 100644 input/pavane.ly delete mode 100644 input/pavane.tex create mode 100644 src/binary-source-file.cc diff --git a/Documentation/README.pod b/Documentation/README.pod index 7126e8edc1..96c5ea4dd5 100644 --- a/Documentation/README.pod +++ b/Documentation/README.pod @@ -224,30 +224,9 @@ Do: configure make -You might want to edit Variables.make to tailor the compilation flags. -why G++ >= 2.7? LilyPond & FlowerLib uses: - -=over 5 - -=item * -builtin bool - -=item * -typeof - -=item * -operator ? - -=item * -the new for-scope - -=item * -class Rational (libg++) - -=item * -named return values - -=back +You probably want to edit Variables.make to tailor the compilation +flags. If you're not into debugging C++, then you should go for no +debugging and C<-O2> =head1 AUTHORS diff --git a/Documentation/faq.pod b/Documentation/faq.pod index b0096fd73a..d54266f053 100644 --- a/Documentation/faq.pod +++ b/Documentation/faq.pod @@ -34,7 +34,6 @@ Q: Why GPL? A: Yes. - Q: Why shouldn't I put all commands (\clef, \meter) inside the music? A: You should do what you like, but at some time we will enable @@ -50,3 +49,32 @@ A: If it is reasonable, I'll add XXXX to the TODO list. In general finding a cute syntax (such as YYYY) isn't very hard. The complicated issue how to adapt the internals to do XXXX. The parser is really a simple front end to the complicated internals. + +Q: Why do I need g++ >= 2.7? + +A: By using g++ LilyPond is portable to all platforms which support +g++ (there are quite a few). Not having to support other compilers +saves us a *lot* of trouble. LilyPond & FlowerLib uses: + +=over 5 + +=item * +builtin bool + +=item * +typeof + +=item * +operator ? + +=item * +the new for-scope + +=item * +class Rational (libg++) + +=item * +named return values + +=back + diff --git a/NEWS b/NEWS index bd29eda5ce..785c5bf38d 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,15 @@ +pl 36 + - Jan's patches: + - do MIDI rests cleanly. + - lily/m2m: time and tempo fixed for metric timing +Internal + - Midi_tempo + - m2m parses more midi stuff (all of bach-wtc); timing?? + - m2m recognises some commandline options +Examples + - fixed midi.ly + +******* pl 35 - Register_group Bugfix @@ -14,6 +26,11 @@ Internal - junked Midi_staff, Staff_column children, Midi_walker - Midi_output +pl 33-1 + - m2m parses midi +Internal + - Binary_source_file + - Source_file::error_str simplified ******* pl33 Examples diff --git a/Sources.make b/Sources.make index b255d37e54..0146217149 100644 --- a/Sources.make +++ b/Sources.make @@ -34,7 +34,9 @@ hdr=bar.hh barreg.hh beam.hh boxes.hh break.hh clefreg.hh clefitem.hh\ tstream.hh voice.hh\ voiceregs.hh voicegroupregs.hh walkregs.hh -mycc=bar.cc barreg.cc beam.cc boxes.cc break.cc calcideal.cc clefreg.cc\ +mycc=bar.cc barreg.cc beam.cc \ + binary-source-file.cc\ + boxes.cc break.cc calcideal.cc clefreg.cc\ clefitem.cc colhpos.cc commandrequest.cc\ complexstaff.cc complexwalker.cc \ debug.cc dimen.cc\ @@ -84,6 +86,7 @@ stablecc=request.cc bar.cc boxes.cc break.cc \ # m2m headers # mym2mhh=\ + binary-source-file.hh\ midi-event.hh\ midi-main.hh\ midi-score.hh\ @@ -96,6 +99,7 @@ mym2mhh=\ # m2m source # mym2mcc=\ + binary-source-file.cc\ midi-event.cc\ midi-main.cc\ midi-score.cc\ diff --git a/Variables.make b/Variables.make index ea71398c05..886b6eb256 100644 --- a/Variables.make +++ b/Variables.make @@ -3,7 +3,7 @@ # version info MAJVER=0 MINVER=0 -PATCHLEVEL=35 +PATCHLEVEL=36 @@ -19,7 +19,7 @@ DEBUGFLAG=-g # CXX=g++ # turn off -pipe if linker doesn't support it -EXTRACXXFLAGS=-pipe -Wall -W -Wmissing-prototypes -DSTRING_UTILS_INLINED +EXTRACXXFLAGS=-pipe -Wall -W -Wmissing-prototypes -DSTRING_UTILS_INLINED -O # # -lefence = ElectricFence. diff --git a/flower/string-convert.cc b/flower/string-convert.cc new file mode 100644 index 0000000000..ccd62a0a5a --- /dev/null +++ b/flower/string-convert.cc @@ -0,0 +1,141 @@ +/* + PROJECT: FlowerSoft C++ library + FILE : string-convert.cc + +--*/ + + +#include +#include "string.hh" + +String +String_convert::bin2hex_str( String bin_str ) +{ + String str; + Byte const* byte_c_l = bin_str.byte_c_l(); + for ( int i = 0; i < bin_str.length_i(); i++ ) { + str += (char)nibble2hex_byte( *byte_c_l >> 4 ); + str += (char)nibble2hex_byte( *byte_c_l++ ); + } + return str; +} + +int +String_convert::bin2_i( String bin_str ) +{ + assert( bin_str.length_i() <= 4 ); + + int result_i = 0; + for ( int i = 0; i < bin_str.length_i(); i++ ) { + result_i <<= 8; + result_i += (Byte)bin_str[ i ]; + } + return result_i; +} + +// breendet imp from String +int +String_convert::dec2_i( String dec_str ) +{ + if ( !dec_str.length_i() ) + return 0; + + long l = 0; + int conv = sscanf( dec_str.ch_c_l(), "%ld", &l ); + assert( conv ); + + return (int)l; +} + +// breendet imp from String +double +String_convert::dec2_f( String dec_str ) +{ + if ( !dec_str.length_i() ) + return 0; + double d = 0; + int conv = sscanf( dec_str.ch_c_l(), "%lf", &d ); + assert( conv ); + return d; +} + +int +String_convert::hex2bin_i( String hex_str, String& bin_str_r ) +{ + if ( hex_str.length_i() % 2 ) + hex_str = "0" + hex_str; + + bin_str_r = ""; + Byte const* byte_c_l= hex_str.byte_c_l(); + int i = 0; + while ( i < hex_str.length_i() ) { + int high_i = hex2nibble_i( *byte_c_l++ ); + int low_i = hex2nibble_i( *byte_c_l++ ); + if ( high_i < 0 || low_i < 0 ) + return 1; // illegal char + bin_str_r += String( (char)( high_i << 4 | low_i ), 1 ); + i += 2; + } + return 0; +} + +String +String_convert::hex2bin_str( String hex_str ) +{ + String str; +// silly, asserts should alway be "on"! +// assert( !hex2bin_i( hex_str, str ) ); + int error_i = hex2bin_i( hex_str, str ); + assert( !error_i ); + return str; +} + +int +String_convert::hex2nibble_i( Byte byte ) +{ + if ( byte >= '0' && byte <= '9' ) + return byte - '0'; + if ( byte >= 'A' && byte <= 'F' ) + return byte - 'A' + 10; + if ( byte >= 'a' && byte <= 'f') + return byte - 'a' + 10; + return -1; +} + +String +String_convert::i2dec_str( int i, int length_i, char ch ) +{ + char fill_ch = ch; + if ( fill_ch) + fill_ch = '0'; + + // ugh + String dec_str( i ); + + // ugh + return String( fill_ch, length_i - dec_str.length_i() ) + dec_str; +} + +String +String_convert::i2hex_str( int i, int length_i, char ch ) +{ + String str; + if ( !i ) + str = "0"; + while ( i ) { + str = ( i % 16 )["0123456789abcdef"] + str; + i /= 16; + } + if ( str.length_i() < length_i ) + str = String( ch, length_i - str.length_i() ) + str; + return str; +} + +Byte +String_convert::nibble2hex_byte( Byte byte ) +{ + if ( ( byte & 0x0f ) <= 9 ) + return ( byte & 0x0f ) + '0'; + else + return ( byte & 0x0f ) - 10 + 'a'; +} diff --git a/flower/string-convert.hh b/flower/string-convert.hh new file mode 100644 index 0000000000..b96af44bd0 --- /dev/null +++ b/flower/string-convert.hh @@ -0,0 +1,34 @@ +/* + PROJECT: FlowerSoft C++ library + FILE : string-convert.hh + +*/ + +#ifndef STRING_CONVERT_HH +#define STRING_CONVERT_HH + +/// +#define functor class // :-) +/** + The functor String_convert handles all conversions to/from String (some + time, anyway). + The class is quite empty from data view. + */ +functor String_convert { + static int hex2bin_i( String hex_str, String& bin_str_r ); + static int hex2nibble_i( Byte byte ); + static Byte nibble2hex_byte( Byte byte ); +public: + static String bin2dec_str( String dec_str ); + static String bin2hex_str( String bin_str ); + static String dec2bin_str( String str ); + static int bin2_i( String str ); + static int dec2_i( String dec_str ); + static double dec2_f( String dec_str ); + static int hex2int_i( String str ); + static String hex2bin_str( String str ); + static String i2hex_str( int i, int length_i, char ch ); + static String i2dec_str( int i, int length_i, char ch ); +}; + +#endif // __STRING_CONVERT_HH // diff --git a/hdr/midi-event.hh b/hdr/midi-event.hh index c9ab0336ea..a566dc50f7 100644 --- a/hdr/midi-event.hh +++ b/hdr/midi-event.hh @@ -6,13 +6,72 @@ #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(); - ~Midi_event(); + virtual ~Midi_event(); + + String mudela_str(); + +protected: + String mudela_str_; + +private: +}; + +class Midi_key : public Midi_event { +public: + Midi_key( int accidentals_i, int minor ); + virtual ~Midi_key(); + + String notename_str( int pitch_i ); + +private: + int accidentals_i_; + int minor_i_; + int key_i_; +}; + +class Midi_note : public Midi_event { +public: +// Midi_note( Midi_key* midi_key_l, Midi_tempo* midi_tempo_l, Midi_time* midi_time_l, int pitch_i, Real duration_f ); + Midi_note( Midi_key* midi_key_l, Midi_time* midi_time_l, int clocks_per_whole_i, int pitch_i, Real duration_f ); + virtual ~Midi_note(); + +}; + +class Midi_tempo : public Midi_event { +public: + Midi_tempo( int useconds_per_4_i ); + virtual ~Midi_tempo(); + + int get_tempo_i( Moment moment ); + +private: + int useconds_per_4_i_; + Real seconds_per_1_f_; +}; + +class Midi_time : public Midi_event { +public: + Midi_time( int num_i, int den_i, int clocks_i, int count_32_i ); + virtual ~Midi_time(); + + String duration_str( int usecond24th_per_clock_i, Real delta_time_f ); + int whole_clocks_i(); private: + int whole_clocks_i_; + int num_i_; + int den_i_; }; #endif // MIDI_EVENT_HH diff --git a/hdr/midi-main.hh b/hdr/midi-main.hh index 2812bb82b4..4eb86c27d2 100644 --- a/hdr/midi-main.hh +++ b/hdr/midi-main.hh @@ -2,8 +2,22 @@ // midi-main.hh -- global (sic) m2m stuff // // copyright 1997 Jan Nieuwenhuizen - #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; void message( String message_str, char const* context_ch_c_l ); void warning( String message_str, char const* context_ch_c_l ); diff --git a/hdr/midiitem.hh b/hdr/midiitem.hh index d30e6448fc..486637c367 100644 --- a/hdr/midiitem.hh +++ b/hdr/midiitem.hh @@ -23,11 +23,10 @@ struct Midi_note : public Midi_item { /** Generate a note-event on a channel pitch. - @param #melreq_l# the pitch. If null, then output a silent C - #on_b# turn on? + @param #melreq_l# is the pitch. */ Midi_note( Melodic_req* melreq_l, int channel_i, bool on_b ); - + virtual String str(); int channel_i_; @@ -60,7 +59,16 @@ private: struct Midi_header : Midi_chunk { /* *************** */ - Midi_header( int format_i, int tracks_i, int tempo_i ); + Midi_header( int format_i, int tracks_i, int clocks_per_4_i ); +}; + +struct Midi_tempo : Midi_item { + /* *************** */ + Midi_tempo( int tempo_i ); + + virtual String str(); + + int tempo_i_; }; struct Midi_track : Midi_chunk { diff --git a/hdr/midioutput.hh b/hdr/midioutput.hh index fed37feffa..34d7f7b039 100644 --- a/hdr/midioutput.hh +++ b/hdr/midioutput.hh @@ -15,5 +15,7 @@ struct Midi_output { Midi_stream* midi_stream_l_; Midi_output(Score* score_l, Midi_def* ); void do_staff(Staff*st_l, int count); + + Midi_def* midi_l_; }; #endif // MIDIOUTPUT_HH diff --git a/hdr/midistream.hh b/hdr/midistream.hh index 34e9c9b523..769cd23250 100644 --- a/hdr/midistream.hh +++ b/hdr/midistream.hh @@ -13,10 +13,10 @@ struct Midi_stream { ostream* os_p_; String filename_str_; - int tempo_i_; + int clocks_per_4_i_; int tracks_i_; - Midi_stream( String filename_str, int tracks_i, int tempo_i ); + Midi_stream( String filename_str, int tracks_i, int clocks_per_4_i_ ); ~Midi_stream(); Midi_stream& operator <<( String str ); diff --git a/hdr/midiwalker.hh b/hdr/midiwalker.hh index 3673ae080b..839ba11a7f 100644 --- a/hdr/midiwalker.hh +++ b/hdr/midiwalker.hh @@ -26,6 +26,8 @@ class Midi_walker : public PCursor { /* *************** */ void do_stop_notes(Moment); + + void output_event(Midi_item&, Moment); public: Midi_walker(Staff*, Midi_track*); diff --git a/hdr/my-midi-parser.hh b/hdr/my-midi-parser.hh index 68b238a795..fd7e088654 100644 --- a/hdr/my-midi-parser.hh +++ b/hdr/my-midi-parser.hh @@ -9,7 +9,6 @@ #include "proto.hh" #include "varray.hh" #include "string.hh" -// #include "plist.hh" int yyparse(); @@ -21,9 +20,29 @@ public: void add_score( Midi_score* midi_score_p ); void error( char const* sz_l ); int parse(); + void forward( Real f ); + 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( String filename_str ); + void set_division( int clocks_per_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 ); private: + Real now_f_; + Real step_f_; + + static int const CHANNELS_i = 16; + static int const PITCHES_i = 128; + Real running_f_f_a_[ CHANNELS_i ][ PITCHES_i ]; + Array midi_score_p_array_; + int clocks_per_whole_i_; + Midi_key* midi_key_p_; + Midi_tempo* midi_tempo_p_; + Midi_time* midi_time_p_; + char const* defined_ch_c_l_; int fatal_error_i_; My_midi_lexer* midi_lexer_p_; diff --git a/hdr/proto.hh b/hdr/proto.hh index 8146e81a63..0f2a007c79 100644 --- a/hdr/proto.hh +++ b/hdr/proto.hh @@ -66,12 +66,17 @@ struct Meter; struct Meter_register; struct Midi_def; struct Midi_duration; +struct Midi_event; struct Midi_header; struct Midi_item; +struct Midi_key; +struct Midi_note; struct Midi_output; struct Midi_pitch; struct Midi_staff; struct Midi_stream; +struct Midi_tempo; +struct Midi_time; struct Midi_track; struct Midi_walker; struct Mixed_qp; diff --git a/hdr/sourcefile.hh b/hdr/sourcefile.hh index 36c7aaa575..251efd517e 100644 --- a/hdr/sourcefile.hh +++ b/hdr/sourcefile.hh @@ -13,15 +13,18 @@ public: /** @return path to opened file. */ - Source_file( String &filename_str ); - ~Source_file(); + // jcn: ugh! filename gets changed!, why? + Source_file( String& filename_str ); + virtual ~Source_file(); + char const* ch_c_l(); - String error_str( char const* pos_ch_c_l ); + virtual String error_str( char const* pos_ch_c_l ); istream* istream_l(); bool in_b( char const* pos_ch_c_l ); - int line_i( char const* pos_ch_c_l ); + off_t length_off(); + virtual int line_i( char const* pos_ch_c_l ); String name_str(); - String file_line_no_str(const char *ch_c_l ); + String file_line_no_str( char const* ch_c_l ); private: void close(); diff --git a/input/Makefile b/input/Makefile index 5e7ff85249..92dfaf11c5 100644 --- a/input/Makefile +++ b/input/Makefile @@ -1,12 +1,12 @@ default: ; -DISTFILES=Makefile kortjakje.ly pavane.ly maartje.ly\ +DISTFILES=Makefile kortjakje.ly maartje.ly\ cadenza.ly scales.ly standchen.ly twinkle.ly\ wohltemperirt.ly\ error.ly midi.ly plet.ly\ martien.ly mlalt.ly mlvio1.ly mlvio2.ly mlcello.ly\ coriolan-alto.ly rhythm.ly \ - standchen.tex pavane.tex scsii-menuetto.tex scsii-menuetto.ly\ + standchen.tex scsii-menuetto.tex scsii-menuetto.ly\ martien.tex diff --git a/input/midi.ly b/input/midi.ly index bdb0a48d38..38e5073778 100644 --- a/input/midi.ly +++ b/input/midi.ly @@ -30,11 +30,11 @@ bass_staf = staff { score { staff { mstaf } staff { bass_staf } + commands { + meter { 2 * 4} + } midi { tempo 4:120 } - commands { - meter { 2 * 4 } - } } diff --git a/input/pavane.ly b/input/pavane.ly deleted file mode 100644 index bb7fd643b0..0000000000 --- a/input/pavane.ly +++ /dev/null @@ -1,118 +0,0 @@ -% Pavane pour une Infante d\'efunte -% by Maurice Ravel -% -% Ravel deceased in 1937, so copyright on the music will pass in 2008. -% -% The purpose of this file is to demonstrate features of LilyPond; -% I hope this citation isn't beyond the bounds of "fairness" -% -% -% (there is an accompanying LaTeX file, pavane.tex) -% - -horn = -music { - $ - \octave { ' } - \key{ fis cis } - \duration { 8 } - -% 1 - d2(( [)d e cis `b] | - `a4 [`b cis] [cis `b] )`b4 | - fis2(( [)fis g e d] | - cis4 [d e(] [)e fis d cis] | - `b4 [cis d(] [)d e cis `b] | - )cis2 r2^"c\'edez" | - r4 fis2 fis4 | - fis2^"en mesure" (()[fis e a fis]| - fis4-- e4-- d4-- )e4-- | - `b2()[`b^"un peu retenu" `a( d cis]| -% 11 - )`b [`fis^"en \'elargissant"-- `a-- `b--] cis4-- `b4--| - `fis2 r2 | - cis4^"1er mouvement"( d4^"tr\`es lontain" ()[d cis d e] - \octave { } - | a4 )gis2. | - a4 (b4()[b a b 'cis] | - fis4 e4 )cis2 | - e4( fis4 () [fis e fis gis] | - cis4 `b4())`b8 r8 r4^"tr\`es soutenu" | - - \meter {2 *4} r4 r4 | - \meter {4 *4} - 'cis4_"\dyn ppp"( 'd4 () ['d 'cis 'd 'e] | - a4 )gis2. | - a4 (b4()[b a b 'cis] | - fis4 e4 )cis2 | - e4_"\dyn pp"( fis4()[fis e fis gis] | - cis4_"\dyn mf" `b4())`b8 r8 r4^"un peu plus lent" | - r1 | - r2 r4 r4 %^\fermata -%% cut 'n paste. - \octave { ' } - | d2^"Reprenez le mouvement"( ([)d e cis `b] | - `a4 [`b cis] [cis `b] )`b4 | - fis2(( [)fis g e d] | - cis4 [d e(] [)e fis d cis] | - `b4 [cis d(] [)d e cis `b] | - )cis2 r2^"c\'edez" | - r4 fis2 fis4 | - fis2(^"en mesure"()[fis e a fis] | - fis4-- e4-- d4-- e4-- | - `b2() [`b `a-. d-. cis-.] | - )`b-. [`fis^"large" `a `b] cis4 `b4 `fis2 r2 | - - %% mark B - r1^"1er mouvement" - \duration {8} - | r2 [c-.( e-. c-. )`a-. ] - \octave{} | - | [c e a ]2/3 b4-> () [b c-- e-- a--] | - b4. b8()g2 | - r1 | - r2 [f a f d] - | [f a 'c]2/3 'e4-^ () ['e f-> a-> 'c->] | - 'e4._"sf" 'e8()'c4 r4 | - r1 | - \meter {2 *4} - r4 r4-\fermata - \meter {4 *4} - - \octave { ' } - |d2(( [)d e cis `b] | - `a4 [`b cis] [cis `b] )`b4 | - fis2( ([)fis g e d] | - cis4 [d e(] [)e fis d cis] | - `b4 [cis d(] [)d e cis `b] | - )cis2 r2^"c\'edez" | - r4 fis2 fis4 | - fis2(()[fis e a fis] | - fis4-- e4-- d4-- e4-- - \octave{ } - | b2()[b a 'd 'cis] | - )b [fis a b ] 'cis4 b4 | - fis2 r2 | - r1-\fermata - $ -} -score { - staff { melodic music { horn } - } - paper { - output "pavane.out" - unitspace 1.5 cm - geometric 1.4 - width 12cm - } - commands { - meter {4 *4} - skip {39*1} - bar "|:" - skip {10*1} - bar ":|" - skip {13*1} - bar "||" - } - midi { tempo 4:70 } -} diff --git a/input/pavane.tex b/input/pavane.tex deleted file mode 100644 index 69a136237e..0000000000 --- a/input/pavane.tex +++ /dev/null @@ -1,12 +0,0 @@ -\documentclass{article} %UGH -\usepackage{a4} -\begin{document} -\input lilyponddefs -\input titledefs -\def\interscoreline{\vskip12pt} -\title{Pavane pour une Infante d\'efunte} -\composer{Maurice Ravel} -\instrument{Cor en Fa} -\maketit -\input pavane.out -\end{document} diff --git a/input/standchen.ly b/input/standchen.ly index 4d104f84ee..41abb47413 100644 --- a/input/standchen.ly +++ b/input/standchen.ly @@ -487,6 +487,6 @@ score { output "standchen.out" } midi { - tempo 4:50 + tempo 4:80 } } diff --git a/input/wohltemperirt.ly b/input/wohltemperirt.ly index 7d615a4d1b..32de885acf 100644 --- a/input/wohltemperirt.ly +++ b/input/wohltemperirt.ly @@ -69,7 +69,7 @@ score { } paper {} midi { - tempo 4:80 + tempo 4:90 } } diff --git a/src/binary-source-file.cc b/src/binary-source-file.cc new file mode 100644 index 0000000000..8335a13a5e --- /dev/null +++ b/src/binary-source-file.cc @@ -0,0 +1,58 @@ +// +// binary-source-file.cc +// + +#include // INT_MAX +#include + +#include "proto.hh" +#include "plist.hh" +#include "string.hh" +#include "debug.hh" +#include "sourcefile.hh" +#include "binary-source-file.hh" + +Binary_source_file::Binary_source_file( String& filename_str ) + : Source_file( filename_str ) +{ +} + +Binary_source_file::~Binary_source_file() +{ +} + +String +Binary_source_file::error_str( char const* pos_ch_c_l ) +{ + assert( this ); + if ( !in_b( pos_ch_c_l ) ) + return ""; + + char const* begin_ch_c_l = pos_ch_c_l - 8 >? ch_c_l(); + char const* end_ch_c_l = pos_ch_c_l + 7 add( sourcefile_p ); sourcefile_l_ = sourcefile_p; is = sourcefile_l_->istream_l(); diff --git a/src/midi-event.cc b/src/midi-event.cc index 2e295a5b13..850379271c 100644 --- a/src/midi-event.cc +++ b/src/midi-event.cc @@ -3,7 +3,16 @@ // // copyright 1997 Jan Nieuwenhuizen +#include #include "proto.hh" + +#include "plist.hh" // all for midi-main.hh +#include "string.hh" +#include "source.hh" +#include "sourcefile.hh" +#include "midi-main.hh" // *tors + +#include "moment.hh" #include "midi-event.hh" Midi_event::Midi_event() @@ -14,3 +23,210 @@ Midi_event::~Midi_event() { } +String +Midi_event::mudela_str() +{ + return mudela_str_; +} + +Midi_key::Midi_key( int accidentals_i, int minor_i ) +{ + accidentals_i_ = accidentals_i; + minor_i_ = minor_i; + if ( !minor_i_ ) + key_i_ = ( ( accidentals_i % 7 )[ "cgdaebf" ] - 'a' + 2 ) % 7; + else + key_i_ = ( ( -accidentals_i % 7 )[ "fbeadg" ] - 'a' + 2 ) % 7; + mudela_str_ = String( "\\key\\" ); + if ( !minor_i_ ) + mudela_str_ += String( (char)( key_i_ - 2 + 'A' ) ); + else + mudela_str_ += String( (char)( key_i_ - 2 + 'a' ) ); +} + +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 ( accidentals_i_ < 0 ) { + accidental_i = - accidental_i; + notename_i = ( notename_i + 1 ) % 7; + } + + String notename_str = (char)( ( ( notename_i + key_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--; + return notename_str; +} + +Midi_key::~Midi_key() +{ +} + +Midi_note::Midi_note( Midi_key* midi_key_l, Midi_time* midi_time_l, int clocks_per_whole_i, int pitch_i, Real delta_time_f ) +{ + mudela_str_ = midi_key_l->notename_str( pitch_i ); + mudela_str_ += midi_time_l->duration_str( clocks_per_whole_i, delta_time_f ); +} + +Midi_note::~Midi_note() +{ +} + +Midi_tempo::Midi_tempo( int useconds_per_4_i ) +{ + useconds_per_4_i_ = useconds_per_4_i; + seconds_per_1_f_ = (Real)useconds_per_4_i_ * 4 / 1e6; + mudela_str_ = "\\Tempo: "; + mudela_str_ += String( useconds_per_4_i_ ); + mudela_str_ += String( ": " ) + + String( get_tempo_i( Moment( 1, 4 ) ) ) + + String( " 4 per minute" ); +} + +Midi_tempo::~Midi_tempo() +{ +} + +int +Midi_tempo::get_tempo_i( Moment moment ) +{ + return Moment( 60 ) / moment / Moment( seconds_per_1_f_ ); +} + +Midi_time::Midi_time( int num_i, int den_i, int clocks_i, int count_32_i ) +{ +// we should warn, at least! +// assert( count_32_i == 8 ); + if ( count_32_i != 8 ) + warning( String( "#32 in quarter: " ) + String( count_32_i ), 0 ); + num_i_ = num_i; + den_i_ = 2 << den_i; + // huh?, see midiitem.cc; reasonably for fugue1.midi +// whole_clocks_i_ = clocks_i * 4 * 10; + whole_clocks_i_ = clocks_i * 4; +// whole_clocks_i_ = clocks_i; + mudela_str_ = "\\Time: "; + mudela_str_ += String( num_i_ ) + "/" + String( den_i_ ) + + ", " + String( whole_clocks_i_ ) + + ": " + String( count_32_i ); +} + +Midi_time::~Midi_time() +{ +} + +String +Midi_time::duration_str( int clocks_per_whole_i, Real delta_time_f ) +{ + dtor << "(" << delta_time_f; + String str; + + Moment delta_time_moment = 1.0; + if ( delta_time_f ) { + // 288/96*.25 = .75 + // 96/96*.25 = .25 + // 24/96*.25 = 0.0625 +// delta_time_moment = Moment( delta_time_f ) / Moment( whole_clocks_i() ); + if ( clocks_per_whole_i > 0 ) + delta_time_moment = Moment( delta_time_f ) / Moment( clocks_per_whole_i ); + else + delta_time_moment = Moment( -clocks_per_whole_i ) / Moment( delta_time_f ); + } + + dtor << ", " << (Real)delta_time_moment << "): "; + + static Real sync_f = 1; + delta_time_moment = delta_time_moment / sync_f; + + double dummy_f; + if ( ( sync_f == 1 ) + && ( abs( modf( (Real)delta_time_moment / ( (Real)1 / 64 / 3 ), &dummy_f ) ) ) > 1e-6 ) { + sync_f = (Real)delta_time_moment / 0.125; + delta_time_moment = (Real)delta_time_moment / sync_f; + mtor << "\nsyncing: " << sync_f << ", " +// << (Real)sync_f / usecond24th_per_clock_i << endl; + << (Real)whole_clocks_i() << endl; + } + + static bool must_resync_bo = false; + if ( ( (Real)delta_time_moment / 0.125 > 16 ) + || ( (Real)delta_time_moment / 0.125 < ( (Real)1 / 16 ) ) ) + must_resync_bo = true; + + if ( must_resync_bo ) { + must_resync_bo = false; + delta_time_moment = delta_time_moment * sync_f; + sync_f = (Real)delta_time_moment / 0.125; + delta_time_moment = (Real)delta_time_moment / sync_f; + mtor << "\nresyncing: " << sync_f << ", " +// << (Real)sync_f / usecond24th_per_clock_i << endl; + << (Real)whole_clocks_i() << endl; + } + + if ( !delta_time_moment ) + return "0"; + + // output of modf: double + double duration_f = 0; + Real rest_f = modf( ( Moment( 1 ) / delta_time_moment ), &duration_f ); + int dots_i = 0; + int plet_type_i = 0; + if ( rest_f ) { + // output of modf: double + double dots_f = 0; + Real dots_rest_f = modf( rest_f * 3, &dots_f ); + if ( !dots_rest_f ) + dots_i = (int)rint( dots_f ); + else if ( abs( dots_rest_f - rint( dots_rest_f ) ) < 1e-8 ) + dots_i = (int)rint( dots_rest_f ); + // try 3plet + else if ( !modf( (Real)3 * delta_time_moment / 2, &duration_f ) ) + plet_type_i = 3; + // try 6plet + else if ( !modf( (Real)6 * delta_time_moment / 2, &duration_f ) ) + plet_type_i = 6; + else { +// str += String( "\n*" ) + String( (int)( 1 / rest_f ) ); + str += String( "\n*" ) + String( rest_f ); + must_resync_bo = true; + } + } + + if ( dots_i ) { + for ( int i = dots_i; i ; i-- ) + delta_time_moment *= (Real)2 / 3; + modf( ( Moment( 1 ) / delta_time_moment ), &duration_f ); + } + + str += String( (int)( duration_f ) ); + if ( dots_i ) + str += String( '.', dots_i ); + if ( plet_type_i ) + str += String( "/" ) + String( plet_type_i ); + + return str; +} + +int +Midi_time::whole_clocks_i() +{ + return whole_clocks_i_; +} + diff --git a/src/midi-lexer.l b/src/midi-lexer.l index d95696dbb5..dfbafd5fbf 100644 --- a/src/midi-lexer.l +++ b/src/midi-lexer.l @@ -1,17 +1,14 @@ %{ // midi-lexer.l -#include +//#include #include "string.hh" #include "proto.hh" +#include "midi-main.hh" #include "my-midi-lexer.hh" #include "midi-parser.hh" -#ifndef MIDI_LEX_DEBUG -#define puts( x ) -#endif - %} %option c++ @@ -40,10 +37,17 @@ VARINT {INT7_8SET}{0,3}{INT7_8UNSET} HEADER MThd TRACK MTrk -RUNNING_STATUS [\x30-\x4f] +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] @@ -69,7 +73,7 @@ SSME [\0x7f][\x03] %% {HEADER}/{INT32} { // using /{INT32}; longer match than {INT32} - puts( "lex: header" ); + dtor << "lex: header" << endl; yy_push_state( int16 ); yy_push_state( int16 ); yy_push_state( int16 ); @@ -78,14 +82,18 @@ SSME [\0x7f][\x03] } {TRACK}/{INT32} { // using /{INT32}; longer match than {INT32} - puts( "lex: track" ); + dtor << "lex: track" << endl; yy_push_state( track ); yy_push_state( int32 ); return TRACK; } - +{INT8} { + error( String( "top level: illegal byte: " ) + + StringConversion::bin2hex_str( String( *YYText() ) ) ); + exit( 1 ); +} {INT32} { - puts( "lex: int32" ); + dtor << "lex: int32" << endl; assert( YYLeng() == 4 ); String str( (Byte const*)YYText(), YYLeng() ); yylval.i = StringConversion::bin2int_i( str ); @@ -93,7 +101,7 @@ SSME [\0x7f][\x03] return INT32; } {INT16} { - puts( "lex: int16" ); + dtor << "lex: int16" << endl; assert( YYLeng() == 2 ); String str( (Byte const*)YYText(), YYLeng() ); yylval.i = StringConversion::bin2int_i( str ); @@ -101,7 +109,7 @@ SSME [\0x7f][\x03] return INT16; } {INT8} { - puts( "lex: int8" ); + dtor << "lex: int8" << endl; assert( YYLeng() == 1 ); // yylval.byte = *(Byte*)YYText(); yylval.i = *(Byte*)YYText(); @@ -110,80 +118,189 @@ SSME [\0x7f][\x03] } {VARINT} { - puts( "lex: track: varint" ); String str( (Byte const*)YYText(), YYLeng() ); yylval.i = My_midi_lexer::varint2int_i( str ); + dtor << String( "lex: track: varint(" ) + + String( yylval.i ) + "): " + + StringConversion::bin2hex_str( str ) << endl; yy_push_state( event ); return VARINT; } - +{INT8} { + error( String( "track: illegal byte: " ) + + StringConversion::bin2hex_str( String( *YYText() ) ) ); + exit( 1 ); +} {RUNNING_STATUS} { - yylval.byte = *(Byte*)YYText(); +// yylval.byte = *(Byte*)YYText(); + yylval.i = *(Byte*)YYText(); + dtor << String ( "lex: running status: " ) + String( yylval.i ) << endl; yy_pop_state(); +// yy_push_state( int8 ); yy_push_state( int8 ); return RUNNING_STATUS; } +{DATA_ENTRY} { +// yylval.byte = *(Byte*)YYText(); + yylval.i = *(Byte*)YYText(); + dtor << String ( "lex: undefined data entry: " ) + String( yylval.i ) << endl; + yy_pop_state(); + yy_push_state( int8 ); + return DATA_ENTRY; +} +{ALL_NOTES_OFF} { + dtor << "lex: all note off" << endl; +// yylval.byte = *(Byte*)YYText(); + yylval.i = *(Byte*)YYText(); + dtor << String ( "lex: all notes off: " ) + String( yylval.i ) << endl; + yy_pop_state(); + yy_push_state( int8 ); + yy_push_state( int8 ); + return ALL_NOTES_OFF; +} {NOTE_OFF} { - puts( "lex: note off" ); - yylval.byte = *(Byte*)YYText(); + dtor << "lex: note off" << endl; +// yylval.byte = *(Byte*)YYText(); + yylval.i = *(Byte*)YYText(); yy_pop_state(); yy_push_state( int8 ); yy_push_state( int8 ); return NOTE_OFF; } {NOTE_ON} { - puts( "lex: note on" ); - yylval.byte = *(Byte*)YYText(); + dtor << "lex: note on" << endl; +// yylval.byte = *(Byte*)YYText(); + yylval.i = *(Byte*)YYText(); yy_pop_state(); yy_push_state( int8 ); yy_push_state( int8 ); return NOTE_ON; } +{POLYPHONIC_AFTERTOUCH} { + dtor << "lex: polyphonic aftertouch" << endl; +// yylval.byte = *(Byte*)YYText(); + yylval.i = *(Byte*)YYText(); + yy_pop_state(); + yy_push_state( int8 ); + yy_push_state( int8 ); + return POLYPHONIC_AFTERTOUCH; +} +{CONTROLMODE_CHANGE} { + dtor << "lex: controlmode change" << endl; +// yylval.byte = *(Byte*)YYText(); + yylval.i = *(Byte*)YYText(); + yy_pop_state(); + yy_push_state( int8 ); + yy_push_state( int8 ); + return CONTROLMODE_CHANGE; +} {PROGRAM_CHANGE} { - yylval.byte = *(Byte*)YYText(); + dtor << "lex: program change" << endl; +// yylval.byte = *(Byte*)YYText(); + yylval.i = *(Byte*)YYText(); yy_pop_state(); yy_push_state( int8 ); return PROGRAM_CHANGE; } +{CHANNEL_AFTERTOUCH} { + dtor << "lex: channel aftertouch" << endl; +// yylval.byte = *(Byte*)YYText(); + yylval.i = *(Byte*)YYText(); + yy_pop_state(); + yy_push_state( int8 ); + yy_push_state( int8 ); + return CHANNEL_AFTERTOUCH; +} +{PITCHWHEEL_RANGE} { + dtor << "lex: pitchwheel range" << endl; +// yylval.byte = *(Byte*)YYText(); + yylval.i = *(Byte*)YYText(); + yy_pop_state(); + yy_push_state( int8 ); + yy_push_state( int8 ); + return PITCHWHEEL_RANGE; +} +{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( int8 ); //? + yy_push_state( data ); + return SYSEX_EVENT2; +} {META_EVENT} { + dtor << "lex: meta" << endl; yy_push_state( meta_event ); return META_EVENT; } - +{INT8} { + error( String( "event: illegal byte: " ) + + StringConversion::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; } {TEXT} { // len data + dtor << "lex: text" << endl; + yy_pop_state(); + yy_pop_state(); yy_push_state( data ); return TEXT; } {COPYRIGHT} { + dtor << "lex: copyright" << endl; + yy_pop_state(); + yy_pop_state(); yy_push_state( data ); return COPYRIGHT; } {TRACK_NAME} { + dtor << "lex: track name" << endl; + yy_pop_state(); + yy_pop_state(); yy_push_state( data ); return TRACK_NAME; } {INSTRUMENT_NAME} { + dtor << "lex: instrument name" << endl; + yy_pop_state(); + yy_pop_state(); yy_push_state( data ); return INSTRUMENT_NAME; } {LYRIC} { + dtor << "lex: lyric" << endl; + yy_pop_state(); + yy_pop_state(); yy_push_state( data ); return LYRIC; } {MARKER} { + dtor << "lex: marker" << endl; + yy_pop_state(); + yy_pop_state(); yy_push_state( data ); return MARKER; } {CUE_POINT} { + dtor << "lex: cue point" << endl; + yy_pop_state(); + yy_pop_state(); yy_push_state( data ); return CUE_POINT; } {TEMPO} { // tttttt usec - puts( "lex: tempo" ); + dtor << "lex: tempo" << endl; yy_pop_state(); yy_pop_state(); yy_push_state( int8 ); @@ -192,6 +309,7 @@ SSME [\0x7f][\x03] return TEMPO; } {SMPTE_OFFSET} { // hr mn se fr ff + dtor << "lex: smpte offset" << endl; yy_pop_state(); yy_pop_state(); yy_push_state( int8 ); @@ -202,7 +320,7 @@ SSME [\0x7f][\x03] return SMPTE_OFFSET; } {TIME} { // nn dd cc bb - puts( "lex: time" ); + dtor << "lex: time" << endl; yy_pop_state(); yy_pop_state(); yy_push_state( int8 ); @@ -212,7 +330,7 @@ SSME [\0x7f][\x03] return TIME; } {KEY} { // sf mi - puts( "lex: key" ); + dtor << "lex: key" << endl; yy_pop_state(); yy_pop_state(); yy_push_state( int8 ); @@ -220,24 +338,32 @@ SSME [\0x7f][\x03] return KEY; } {SSME} { // len data + dtor << "lex: smme" << endl; yy_pop_state(); yy_pop_state(); yy_push_state( data ); return SSME; } {END_OF_TRACK} { - puts( "lex: end of track" ); + dtor << "lex: end of track" << endl; yy_pop_state(); yy_pop_state(); yy_pop_state(); return END_OF_TRACK; } {INT8} { - yylval.byte = *(Byte*)YYText(); + warning( String( "meta_event: unimplemented event: " ) + + StringConversion::bin2hex_str( String( *YYText() ) ), + *this->here_ch_c_l() ); + yy_pop_state(); + yy_pop_state(); + yy_push_state( int8 ); + yy_push_state( int8 ); return INT8; } {VARINT} { + dtor << "lex: data" << endl; String str( (Byte const*)YYText(), YYLeng() ); int i = My_midi_lexer::varint2int_i( str ); String* str_p = new String; @@ -245,10 +371,13 @@ SSME [\0x7f][\x03] *str_p += (char)yyinput(); yylval.str_p = str_p; yy_pop_state(); - yy_pop_state(); return DATA; } - +{INT8} { + error( String( "data: illegal byte: " ) + + StringConversion::bin2hex_str( String( *YYText() ) ) ); + exit( 1 ); +} <> { // mtor << "<>"; diff --git a/src/midi-main.cc b/src/midi-main.cc index 3735517f13..5b6ecb3e2d 100644 --- a/src/midi-main.cc +++ b/src/midi-main.cc @@ -7,10 +7,14 @@ #include #include "proto.hh" #include "plist.hh" +#include "version.hh" +#include "fversion.hh" #include "string.hh" +#include "lgetopt.hh" #include "source.hh" #include "sourcefile.hh" #include "midi-main.hh" +#include "moment.hh" #include "midi-event.hh" #include "midi-track.hh" #include "my-midi-lexer.hh" @@ -19,9 +23,12 @@ Source source; Source* source_l_g = &source; +Verbose level_ver = NORMAL_ver; + //ugh char const* defined_ch_c_l = 0; +// ugh, another global String find_file( String str ) { @@ -32,7 +39,7 @@ find_file( String str ) void message( String message_str, char const* context_ch_c_l ) { - String str = "lilypond: "; + String str = "m2m: "; Source_file* sourcefile_l = source_l_g->sourcefile_l( context_ch_c_l ); if ( sourcefile_l ) { str += sourcefile_l->file_line_no_str(context_ch_c_l) + String(": "); @@ -64,11 +71,110 @@ error( String message_str, char const* context_ch_c_l ) midi_lexer_l_g->errorlevel_i_ |= 1; } +void +help() +{ + btor << + "--debug, -d be really verbose\n" + "--help, -h This help\n" + "--include, -I add to file search path.\n" + "--output, -o set default output\n" + "--quiet, -q be quiet\n" + "--verbose, -v be verbose\n" + "--warranty, -w show warranty & copyright\n" + ; +} + +void +identify() +{ + mtor << "This is m2m " << VERSIONSTR << "/FlowerLib " << FVERSIONSTR + << " of " << __DATE__ << " " << __TIME__ << endl; +} + +void +notice() +{ + mtor << + "\n" + "M2m, translate midi to mudela.\n" + "Copyright (C) 1997 by\n" + " Han-Wen Nienhuys \n" +// "Contributors\n" + " Jan Nieuwenhuizen \n" +// " Mats Bengtsson \n" + "\n" + " This program is free software; you can redistribute it and/or\n" + "modify it under the terms of the GNU General Public License version 2\n" + "as published by the Free Software Foundation.\n" + "\n" + " This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" + "General Public License for more details.\n" + "\n" + " You should have received a copy (refer to the file COPYING) of the\n" + "GNU General Public License along with this program; if not, write to\n" + "the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,\n" + "USA.\n"; +} + int main( int argc_i, char* argv_sz_a[] ) { - if ( !argc_i ) - return 2; - My_midi_parser midi_parser( argv_sz_a[ 1 ] ); - return midi_parser.parse(); + long_option_init long_option_init_a[] = { + 0, "debug", 'd', + 0, "help", 'h', +// 1, "include", 'I', + 1, "output", 'o', + 0, "quiet", 'q', + 0, "verbose", 'v', + 0, "warranty", 'w', + 0,0,0 + }; + Getopt_long getopt_long( argc_i, argv_sz_a, long_option_init_a ); + identify(); + + String output_str; + while ( long_option_init* long_option_init_p = getopt_long() ) + switch ( long_option_init_p->shortname ) { + case 'd': + level_ver = DEBUG_ver; + break; + case 'h': + help(); + exit( 0 ); + break; +// case 'I': +// path->push( getopt_long.optarg ); +// break; + case 'o': + output_str = getopt_long.optarg; + break; + case 'q': + level_ver = QUIET_ver; + break; + case 'v': + level_ver = VERBOSE_ver; + break; + case 'w': + notice(); + exit( 0 ); + break; + default: + assert( 0 ); + break; + } + + char* arg_sz = 0; + while ( ( arg_sz = getopt_long.get_next_arg() ) ) { + My_midi_parser midi_parser( arg_sz ); + int error_i = midi_parser.parse(); + if ( error_i ) + return error_i; + error_i = midi_parser.output( output_str ); + if ( error_i ) + return error_i; + } + return 0; } diff --git a/src/midi-parser.y b/src/midi-parser.y index 519266f1fb..56680f4b77 100644 --- a/src/midi-parser.y +++ b/src/midi-parser.y @@ -2,8 +2,16 @@ #include +#include "proto.hh" // ugh, these all for midi-main.hh +#include "plist.hh" +#include "string.hh" +#include "sourcefile.hh" +#include "source.hh" +#include "midi-main.hh" // *tors + #include "my-midi-lexer.hh" #include "my-midi-parser.hh" +#include "moment.hh" #include "midi-event.hh" #include "midi-track.hh" #include "midi-score.hh" @@ -32,14 +40,21 @@ %token END_OF_TRACK TEMPO SMPTE_OFFSET TIME KEY SSME %token INT8 INT16 INT32 INT7_8UNSET INT7_8SET VARINT -%token RUNNING_STATUS NOTE_OFF NOTE_ON PROGRAM_CHANGE +%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 DATA +%type varint %type header midi_score %type track %type event -%type the_event meta_event text_event midi_event sysex_event -%type running_status note_off note_on program_change +%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 %% @@ -60,6 +75,7 @@ midi_score: header: HEADER INT32 INT16 INT16 INT16 { $$ = new Midi_score( $3, $4, $5 ); + midi_parser_l_g->set_division( $5 ); } ; @@ -73,12 +89,25 @@ track: ; event: - VARINT the_event { + varint the_event { + if ( $2 && $2->mudela_str().length_i() ) { + if ( ( $2->mudela_str()[ 0 ] >= 'a' ) + && $2->mudela_str()[ 0 ] <= 'g' ) + qtor << $2->mudela_str() << " "; + else + vtor << $2->mudela_str() << " "; + } } ; +varint: + VARINT { + midi_parser_l_g->forward( $1 ); + } + ; + the_event: - meta_event { + meta_event { } | midi_event { } @@ -88,86 +117,165 @@ the_event: meta_event: META_EVENT the_meta_event { - }; + $$ = $2; + } + | + META_EVENT INT8 INT8 INT8 { + $$ = 0; + } + ; the_meta_event: SEQUENCE INT16 { } | text_event DATA { + $$ = 0; + vtor << *$2 << endl; + delete $2; } | END_OF_TRACK { + $$ = 0; } | TEMPO INT8 INT8 INT8 { + $$ = new Midi_tempo( ( $2 << 16 ) + ( $3 << 8 ) + $4 ); + vtor << $$->mudela_str() << endl; // ?? waai not at event: + midi_parser_l_g->set_tempo( ( $2 << 16 ) + ( $3 << 8 ) + $4 ); } | SMPTE_OFFSET INT8 INT8 INT8 INT8 INT8 { + $$ = 0; } | TIME INT8 INT8 INT8 INT8 { + $$ = new Midi_time( $2, $3, $4, $5 ); + vtor << $$->mudela_str() << endl; // ?? waai not at event: + midi_parser_l_g->set_time( $2, $3, $4, $5 ); } | KEY INT8 INT8 { + $$ = new Midi_key( $2, $3 ); + midi_parser_l_g->set_key( $2, $3 ); } | SSME DATA { + $$ = 0; + delete $2; } ; text_event: TEXT { + vtor << endl << "Text: "; } | COPYRIGHT { + vtor << endl << "Copyright: "; } | TRACK_NAME { + vtor << endl << "Track name: "; } | INSTRUMENT_NAME { + vtor << endl << "Instrument name: "; } | LYRIC { + vtor << endl << "Lyric: "; } | MARKER { + vtor << endl << "Marker: "; } | CUE_POINT { + vtor << endl << "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 { + RUNNING_STATUS INT8 { //INT8 { + $$ = 0; + } + ; + +data_entry: + DATA_ENTRY INT8 { + $$ = 0; + } + ; + +all_notes_off: + ALL_NOTES_OFF INT8 INT8 { + $$ = 0; } ; note_off: NOTE_OFF INT8 INT8 { + int i = $1; + i = i & ~0x80; + $$ = midi_parser_l_g->note_end_midi_event_p( $1 & ~0x80, $2, $3 ); } ; note_on: NOTE_ON INT8 INT8 { - int pitch_i = $2; - // assuming key of C - String notename_str = ( pitch_i % 12 )[ "ccddeffggaab" ]; - static int accidental_i_a[ 12 ] = { 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0 }; - int accidental_i = accidental_i_a[ pitch_i % 12 ]; - if ( accidental_i == 1 ) - notename_str += "is"; - cout << "note(" << pitch_i << "): " << notename_str << endl; + int i = $1; + i = i & ~0x90; + $$ = 0; + midi_parser_l_g->note_begin( $1 & ~0x90, $2, $3 ); + } + ; + +polyphonic_aftertouch: + POLYPHONIC_AFTERTOUCH INT8 INT8 { + $$ = 0; + } + ; + +controlmode_change: + CONTROLMODE_CHANGE INT8 INT8 { + $$ = 0; } ; program_change: - PROGRAM_CHANGE { + PROGRAM_CHANGE INT8 { + $$ = 0; + } + ; + +channel_aftertouch: + CHANNEL_AFTERTOUCH INT8 INT8 { + $$ = 0; + } + ; + +pitchwheel_range: + PITCHWHEEL_RANGE INT8 INT8 { + $$ = 0; } ; sysex_event: - SYSEX_EVENT1 { + SYSEX_EVENT1 DATA { + $$ = 0; } - | SYSEX_EVENT2 { + | SYSEX_EVENT2 DATA { // INT8 ? + $$ = 0; } ; diff --git a/src/midi-track.cc b/src/midi-track.cc index 99390c3346..77abf04e1c 100644 --- a/src/midi-track.cc +++ b/src/midi-track.cc @@ -4,6 +4,8 @@ // copyright 1997 Jan Nieuwenhuizen #include "proto.hh" +#include "string.hh" +#include "moment.hh" #include "midi-event.hh" #include "midi-track.hh" diff --git a/src/midiitem.cc b/src/midiitem.cc index b86eb95f1b..0ce9ead5e0 100644 --- a/src/midiitem.cc +++ b/src/midiitem.cc @@ -57,7 +57,7 @@ Midi_duration::str() return String( ""; } -Midi_header::Midi_header( int format_i, int tracks_i, int tempo_i ) +Midi_header::Midi_header( int format_i, int tracks_i, int clocks_per_4_i ) { String str; @@ -67,7 +67,7 @@ Midi_header::Midi_header( int format_i, int tracks_i, int tempo_i ) String tracks_str = StringConversion::int2hex_str( tracks_i, 4, '0' ); str += StringConversion::hex2bin_str( tracks_str ); - String tempo_str = StringConversion::int2hex_str( tempo_i, 4, '0' ); + String tempo_str = StringConversion::int2hex_str( clocks_per_4_i, 4, '0' ); str += StringConversion::hex2bin_str( tempo_str ); set( "MThd", str, "" ); @@ -103,12 +103,8 @@ Midi_item::output_midi( Midi_stream& midi_stream_r ) Midi_note::Midi_note( Melodic_req* melreq_l, int channel_i, bool on_bo ) { - - if (!melreq_l ) - pitch_i_ = INT_MAX-1; // any pitch. - else - pitch_i_ = melreq_l->pitch() + c0_pitch_i_c_; - + assert(melreq_l); + pitch_i_ = melreq_l->pitch() + c0_pitch_i_c_; channel_i_ = channel_i; // poor man-s staff dynamics: @@ -130,6 +126,20 @@ Midi_note::str() return String( "" ); } +Midi_tempo::Midi_tempo( int tempo_i ) +{ + tempo_i_ = tempo_i; +} + +String +Midi_tempo::str() +{ + int useconds_per_4_i = 60 * (int)1e6 / tempo_i_; + String str = "ff5103"; + str += StringConversion::int2hex_str( useconds_per_4_i, 6, '0' ); + return StringConversion::hex2bin_str( str ); +} + Midi_track::Midi_track( int number_i ) { // 4D 54 72 6B MTrk @@ -149,7 +159,7 @@ Midi_track::Midi_track( int number_i ) number_i_ = number_i; char const* data_ch_c_l = "00" "ff58" "0404" "0218" "08" - "00" "ff51" "0307" "a120" +// "00" "ff51" "0307" "a120" // why a key at all, in midi? // key: C "00" "ff59" "02" "00" "00" @@ -177,10 +187,8 @@ Midi_track::add( int delta_time_i, String event_str ) void Midi_track::add( Moment delta_time_moment, Midi_item* mitem_l ) { - // silly guess: 24 midi clocks per 4 note - // huh? -// int delta_time_i = delta_time_moment / Moment( 1, 4 ) * Moment( 24 ); - int delta_time_i = delta_time_moment / Moment( 1, 4 ) * Moment( 96 ); + // use convention of 384 clocks per 4 + int delta_time_i = delta_time_moment * Moment( 384 ) / Moment( 1, 4 ); add( delta_time_i, mitem_l->str() ); } diff --git a/src/midioutput.cc b/src/midioutput.cc index d84649fd49..f1e5e6b412 100644 --- a/src/midioutput.cc +++ b/src/midioutput.cc @@ -21,9 +21,14 @@ Midi_output:: Midi_output(Score* score_l, Midi_def* midi_l ) { + midi_l_ = midi_l; + Midi_stream midi_stream(midi_l->outfile_str_, score_l->staffs_.size(), - midi_l->get_tempo_i(Moment(1, 4))); + 384 ); +// oeps, not tempo, but clocks per 4 (384 convention) +// must set tempo in tempo request +// midi_l->get_tempo_i(Moment(1, 4))); midi_stream_l_ = &midi_stream; int track_i=0; @@ -38,6 +43,8 @@ void Midi_output::do_staff(Staff*st_l,int track_i) { Midi_track midi_track( track_i ); + Midi_tempo midi_tempo( midi_l_->get_tempo_i( Moment( 1, 4 ) ) ); + midi_track.add( Moment( 0.0 ), &midi_tempo ); for (Midi_walker w (st_l, &midi_track); w.ok(); w++) w.process_requests(); diff --git a/src/midistream.cc b/src/midistream.cc index 73fe2e4733..84b105d27d 100644 --- a/src/midistream.cc +++ b/src/midistream.cc @@ -13,11 +13,11 @@ #include "midistream.hh" #include "debug.hh" -Midi_stream::Midi_stream( String filename_str, int tracks_i, int tempo_i ) +Midi_stream::Midi_stream( String filename_str, int tracks_i, int clocks_per_4_i ) { filename_str_ = filename_str; tracks_i_ = tracks_i; - tempo_i_ = tempo_i; + clocks_per_4_i_ = clocks_per_4_i; open(); header(); } @@ -75,7 +75,7 @@ Midi_stream::header() // *os_p_ << str; // *this << Midi_header( 1, 1, tempo_i_ ); - *this << Midi_header( 1, tracks_i_, tempo_i_ ); + *this << Midi_header( 1, tracks_i_, clocks_per_4_i_ ); } void diff --git a/src/midiwalker.cc b/src/midiwalker.cc index 036a227686..b8350bc2cc 100644 --- a/src/midiwalker.cc +++ b/src/midiwalker.cc @@ -21,6 +21,7 @@ Midi_walker::Midi_walker(Staff *st_l, Midi_track* track_l) track_l_ = track_l; last_moment_= 0; } + /** output notestop events for all notes which end before #max_moment# */ @@ -32,12 +33,18 @@ Midi_walker::do_stop_notes(Moment max_moment) Melodic_req * req_l = stop_notes.get(); Midi_note note(req_l, track_l_->number_i_, false); - - Moment delta_t = stop_moment-last_moment_ ; - last_moment_ += delta_t; - track_l_->add(delta_t, ¬e ); + output_event(note, stop_moment); } } +/** advance the track to #now#, output the item, and adjust current + "moment". */ +void +Midi_walker::output_event(Midi_item &i, Moment now) +{ + Moment delta_t = now - last_moment_ ; + last_moment_ += delta_t; + track_l_->add(delta_t, &i ); +} void Midi_walker::process_requests() @@ -46,13 +53,15 @@ Midi_walker::process_requests() for ( int i = 0; i < ptr()->musicalreq_l_arr_.size(); i++ ) { Rhythmic_req *n = ptr()->musicalreq_l_arr_[i]->rhythmic(); - if ( !n || !(n->note() || n->rest()) ) + if ( !n) + continue; + Note_req * note_l = n->note(); + if (!note_l) continue; - Midi_note note(n->melodic(), track_l_->number_i_, true); - stop_notes.enter(n->melodic(), n->duration() + ptr()->when() ); - Moment dt = 0; - track_l_->add(dt, ¬e); + Midi_note note(note_l, track_l_->number_i_, true); + stop_notes.enter(note_l, n->duration() + ptr()->when() ); + output_event(note, ptr()->when()); } } diff --git a/src/my-midi-lexer.cc b/src/my-midi-lexer.cc index 70c860bcf5..a070992f53 100644 --- a/src/my-midi-lexer.cc +++ b/src/my-midi-lexer.cc @@ -19,7 +19,7 @@ My_midi_lexer* midi_lexer_l_g; My_midi_lexer::My_midi_lexer( String filename_str ) { input_file_p_ = new Input_file( filename_str ); - switch_streams( input_file_p_->is ); + switch_streams( input_file_p_->is ); midi_lexer_l_g = this; errorlevel_i_ = 0; } @@ -56,17 +56,20 @@ My_midi_lexer::here_ch_c_l() return input_file_p_->sourcefile_l_->ch_c_l() + yyin->tellg(); } -#if 0 // ?? huh -int -My_midi_lexer::yylex() -{ - return 0; -} -#endif - int My_midi_lexer::varint2int_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 << "\nvarint2int:" << StringConversion::bin2hex_str( str ) << endl; + assert( 0 ); // illegal varint return 0; } diff --git a/src/my-midi-parser.cc b/src/my-midi-parser.cc index 51dda6bd15..cd12082239 100644 --- a/src/my-midi-parser.cc +++ b/src/my-midi-parser.cc @@ -3,6 +3,17 @@ // // copyright 1997 Jan Nieuwenhuizen +#include "proto.hh" + +#include "plist.hh" // ugh +#include "string.hh" +#include "sourcefile.hh" +#include "source.hh" +#include "midi-main.hh" // *tors + +#include "my-midi-lexer.hh" +#include "my-midi-parser.hh" +#include "midi-event.hh" #include "my-midi-lexer.hh" #include "my-midi-parser.hh" @@ -19,14 +30,37 @@ My_midi_parser::My_midi_parser( String filename_str ) { midi_lexer_p_ = new My_midi_lexer( filename_str ); midi_parser_l_g = this; + + midi_key_p_ = new Midi_key( 0, 0 ); +// midi_tempo_p_ = new Midi_tempo( 384 ); // wiellie dunno! + // 07A120 == 500000 + midi_tempo_p_ = new Midi_tempo( 0x07a120 ); // wiellie dunno! + midi_time_p_ = new Midi_time( 4, 4, 0x24, 8 ); + defined_ch_c_l_ = 0; fatal_error_i_ = 0; + now_f_ = 0; + step_f_ = 0; + + for ( int i = 0; i < CHANNELS_i; i++ ) + for ( int j = 0; j < PITCHES_i; j++ ) + running_f_f_a_[ i ][ j ] = 0; } 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_; +} + +void +My_midi_parser::add_score( Midi_score* midi_score_p ) +{ + midi_score_p_array_.push( midi_score_p ); + cout << endl; } void @@ -38,6 +72,39 @@ My_midi_parser::error( char const* sz_l ) exit( fatal_error_i_ ); } +void +My_midi_parser::forward( Real f ) +{ + // ugh + if ( f ) + step_f_ = f; + now_f_ += step_f_; +} + +void +My_midi_parser::note_begin( int channel_i, int pitch_i, int dyn_i ) +{ + // one pitch a channel at time! + // heu, what if start at t = 0? +// assert( !running_f_f_a_[ channel_i ][ pitch_i ] ); + running_f_f_a_[ channel_i ][ pitch_i ] = now_f_; +} + +Midi_event* +My_midi_parser::note_end_midi_event_p( int channel_i, int pitch_i, int dyn_i ) +{ + Real start_f = running_f_f_a_[ channel_i ] [ pitch_i ]; + // did we start? -> heu, don-t know: what if start at t = 0? +// assert( start_f ); + return new Midi_note( midi_key_p_, midi_time_p_, clocks_per_whole_i_, pitch_i, now_f_ - start_f ); +} + +int +My_midi_parser::output( String filename_str ) +{ + return 0; +} + int My_midi_parser::parse() { @@ -45,8 +112,31 @@ My_midi_parser::parse() } void -My_midi_parser::add_score( Midi_score* midi_score_p ) +My_midi_parser::set_division( int clocks_per_4_i ) { - midi_score_p_array_.push( midi_score_p ); + clocks_per_whole_i_ = clocks_per_4_i * 4; + if ( clocks_per_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/src/sourcefile.cc b/src/sourcefile.cc index 0775719160..eac2b1f84a 100644 --- a/src/sourcefile.cc +++ b/src/sourcefile.cc @@ -34,6 +34,7 @@ Source_file::Source_file( String &filename_str ) open(); map(); + // ugh!?, should call name_str() ! filename_str = name_str_; } @@ -83,15 +84,17 @@ Source_file::error_str( char const* pos_ch_c_l ) } end_ch_c_l--; -// String( char const* p, int length ) is missing!? -// String line_str( begin_ch_c_l, end_ch_c_l - begin_ch_c_l ); - +#if 1 +// String( char const* p, int length ) is missing!? + String line_str( (Byte const*)begin_ch_c_l, end_ch_c_l - begin_ch_c_l ); +#else int length_i = end_ch_c_l - begin_ch_c_l; char* ch_p = new char[ length_i + 1 ]; strncpy( ch_p, begin_ch_c_l, length_i ); ch_p[ length_i ] = 0; String line_str( ch_p ); delete ch_p; +#endif int error_col_i = 0; char const* scan_ch_c_l = begin_ch_c_l; @@ -129,6 +132,12 @@ Source_file::istream_l() return istream_p_; } +off_t +Source_file::length_off() +{ + return size_off_; +} + int Source_file::line_i( char const* pos_ch_c_l ) { @@ -191,8 +200,8 @@ Source_file::unmap() } } String -Source_file::file_line_no_str(const char *cch_c_l ) +Source_file::file_line_no_str(char const *ch_c_l ) { return name_str() + ": " - + String( line_i( cch_c_l ) ); + + String( line_i( ch_c_l ) ); } -- 2.39.5