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