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