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