~ubuntu-branches/ubuntu/wily/pmidi/wily

« back to all changes in this revision

Viewing changes to src/midiread.c

  • Committer: Bazaar Package Importer
  • Author(s): Mikael Hedin
  • Date: 2003-10-23 12:09:07 UTC
  • Revision ID: james.westby@ubuntu.com-20031023120907-30pl4zjuuu30h8j3
Tags: upstream-1.5.5
ImportĀ upstreamĀ versionĀ 1.5.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * 
 
3
 * File: midiread.m - Read in a midi file.
 
4
 * 
 
5
 * Copyright (C) 1999 Steve Ratcliffe
 
6
 * 
 
7
 *  This program is free software; you can redistribute it and/or modify
 
8
 *  it under the terms of the GNU General Public License version 2 as
 
9
 *  published by the Free Software Foundation.
 
10
 * 
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 */
 
16
 
 
17
 
 
18
#include "glib.h"
 
19
#include "elements.h"
 
20
#include "except.h"
 
21
#include "intl.h"
 
22
 
 
23
#include <stdio.h>
 
24
#include "midi.h"
 
25
 
 
26
/*
 
27
 * This structure is used to keep track of the state while
 
28
 * reading in a midi file.
 
29
 */
 
30
struct midistate {
 
31
        FILE *fp;               /* File being read */
 
32
        int  current_time;      /* Current midi time */
 
33
        int  port;              /* Midi port number */
 
34
        int  device;    /* Midi device number */
 
35
        int  track_count;       /* Count of current track */
 
36
        int  chunk_size;        /* Size of current chunk */
 
37
        int  chunk_count;       /* Count within current chunk */
 
38
        GPtrArray *notes;       /* Currently on notes */
 
39
 
 
40
        struct tempomapElement *tempo_map;      /* The tempo map */
 
41
};
 
42
 
 
43
static struct rootElement *read_head(struct midistate *msp);
 
44
static struct trackElement *read_track(struct midistate *msp);
 
45
static void handle_status(struct midistate *msp, struct trackElement *track, 
 
46
        int status);
 
47
static struct metaElement *handle_meta(struct midistate *msp, int type, 
 
48
        unsigned char *data);
 
49
static int read_int(struct midistate *msp, int n);
 
50
static unsigned char *read_data(struct midistate *msp, int length);
 
51
static gint32 read_var(struct midistate *msp);
 
52
static void put_back(struct midistate *msp, char c);
 
53
static struct element *save_note(struct midistate *msp, int note, int vel);
 
54
static void finish_note(struct midistate *msp, int note, int vel);
 
55
static void skip_chunk(struct midistate *msp);
 
56
 
 
57
/*
 
58
 * Read in a midi file from the specified open file pointer, fp
 
59
 * and return an mtree structure tree representing the file.
 
60
 * 
 
61
 *  Arguments:
 
62
 *    fp        - Input file pointer
 
63
 */
 
64
struct rootElement *
 
65
midi_read(FILE *fp)
 
66
{
 
67
        struct midistate mState;
 
68
        struct midistate *msp;
 
69
        struct rootElement *root;
 
70
        struct element *el;
 
71
        int  i;
 
72
 
 
73
        msp = &mState;
 
74
        msp->fp = fp;
 
75
        msp->tempo_map = md_tempomap_new();
 
76
        msp->notes = g_ptr_array_new();
 
77
        msp->port = 0;
 
78
 
 
79
        root = read_head(msp);
 
80
        md_add(MD_CONTAINER(root), NULL); /* Leave room for the tempo map */
 
81
        for (i = 0; i < root->tracks; i++) {
 
82
                el = MD_ELEMENT(read_track(msp));
 
83
 
 
84
                /* If format 1 then the first track is really the tempo map */
 
85
                if (root->format == 1
 
86
                                && i == 0
 
87
                                && MD_CONTAINER(el)->elements->len == 0) {
 
88
                        /* It will be added after the loop */
 
89
                        md_free(el);
 
90
                        continue;
 
91
                }
 
92
 
 
93
                md_add(MD_CONTAINER(root), el);
 
94
        }
 
95
 
 
96
        g_ptr_array_index(MD_CONTAINER(root)->elements, 0) = msp->tempo_map;
 
97
        msp->tempo_map = NULL;
 
98
 
 
99
        g_ptr_array_free(msp->notes, 1);
 
100
 
 
101
        return root;
 
102
}
 
103
 
 
104
/*
 
105
 * Read in a midi file from the specified file name.
 
106
 * 
 
107
 *  Arguments:
 
108
 *    name      - File name to read
 
109
 */
 
