]> git.donarmstrong.com Git - lilypond.git/blob - modules/midi.c
patch::: 1.5.10.jcn3
[lilypond.git] / modules / midi.c
1 /*
2   midi.c -- implement Python midi parser module
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7             Jan Nieuwenhuizen <janneke@gnu.org>
8
9 */
10
11 /*
12
13 python2
14 import midi
15 s = open ("s.midi").read ()
16 midi.parse_track (s)
17 midi.parse (s)
18
19 */
20
21 #include <python2.0/Python.h>
22
23 #if 0
24 int x = 0;
25 int *track = &x;
26 #define debug_print(f, args...) fprintf (stderr, "%s:%d: track: %p :" f, __FUNCTION__, __LINE__, *track, ##args)
27 #else
28 #define debug_print(f, args...)
29 #endif
30
31 static PyObject *Midi_error;
32 static PyObject *Midi_warning;
33
34 static PyObject *
35 midi_error (char *s)
36 {
37   PyErr_SetString (Midi_error, s);
38   return 0;
39 }
40
41 static PyObject *
42 midi_warning (char *s)
43 {
44   PyErr_SetString (Midi_warning, s);
45   return 0;
46 }
47
48
49 typedef struct message {
50   unsigned char msg;
51   char * description;
52 } message_t;
53
54 message_t channelVoiceMessages[] = {
55   0x80, "NOTE_OFF",
56   0x90, "NOTE_ON",
57   0xA0, "POLYPHONIC_KEY_PRESSURE",
58   0xB0, "CONTROLLER_CHANGE",
59   0xC0, "PROGRAM_CHANGE",
60   0xD0, "CHANNEL_KEY_PRESSURE",
61   0xE0, "PITCH_BEND",
62   0,0
63 };
64
65 message_t channelModeMessages[] = {
66   0x78, "ALL_SOUND_OFF",
67   0x79, "RESET_ALL_CONTROLLERS",
68   0x7A, "LOCAL_CONTROL",
69   0x7B, "ALL_NOTES_OFF",
70   0x7C, "OMNI_MODE_OFF",
71   0x7D, "OMNI_MODE_ON",
72   0x7E, "MONO_MODE_ON",
73   0x7F, "POLY_MODE_ON",
74   0,0
75 };
76
77 message_t metaEvents[] = {
78   0x00, "SEQUENCE_NUMBER",
79   0x01, "TEXT_EVENT",
80   0x02, "COPYRIGHT_NOTICE",
81   0x03, "SEQUENCE_TRACK_NAME",
82   0x04, "INSTRUMENT_NAME",
83   0x05, "LYRIC",
84   0x06, "MARKER",
85   0x07, "CUE_POINT",
86   0x20, "MIDI_CHANNEL_PREFIX",
87   0x21, "MIDI_PORT",
88   0x2F, "END_OF_TRACK",
89   0x51, "SET_TEMPO",
90   0x54, "SMTPE_OFFSET",
91   0x58, "TIME_SIGNATURE",
92   0x59, "KEY_SIGNATURE",
93   0x7F, "SEQUENCER_SPECIFIC_META_EVENT",
94   0,0
95 };
96
97 unsigned long int
98 get_number (char * str, char * end_str, int length)
99 {
100   /* # MIDI uses big-endian for everything */
101   long sum = 0;
102   int i = 0;
103   
104   for (; i < length; i++)
105     sum = (sum << 8) + (unsigned char) str[i];
106
107   debug_print ("%d:\n", sum);
108   return sum;
109 }
110
111 unsigned long int
112 get_variable_length_number (char **str, char * end_str)
113 {
114   long sum = 0;
115   int i = 0;
116   while (*str < end_str)
117     {
118       unsigned char x = **str;
119       (*str) ++;
120       sum = (sum << 7) + (x & 0x7F);
121       if (!(x & 0x80))
122         break;
123     }
124   debug_print ("%d:\n", sum);
125   return sum;
126 }
127
128 static PyObject *
129 read_unimplemented_event (char **track, char *end, unsigned long time,
130                           unsigned char x, unsigned char z)
131 {
132   debug_print ("%x:%s", z, "unimplemented MIDI event\n");
133   *track += 2;
134   return Py_BuildValue ("(iii)", z, *((*track) -2), *((*track) -1));
135 }
136
137 PyObject *
138 read_one_byte (char **track, char *end, unsigned long time,
139                unsigned char x, unsigned char z)
140 {
141   debug_print ("%x:%s", z, "event\n");
142   *track += 1;
143   return Py_BuildValue ("(ii)", z, *((*track) -1));
144 }
145
146 PyObject *
147 read_two_bytes (char **track, char *end, unsigned long time,
148                 unsigned char x, unsigned char z)
149 {
150   debug_print ("%x:%s", z, "event\n");
151   *track += 2;
152   return Py_BuildValue ("(iii)", z, *((*track) -2), *((*track) -1));
153 }
154
155 PyObject *
156 read_three_bytes (char **track, char *end, unsigned long time,
157                   unsigned char x, unsigned char z)
158 {
159   debug_print ("%x:%s", z, "event\n");
160   *track += 3;
161   return Py_BuildValue ("(iiii)", z, *((*track) -3), *((*track) -2), *((*track) -1));
162 }
163
164 PyObject *
165 read_string (char **track, char *end, unsigned long time,
166              unsigned char x, unsigned char z)
167 {
168   unsigned long length = get_variable_length_number (track, end);
169   if (length < *track - end)
170     debug_print ("%s", "zero length string\n");
171   *track += length;
172   debug_print ("%x:%s", length, "string\n");
173   return Py_BuildValue ("(is)", z, *((*track) -length));
174 }
175
176 typedef PyObject* (*Read_midi_event)
177      (char **track, char *end, unsigned long time,
178       unsigned char x, unsigned char z);
179
180 Read_midi_event read_ff_byte [16] =
181 {
182   read_three_bytes,  //  0
183   read_one_byte,     // 10
184   read_one_byte,  // 20
185   read_one_byte,  // 30
186   read_one_byte,  // 40
187   read_one_byte,  // 50
188   read_one_byte,  // 60
189   read_two_bytes, // 70
190   read_two_bytes, // 80
191   read_two_bytes, // 90
192   read_two_bytes, // a0
193   read_two_bytes, // b0
194   read_one_byte,  // c0
195   read_two_bytes, // d0
196   read_two_bytes, // e0
197   read_two_bytes, // e0
198 };
199
200
201 static PyObject *
202 read_f0_byte (char **track, char *end, unsigned long time,
203               unsigned char x, unsigned char z)
204               
205 {
206   debug_print ("%x:%s", z, "event\n");
207   if (z == 0xff)
208     {
209       unsigned char zz = *(*track)++;
210       debug_print ("%x:%s", zz, "f0-event\n");
211       if (zz == 0x01 && **track <= 0x07)
212         return read_string (track, end, time, x, zz);
213       else if (zz == 0x2f && **track == 0x00)
214         {
215           (*track)++;
216           debug_print ("%s", "done\n");
217           return 0;
218         }
219       else
220         return read_unimplemented_event (track, end, time, x, zz);
221       exit (0);
222     }
223   else
224     return read_string (track, end, time, x, z);
225 }
226
227 Read_midi_event read_midi_event [16] =
228 {
229   read_one_byte,  //  0
230   read_one_byte,  // 10
231   read_one_byte,  // 20
232   read_one_byte,  // 30
233   read_one_byte,  // 40
234   read_one_byte,  // 50
235   read_one_byte,  // 60
236   read_two_bytes, // 70
237   read_two_bytes, // 80
238   read_two_bytes, // 90
239   read_two_bytes, // a0
240   read_two_bytes, // b0
241   read_one_byte,  // c0
242   read_two_bytes, // d0
243   read_two_bytes, // e0
244   read_f0_byte,   // f0
245 };
246              
247 static PyObject *
248 read_event (char **track, char *end, unsigned long time,
249             unsigned char *running_status)
250 {
251   int rsb_skip = ((**track & 0x80)) ? 1 :0;
252
253   unsigned char x = (rsb_skip) ? (*track)[0]: *running_status;
254   // unsigned char y = x & 0xf0;
255   unsigned char z = (*track)[1 + rsb_skip];
256   
257   debug_print ("%x:%s", z, "event\n");
258   *track += 2 + rsb_skip;
259
260   return (*read_midi_event[z >> 4]) (track, end, time, x, z);
261 }
262
263 static PyObject *
264 midi_parse_track (char **track, char *track_end)
265 {
266   unsigned int time = 0;
267   unsigned char running_status;
268   unsigned long track_len, track_size;
269   PyObject *pytrack = 0;
270
271   debug_print ("%s", "\n");
272   
273   track_size = track_end - *track;
274   /* need this for direct midi.parse_track (s) on midi file */
275   if (strcmp (*track, "MTrk"))
276     *track = memmem (*track, track_size - 1, "MTrk", 4);
277   debug_print ("%s", "\n");
278   assert (!strcmp (*track, "MTrk"));
279   *track += 4;
280
281   track_len = get_number (*track, *track + 4, 4);
282   *track += 4;
283
284   debug_print ("track_len: %u\n", track_len);
285   debug_print ("track_size: %u\n", track_size);
286   debug_print ("track begin: %p\n", track);
287   debug_print ("track end: %p\n", track + track_len);
288   
289   //assert (track_len <= track_size);
290
291   pytrack = PyList_New (0);
292
293   track_end = *track + track_len;
294
295   while (*track < track_end)
296     {
297       long dt = get_variable_length_number(track, track_end);
298       time += dt;
299       PyList_Append (pytrack, read_event (track, track_end, time,
300                                           &running_status));
301     }
302
303   *track = track_end;
304   return pytrack;
305 }
306
307
308 static PyObject *
309 pymidi_parse_track (PyObject *self, PyObject *args)
310 {
311   char *track, *track_end;
312   unsigned long track_size, track_len;
313
314   PyObject * sobj = PyTuple_GetItem (args, 0);
315
316   debug_print ("%s", "\n");
317   if (!PyArg_ParseTuple (args, "s#", &track, &track_size))
318     return 0;
319
320   if (track_size < 0)
321     return midi_error ("negative track size");
322
323   track_end = track + track_size;
324   
325   return midi_parse_track (&track, track_end);
326 }
327
328 static PyObject *
329 midi_parse (char **midi, char *midi_end)
330 {
331   PyObject *pymidi = 0;
332   unsigned long header_len;
333   unsigned format, tracks;
334   int division;
335   int i;
336   
337   debug_print ("%s", "\n");
338
339   /* Header */
340   header_len = get_number (*midi, *midi + 4, 4);
341   *midi += 4;
342   
343   if (header_len < 6)
344     return midi_error ("header too short");
345     
346   format = get_number (*midi, *midi + 2, 2);
347   *midi += 2;
348   
349   tracks = get_number (*midi, *midi + 2, 2);
350   *midi += 2;
351
352   if (tracks > 32)
353     return midi_error ("too many tracks");
354   
355   division = get_number (*midi, *midi + 2, 2) * 4;
356   *midi += 2;
357
358   if (division < 0)
359     /* return midi_error ("can't handle non-metrical time"); */
360     ;
361   *midi += header_len - 6;
362
363   pymidi = PyList_New (0);
364   PyList_Append (pymidi, Py_BuildValue ("(iii)", format, tracks, division));
365
366   /* Tracks */
367   for (i = 0; i < tracks; i++)
368     PyList_Append (pymidi, midi_parse_track (midi, midi_end));
369
370   return pymidi;
371 }
372
373 static PyObject *
374 pymidi_parse (PyObject *self, PyObject *args)
375 {
376   char *midi, *midi_end;
377   unsigned long midi_size, midi_len;
378   
379   PyObject *sobj = PyTuple_GetItem (args, 0);
380
381   debug_print ("%s", "\n");
382   if (!PyArg_ParseTuple (args, "s#", &midi, &midi_size))
383     return 0;
384
385   if (strcmp (midi, "MThd"))
386       return midi_error ("MThd expected");
387   
388   midi += 4;
389
390   midi_end = midi + midi_size;
391
392   return midi_parse (&midi, midi_end);
393 }
394
395
396 static PyMethodDef MidiMethods[] = 
397 {
398   {"parse",  pymidi_parse, 1},
399   {"parse_track",  pymidi_parse_track, 1},
400   {0, 0}        /* Sentinel */
401 };
402
403 initmidi ()
404 {
405   PyObject *m, *d;
406   m = Py_InitModule ("midi", MidiMethods);
407   d = PyModule_GetDict (m);
408   
409   Midi_error = PyString_FromString ("midi.error");
410   PyDict_SetItemString (d, "error", Midi_error);
411   Midi_warning = PyString_FromString ("midi.warning");
412   PyDict_SetItemString (d, "warning", Midi_warning);
413 }