]> git.donarmstrong.com Git - lilypond.git/blob - midi2ly/midi-track-parser.cc
3b62ffc106ba0a3e5d5467a9c398dc297d4f47d6
[lilypond.git] / midi2ly / midi-track-parser.cc
1 /*
2   midi-track-parser.cc -- implement
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--1998 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include <assert.h>
10 #include "string-convert.hh"
11 #include "midi2ly-global.hh"
12 #include "midi-track-parser.hh"
13 #include "lilypond-column.hh"
14 #include "lilypond-item.hh"
15 #include "lilypond-score.hh"
16 #include "lilypond-staff.hh"
17
18 Midi_track_parser::Midi_track_parser (Midi_parser_info* info_l, int i)
19 {
20   info_l_ = info_l;
21   at_mom_ = 0;
22   track_info_p_ = 0;
23   lilypond_staff_p_ = new Lilypond_staff (i, "", "", "");
24   parse_header ();
25   parse_delta_time ();
26 }
27
28 Midi_track_parser::~Midi_track_parser ()
29 {
30   delete lilypond_staff_p_;
31   delete track_info_p_;
32 }
33
34 Rational
35 Midi_track_parser::at_mom ()
36 {
37   return at_mom_;
38 }
39
40 bool
41 Midi_track_parser::eot ()
42 {
43   if ( info_l_->byte_L_ < info_l_->end_byte_L_ )
44     return false;
45   return true;
46 }
47
48 void
49 Midi_track_parser::note_end (Lilypond_column* col_l, int channel_i, int pitch_i, int aftertouch_i )
50 {
51   // junk dynamics
52   (void)aftertouch_i;
53
54   assert (col_l);
55
56   for (Cons<Lilypond_note>** pp = &open_note_l_list_.head_; *pp;)
57     {
58       Cons<Lilypond_note>* i = *pp;
59       if ((i->car_->pitch_i_ == pitch_i) && (i->car_->channel_i_ == channel_i))
60         {
61           i->car_->end_column_l_ = col_l;
62           delete open_note_l_list_.remove_cons (pp);
63           return;
64         }
65       else
66         pp = &i->next_;
67     }
68   warning (_f ("Junking note-end event: channel = %d, pitch = %d", 
69                channel_i, pitch_i));
70 }
71
72 void
73 Midi_track_parser::note_end_all (Lilypond_column* col_l)
74 {
75   // find
76   assert (col_l);
77   for (Cons<Lilypond_note>* i = open_note_l_list_.head_; i; i = i->next_)
78     {
79       i->car_->end_column_l_ = col_l;
80     }
81   // UGH UGH. MEMORY LEAK.
82   open_note_l_list_.init ();
83 }
84
85 Lilypond_staff*
86 Midi_track_parser::parse (Lilypond_column* col_l)
87 {
88   Rational mom = at_mom ();
89   while (!eot () && (mom == at_mom ()))
90     {
91       Lilypond_item* p = parse_event (col_l);
92       if (p)
93         lilypond_staff_p_->add_item (p);
94     }
95
96   if (!eot())
97     return 0;
98
99   // catch-all
100   note_end_all (col_l);
101
102   Lilypond_staff* p = lilypond_staff_p_;
103   lilypond_staff_p_ = 0;
104   return p;
105 }
106
107 void
108 Midi_track_parser::parse_delta_time ()
109 {
110   if (eot ())
111     return;
112   int delta_i = get_var_i ();
113   at_mom_ += Rational (delta_i, info_l_->division_1_i_);
114 }
115
116 Lilypond_item*
117 Midi_track_parser::parse_event (Lilypond_column* col_l)
118 {
119   Byte byte = peek_byte ();
120   // RUNNING_STATUS     [\x00-\x5f]
121   if (byte <= 0x5f)
122     {
123       if (running_byte_ <= 0x5f)
124         exit (_ ("invalid running status"));
125       /*
126         'running status' rather means 'missing status'.
127         we'll just pretend we read the running status byte.
128       */
129       byte = running_byte_;
130     }
131   else
132     byte = next_byte ();
133
134   Lilypond_item* item_p = 0;
135   // DATA_ENTRY [\x60-\x79]
136   if ((byte >= 0x60) && (byte <= 0x79))
137     {
138       next_byte ();
139     }
140   // ALL_NOTES_OFF      [\x7a-\x7f]
141   else if ((byte >= 0x7a) && (byte <= 0x7f))
142     {
143       next_byte ();
144       next_byte ();
145       note_end_all (col_l);
146     }
147   // NOTE_OFF   [\x80-\x8f]
148   else if ((byte >= 0x80) && (byte <= 0x8f))
149     {
150       running_byte_ = byte;
151       int channel_i = byte & ~0x90;
152       int pitch_i = (int)next_byte ();
153       int dyn_i = (int)next_byte ();
154       note_end (col_l, channel_i, pitch_i, dyn_i);
155     }
156   // NOTE_ON            [\x90-\x9f]
157   else if ((byte >= 0x90) && (byte <= 0x9f))
158     {
159       running_byte_ = byte;
160       int channel_i = byte & ~0x90;
161       int pitch_i = (int)next_byte ();
162       int dyn_i = (int)next_byte ();
163       /*
164         sss: some broken devices encode NOTE_OFF as
165         NOTE_ON with zero volume
166       */
167       if (dyn_i)
168         {
169           Lilypond_note* p = new Lilypond_note (col_l, channel_i, pitch_i, dyn_i);
170           item_p = p;
171           open_note_l_list_.append (new Cons<Lilypond_note> (p, 0));
172         }
173       else
174         {
175           note_end (col_l, channel_i, pitch_i, dyn_i);
176         }
177     }
178     
179   // POLYPHONIC_AFTERTOUCH      [\xa0-\xaf]
180   else if ((byte >= 0xa0) && (byte <= 0xaf))
181     {
182       running_byte_ = byte;
183       next_byte ();
184       next_byte ();
185     }
186   // CONTROLMODE_CHANGE [\xb0-\xbf]
187   else if ((byte >= 0xb0) && (byte <= 0xbf))
188     {
189       running_byte_ = byte;
190       next_byte ();
191       next_byte ();
192     }
193   // PROGRAM_CHANGE     [\xc0-\xcf]
194   else if ((byte >= 0xc0) && (byte <= 0xcf))
195     {
196       running_byte_ = byte;
197       next_byte ();
198     }
199   // CHANNEL_AFTERTOUCH [\xd0-\xdf]
200   else if ((byte >= 0xd0) && (byte <= 0xdf))
201     {
202       running_byte_ = byte;
203       next_byte ();
204       next_byte ();
205     }
206   // PITCHWHEEL_RANGE   [\xe0-\xef]
207   else if ((byte >= 0xe0) && (byte <= 0xef))
208     {
209       running_byte_ = byte;
210       next_byte ();
211       next_byte ();
212     }
213   // SYSEX_EVENT1       [\xf0]
214   else if (byte == 0xf0)
215     {
216       int length_i = get_var_i ();
217       String str = get_str (length_i);
218     }
219   // SYSEX_EVENT2       [\xf7]
220   else if (byte == 0xf7)
221     {
222       int length_i = get_var_i ();
223       String str = get_str (length_i);
224     }
225   // META_EVENT [\xff]
226   else if (byte == 0xff)
227     {
228       // SEQUENCE       [\x00][\x02]
229       byte = next_byte ();
230       if (byte == 0)
231         {
232           next_byte ();
233           get_i (2);
234         }
235       // YYTEXT         [\x01]
236       // YYCOPYRIGHT    [\x02]
237       // YYTRACK_NAME   [\x03]
238       // YYINSTRUMENT_NAME      [\x04]
239       // YYLYRIC                [\x05]
240       // YYMARKER               [\x06]
241       // YYCUE_POINT    [\x07]
242       else if ((byte >= 0x01) && (byte <= 0x07))
243         {
244           // LOGOUT (DEBUG_ver) << "\n% Text(" << (int)byte << "):" << flush;
245           int length_i = get_var_i ();
246           String str = get_str (length_i);
247           // LOGOUT (DEBUG_ver) << str << endl;
248           Lilypond_text::Type t = (Lilypond_text::Type)byte;
249           Lilypond_text* p = new Lilypond_text (t, str);
250           item_p = p;
251           if (t == Lilypond_text::COPYRIGHT)
252             lilypond_staff_p_->copyright_str_ = p->text_str_;
253           else if (t == Lilypond_text::TRACK_NAME)
254             lilypond_staff_p_->name_str_ = p->text_str_;
255           else if (t == Lilypond_text::INSTRUMENT_NAME)
256             lilypond_staff_p_->instrument_str_ = p->text_str_;
257         }
258       // END_OF_TRACK   [\x2f][\x00]
259       else
260         {
261           Byte next = peek_byte ();
262           if ((byte == 0x2f) && (next == 0x00))
263             {
264               next_byte ();
265               info_l_->byte_L_ = info_l_->end_byte_L_;
266             }
267           // TEMPO              [\x51][\x03]
268           else if ((byte == 0x51) && (next == 0x03))
269             {
270               next_byte ();
271               unsigned useconds_per_4_u = get_u (3);
272               // $$ = new Lilypond_tempo ( ($2 << 16) + ($3 << 8) + $4);
273               // LOGOUT (DEBUG_ver) << $$->str() << endl;
274               Lilypond_tempo* p = new Lilypond_tempo ( useconds_per_4_u );
275               item_p = p;
276               info_l_->score_l_->lilypond_tempo_l_ = p;
277               lilypond_staff_p_->lilypond_tempo_l_ = p;
278             }
279           // SMPTE_OFFSET       [\x54][\x05]
280           else if ((byte == 0x54) && (next == 0x05))
281             {
282               next_byte ();
283               (int)next_byte ();
284               (int)next_byte ();
285               (int)next_byte ();
286               (int)next_byte ();
287               (int)next_byte ();
288             }
289           // TIME               [\x58][\x04]
290           else if ((byte == 0x58) && (next == 0x04))
291             {
292               next_byte ();
293               int num_i = (int)next_byte ();
294               int den_i = (int)next_byte ();
295               int clocks_4_i = (int)next_byte ();
296               int count_32_i = (int)next_byte ();
297               Lilypond_time_signature* p = new Lilypond_time_signature ( num_i, den_i, clocks_4_i, count_32_i );
298               item_p = p;
299               info_l_->score_l_->lilypond_time_signature_l_ = p;
300               info_l_->bar_mom_ = p->bar_mom ();
301               lilypond_staff_p_->lilypond_time_signature_l_ = p;
302             }
303           // KEY                [\x59][\x02]
304           else if ((byte == 0x59) && (next == 0x02))
305             {
306               next_byte ();
307               int accidentals_i = (int)(signed char)next_byte ();
308               int minor_i = (int)(bool)next_byte ();
309               Lilypond_key* p = new Lilypond_key (accidentals_i, minor_i);
310               item_p = p;
311 #if 0
312               info_l_->score_l_->lilypond_key_l_ = p;
313               lilypond_staff_p_->lilypond_key_l_ = p;
314 #endif
315             }
316           // SSME               [\0x7f][\x03]
317           else if ((byte == 0x7f) && (next == 0x03))
318             {
319               next_byte ();
320               int length_i = get_var_i ();
321               String str = get_str (length_i);
322               item_p = new Lilypond_text ((Lilypond_text::Type)byte, str);
323             }
324           else
325             {
326               next_byte ();
327               next_byte ();
328               warning (_ ("unimplemented MIDI meta-event"));
329             }
330         }
331     }
332   else
333     exit (_ ("invalid MIDI event"));
334
335   if (item_p)
336     item_p->lilypond_column_l_ = col_l;
337
338   parse_delta_time ();
339
340   return item_p;
341 }
342
343 void
344 Midi_track_parser::parse_header ()
345 {
346   String str = get_str (4);
347   if ( str != "MTrk" )
348     exit (_ ("MIDI track expected"));
349
350   int length_i = get_i (4);
351   // is this signed?
352   if (length_i < 0)
353     exit (_ ("invalid track length"));
354   assert (!track_info_p_);
355   track_info_p_ = new Midi_parser_info (*info_l_);
356   track_info_p_->end_byte_L_ = track_info_p_->byte_L_ + length_i;
357   forward_byte_L (length_i);
358   //  forward_byte_L (length_i-1);
359   info_l_ = track_info_p_;
360 }