110
struct rootElement *
 
111
midi_read_file(char *name)
 
112
{
 
113
        FILE *fp;
 
114
        struct rootElement *root;
 
115
 
 
116
        fp = fopen(name, "rb");
 
117
        if (fp == NULL)
 
118
                except(ioError, _("Could not open file %s"), name);
 
119
 
 
120
        root = midi_read(fp);
 
121
 
 
122
        fclose(fp);
 
123
 
 
124
        return root;
 
125
}
 
126
 
 
127
/*
 
128
 * Read the header information from a midi file
 
129
 * 
 
130
 *  Arguments:
 
131
 *    msp       - current midi state
 
132
 */
 
133
static struct rootElement *
 
134
read_head(struct midistate *msp)
 
135
{
 
136
        guint32  magic;
 
137
        int  length;
 
138
        struct rootElement *root;
 
139
 
 
140
        root = md_root_new();
 
141
 
 
142
        /* The first word just identifies the file as a midi file */
 
143
        magic = read_int(msp, 4);
 
144
        if (magic != MIDI_HEAD_MAGIC)
 
145
                except(formatError, _("Bad header (%x), probably not a real midi file"),
 
146
                        magic);
 
147
 
 
148
        /* The header chunk should be 6 bytes, (perhaps longer in the future) */
 
149
        length = read_int(msp, 4);
 
150
        if (length < 6)
 
151
                except(formatError, _("Bad header length, probably not a real midi file"));
 
152
 
 
153
        root->format = read_int(msp, 2);
 
154
        root->tracks = read_int(msp, 2);
 
155
        root->time_base = read_int(msp, 2);
 
156
 
 
157
        /* Should skip any extra bytes, (may not be seekable) */
 
158
        while (length > 6) {
 
159
                length--;
 
160
                (void) getc(msp->fp);
 
161
        }
 
162
 
 
163
        return root;
 
164
}
 
165
 
 
166
/*
 
167
 * Read in one track from the file, and return an element tree
 
168
 * describing it.
 
169
 * 
 
170
 *  Arguments:
 
171
 *    msp       - Midi state
 
172
 */
 
173
static struct trackElement *
 
174
read_track(struct midistate *msp)
 
175
{
 
176
        int  status, laststatus;
 
177
        int  head;
 
178
        int  length;
 
179
        int  delta_time;
 
180
        struct trackElement *track;
 
181
        int  i;
 
182
 
 
183
        laststatus = 0;
 
184
        head = read_int(msp, 4);
 
185
        if (head != MIDI_TRACK_MAGIC)
 
186
                except(formatError,
 
187
                        _("Bad track header (%x), probably not a midi file"),
 
188
                        head);
 
189
 
 
190
        length = read_int(msp, 4);
 
191
        msp->chunk_size = length;
 
192
        msp->chunk_count = 0;   /* nothing read yet */
 
193
 
 
194
        track = md_track_new();
 
195
 
 
196
        msp->current_time = 0;
 
197
        while (msp->chunk_count < msp->chunk_size) {
 
198
 
 
199
                delta_time = read_var(msp);
 
200
                msp->current_time += delta_time;
 
201
 
 
202
                status = read_int(msp, 1);
 
203
                if ((status & 0x80) == 0) {
 
204
                        
 
205
                        /*
 
206
                         * This is not a status byte and so running status is being
 
207
                         * used.  Re-use the previous status and push back this byte.
 
208
                         */
 
209
                        put_back(msp, status);
 
210
                        status = laststatus;
 
211
                } else {
 
212
                        laststatus = status;
 
213
                }
 
214
 
 
215
                handle_status(msp, track, status);
 
216
        }
 
217
 
 
218
  restart:
 
219
        for (i = 0; i < msp->notes->len; i++) {
 
220
                struct noteElement *ns;
 
221
                ns = g_ptr_array_index(msp->notes, i);
 
222
                msp->device = MD_ELEMENT(ns)->device_channel;
 
223
printf("Left over note, finishing\n");
 
224
                finish_note(msp, ns->note, 0);
 
225
                goto restart;
 
226
        }
 
227
 
 
228
        msp->track_count++;
 
229
 
 
230
        return track;
 
231
}
 
232
 
 
233
/*
 
234
 * Complete the reading of the status byte. The parsed midi
 
235
 * command will be added to the specified track .
 
236
 * 
 
237
 *  Arguments:
 
238
 *    msp       - Current midi file status
 
239
 *    track     - Current track
 
240
 *    status    - Status byte, ie. current command
 
241
 */
 
