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