242
static void 
 
243
handle_status(struct midistate *msp, struct trackElement *track, int status)
 
244
{
 
245
        int  ch;
 
246
        int  type;
 
247
        int  device;
 
248
        int  length;
 
249
        short note, vel, control;
 
250
        int  val;
 
251
        unsigned char *data;
 
252
        struct element *el;
 
253
 
 
254
        ch = status & 0x0f;
 
255
        type = status & 0xf0;
 
256
 
 
257
        /*
 
258
         * Do not set the device if the type is 0xf0 as these commands are
 
259
         * not channel specific
 
260
         */
 
261
        device = 0;
 
262
        if (type != 0xf0)
 
263
                device = (msp->port<<4) + ch;
 
264
        msp->device = device;
 
265
 
 
266
        el = NULL;
 
267
 
 
268
        switch (type) { 
 
269
        case MIDI_NOTE_OFF:
 
270
                note = read_int(msp, 1);
 
271
                vel = read_int(msp, 1);
 
272
 
 
273
                finish_note(msp, note, vel);
 
274
                break;
 
275
 
 
276
        case MIDI_NOTE_ON:
 
277
                note = read_int(msp, 1);
 
278
                vel = read_int(msp, 1);
 
279
 
 
280
                if (vel == 0) {
 
281
                        /* This is really a note off */
 
282
                        finish_note(msp, note, vel);
 
283
                } else {
 
284
                        /* Save the start, so it can be matched with the note off */
 
285
                        el = save_note(msp, note, vel);
 
286
                }
 
287
                break;
 
288
 
 
289
        case MIDI_KEY_AFTERTOUCH:
 
290
                note = read_int(msp, 1);
 
291
                vel = read_int(msp, 1);
 
292
 
 
293
                /* new aftertouchElement */
 
294
                el = MD_ELEMENT(md_keytouch_new(note, vel));
 
295
                break;
 
296
 
 
297
        case MIDI_CONTROLER:
 
298
                control = read_int(msp, 1);
 
299
                val = read_int(msp, 1);
 
300
                el = MD_ELEMENT(md_control_new(control, val));
 
301
 
 
302
                break;
 
303
        
 
304
        case MIDI_PATCH:
 
305
                val = read_int(msp, 1);
 
306
                el = MD_ELEMENT(md_program_new(val));
 
307
                break;
 
308
 
 
309
        case MIDI_CHANNEL_AFTERTOUCH:
 
310
                val = read_int(msp, 1);
 
311
                el = MD_ELEMENT(md_pressure_new(val));
 
312
                break;
 
313
        case MIDI_PITCH_WHEEL:
 
314
                val = read_int(msp, 1);
 
315
                val |= read_int(msp, 1) << 7;
 
316
                val -= 0x2000;  /* Center it around zero */
 
317
                el = MD_ELEMENT(md_pitch_new(val));
 
318
                break;
 
319
 
 
320
        /* Now for all the non-channel specific ones */
 
321
        case 0xf0:
 
322
                /* Deal with the end of track event first */
 
323
                if (ch == 0x0f) {
 
324
                        type = read_int(msp, 1);
 
325
                        if (type == 0x2f) {
 
326
                                /* End of track - skip to end of real track */
 
327
                                track->final_time = msp->current_time;
 
328
                                skip_chunk(msp);
 
329
                                return;
 
330
                        }
 
331
                }
 
332
 
 
333
                /* Get the length of the following data */
 
334
                length = read_var(msp);
 
335
                data = read_data(msp, length);
 
336
                if (ch == 0x0f) {
 
337
                        el = (struct element *)handle_meta(msp, type, data);
 
338
                } else {
 
339
                        el = (struct element *)md_sysex_new(status, data, length);
 
340
                }
 
341
                break;
 
342
        default:
 
343
                except(formatError, _("Bad status type 0x%x"), type);
 
344
                /*NOTREACHED*/
 
345
        }
 
346
 
 
347
        if (el != NULL) {
 
348
                el->element_time = msp->current_time;
 
349
                el->device_channel = device;
 
350
 
 
351
                md_add(MD_CONTAINER(track), el);
 
352
        }
 
353
}
 
354
 
 
355
/*
 
356
 * Do extra handling of meta events. We want to save time
 
357
 * signature and key for use elsewhere, for example. This
 
358
 * routine create the correct type of class and returns it.
 
359
 * 
 
360
 *  Arguments:
 
361
 *    msp       - The midi file state
 
362
 *    type      - The meta event type
 
363
 *    data      - The data for the event
 
364
 */
 
365
static struct metaElement *
 
366
handle_meta(struct midistate *msp, int type, unsigned char *data)
 
367
{
 
368
        struct metaElement *el = NULL;
 
369
        struct mapElement *map = NULL;
 
370
        int  micro_tempo;
 
371
 
 
372
        switch (type) {
 
373
        case MIDI_META_SEQUENCE:
 
374
                break;
 
375
        case MIDI_META_TEXT:
 
376
        case MIDI_META_COPYRIGHT:
 
377
        case MIDI_META_TRACKNAME:
 
378
        case MIDI_META_INSTRUMENT:
 
379
        case MIDI_META_LYRIC:
 
380
        case MIDI_META_MARKER:
 
381
        case MIDI_META_CUE:
 
382
                /* Text based events */
 
383
                el = MD_META(md_text_new(type, (char*)data));
 
384
                break;
 
385
        case MIDI_META_CHANNEL:
 
386
                break;
 
387
        case MIDI_META_PORT:
 
388
                msp->port = data[0];
 
389
                g_free(data);
 
390
                break;
 
391
        case MIDI_META_EOT:
 
392
                break;
 
393
        case MIDI_META_TEMPO:
 
394
                micro_tempo = ((data[0]<<16) & 0xff0000)
 
395
                        + ((data[1]<<8) & 0xff00) + (data[2] & 0xff);
 
396
                map = MD_MAP(md_tempo_new(micro_tempo));
 
397
                g_free(data);
 
398
                break;
 
399
        case MIDI_META_SMPTE_OFFSET:
 
400
                el = MD_META(md_smpteoffset_new(data[0], data[1], data[2], data[3],
 
401
                        data[4]));
 
402
                break;
 
403
        case MIDI_META_TIME:
 
404
                map = MD_MAP(md_timesig_new(data[0], 1<<data[1],
 
405
                        data[2], data[3]));
 
406
                g_free(data);
 
407
                break;
 
408
        case MIDI_META_KEY:
 
409
                map = MD_MAP(md_keysig_new(data[0], (data[1]==1)? 1: 0));
 
410
                g_free(data);
 
411
                break;
 
412
        case MIDI_META_PROP:
 
413
                /* Proprietry sequencer specific event */
 
414
                /* Just throw it out */
 
415
                break;
 
416
        default:
 
417
                g_warning(_("Meta event %d not implemented\n"), type);
 
418
                break;
 
419
        }
 
420
 
 
421
        /* If this affected the tempo map then add it */
 
422
        if (map) {
 
423
                MD_ELEMENT(map)->element_time = msp->current_time;
 
424
                md_add(MD_CONTAINER(msp->tempo_map), MD_ELEMENT(map));
 
425
        }
 
426
 
 
427
        return el;
 
428
}
 
429
 
 
430
/*
 
431
 * Reads an interger from the midi file. The number of bytes to
 
432
 * be read is specified in n .
 
433
 * 
 
434
 *  Arguments:
 
435
 *    msp       - Midi file state
 
436
 *    n         - Number of bytes to read
 
437
 */
 
438
static int 
 
439
read_int(struct midistate *msp, int n)
 
440
{
 
441
        int  val;
 
442
        int  c;
 
443
        int  i;
 
444
 
 
445
        val = 0;
 
446
 
 
447
        for (i = 0; i < n; i++) {
 
448
                val <<= 8;
 
449
                c = getc(msp->fp);
 
450
                msp->chunk_count++;
 
451
                if (c == -1)
 
452
                        except(formatError, _("Unexpected end of file"));
 
453
 
 
454
                val |= c;
 
455
        }
 
456
 
 
457
        return val;
 
458
}
 
459
 
 
460
/*
 
461
 * Read in a specified amount of data from the file. The return
 
462
 * is allocated data which must be freed by the caller. An extra
 
463
 * null byte is appended for the sake of text events.
 
464
 *  Arguments:
 
465
 *    msp       - Midifile state
 
466
 *    length    - Length of data to read
 
467
 */
 
468
static unsigned char *
 
469
read_data(struct midistate *msp, int length)
 
470
{
 
471
 
 
472
        unsigned char *data = g_malloc(length+1);
 
473
 
 
474
        if (length == 0) {
 
475
                data[0] = 0;
 
476
                return data;
 
477
        }
 
478
 
 
479
        if (fread(data, length, 1, msp->fp) == 1) {
 
480
                msp->chunk_count += length;
 
481
                data[length] = '\0';
 
482
                return data;
 
483
        } else {
 
484
                except(formatError, _("Unexpected end of file"));
 
485
                /*NOTREACHED*/
 
486
        }
 
487
        return NULL;
 
488
}
 
489
 
 
490
/*
 
491
 * Read a variable length integer from the midifile and return
 
492
 * it. Returns an int32 so cannot really deal with more than
 
493
 * four bytes.
 
494
 * 
 
495
 *  Arguments:
 
496
 *    msp       - Midi file state
 
497
 */
 
498
static gint32 
 
499
read_var(struct midistate *msp)
 
500
{
 
501
        int  val;
 
502
        int  c;
 
503
 
 
504
        val = 0;
 
505
        do {
 
506
                c = getc(msp->fp);
 
507
                msp->chunk_count++;
 
508
                if (c == -1)
 
509
                        except(formatError, _("Unexpected end of file"));
 
510
                val <<= 7;
 
511
                val |= (c & 0x7f);
 
512
        } while ((c & 0x80) == 0x80);
 
513
 
 
514
        return val;
 
515
}
 
516
 
 
517
/*
 
518
 * Push back a character. Have to also keep track of the
 
519
 * chunk_count.
 
520
 *  Arguments:
 
521
 *    msp       - Midi input state
 
522
 *    c         - Character to push back
 
523
 */
 
524
static void 
 
525
put_back(struct midistate *msp, char c)
 
526
{
 
527
        ungetc(c, msp->fp);
 
528
        msp->chunk_count--;
 
529
}
 
530
 
 
531
/*
 
532
 * Save the initial note-on message. This will later be paired
 
533
 * with a note off message. We have to keep track of channel and
 
534
 * device that the note-on is for so that it can be correctly
 
535
 * matched.
 
536
 * 
 
537
 *  Arguments:
 
538
 *    msp       - Midi file state
 
539
 *    note      - Note number
 
540
 *    vel       - Velocity
 
541
 */
 
542
static struct element *
 
543
save_note(struct midistate *msp, int note, int vel)
 
544
{
 
545
        struct noteElement *n;
 
546
 
 
547
        /* Create a new note and set its length to -1
 
548
         * this will be filled in later, when the note-off arrives
 
549
         */
 
550
        n = md_note_new(note, vel, -1); 
 
551
 
 
552
        /* Save it so that we match up with the note off */
 
553
        g_ptr_array_add(msp->notes, n);
 
554
 
 
555
        return MD_ELEMENT(n);
 
556
}
 
557
 
 
558
/*
 
559
 * Called when a note off is seen. Finds the corresponding note
 
560
 * on and constructs a note element.
 
561
 * 
 
562
 *  Arguments:
 
563
 *    msp       - Midi file state
 
564
 *    note      - Note number
 
565
 *    vel       - Note velocity
 
566
 */
 
567
static void 
 
568
finish_note(struct midistate *msp, int note, int vel)
 
569
{
 
570
        int  i;
 
571
        GPtrArray *notes;
 
572
        struct noteElement *n;
 
573
        int  len;
 
574
 
 
575
        notes = msp->notes;
 
576
        n = NULL;
 
577
        for (i = notes->len-1; i >= 0; i--) {
 
578
                n = g_ptr_array_index(notes, i);
 
579
                if (n->note == note && MD_ELEMENT(n)->device_channel == msp->device) {
 
580
                        len = msp->current_time - MD_ELEMENT(n)->element_time;
 
581
                        n->offvel = vel;
 
582
                        n->length = len;
 
583
                        if (n->length < 0) {
 
584
                                printf("Len neg: msp->time%d, s->time%d, note=%d, s.vel%d\n",
 
585
                                        msp->current_time, MD_ELEMENT(n)->element_time,
 
586
                                        note, n->vel);
 
587
                                n->length = 0;
 
588
                        }
 
589
                        g_ptr_array_remove_index_fast(notes, i);
 
590
                        break;
 
591
                }
 
592
        }
 
593
}
 
594
 
 
595
/*
 
596
 * Skip to the end of the chunk. Note that the input may not be
 
597
 * seekable, so we just read bytes until at the end of the chunk.
 
598
 * 
 
599
 *  Arguments:
 
600
 *    msp       - Midi file state
 
601
 */
 
602
static void 
 
603
skip_chunk(struct midistate *msp)
 
604
{
 
605
        while (msp->chunk_count < msp->chunk_size)
 
606
                (void) read_int(msp, 1);
 
607
}