Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/MD_package/MDSequenceSMF.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 183 - (show annotations) (download) (as text)
Wed Mar 4 13:15:43 2020 UTC (4 years, 1 month ago) by toshinagata1964
File MIME type: text/x-csrc
File size: 39157 byte(s)
Internal errors during SMF saving are reported to the user
1 /*
2 MDSequenceSMF.c
3 Created by Toshi Nagata, 2000.11.24.
4
5 Copyright (c) 2000-2017 Toshi Nagata. All rights reserved.
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 as published by
9 the Free Software Foundation version 2 of the License.
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 #include "MDHeaders.h"
18
19 #include <stdlib.h> /* for malloc(), realloc(), and free() */
20 #include <string.h> /* for memset() */
21 #include <stdio.h>
22 #include <ctype.h>
23
24 #define DEBUG_PRINT 0
25
26 /* An internal struct for converting SMF to MD format */
27 typedef struct MDSMFConvert MDSMFConvert;
28 struct MDSMFConvert {
29 /* The information for the whole sequence */
30 STREAM stream;
31 MDSequence * sequence; /* the resulting sequence */
32 int32_t timebase; /* the SMF timebase */
33 int32_t max_tick; /* the maximum tick (the length of the sequence) */
34 int32_t trkno; /* the number of tracks */
35
36 /* The information for each track */
37 MDTrack * temptrk; /* the current track */
38 int32_t track_index; /* the current track number */
39 int32_t tick; /* the tick of the last event */
40 int32_t deltatime; /* the deltatime of the current event */
41 unsigned char status; /* running status */
42 unsigned char track_channel; /* track channel (16 if the sequence is multi-track mode) */
43 int32_t pos; /* the file position where the track size is to be written */
44
45 MDSequenceCallback callback; /* A callback function. Periodically called, and abort if 0 */
46 int32_t filesize; /* total file size */
47 void * cbdata; /* callback data */
48
49 /* Store error message */
50 STREAM err_stream;
51 };
52
53 /* SMF ��������������������������������������������� */
54 enum {
55 kMDEventSMFBankSelectMSB = 0,
56 kMDEventSMFDataEntryMSB = 6,
57 kMDEventSMFBankSelectLSB = 32,
58 kMDEventSMFDataEntryLSB = 38,
59 kMDEventSMFDataIncrement = 96,
60 kMDEventSMFDataDecrement = 97,
61 kMDEventSMFNRPNLSB = 98,
62 kMDEventSMFNRPNMSB = 99,
63 kMDEventSMFRPNLSB = 100,
64 kMDEventSMFRPNMSB = 101
65 };
66
67 #define kMDMaxSMFTempo 16777215 /* 2^24 - 1 */
68
69 static int32_t
70 MDSequenceTempoToSMFTempo(float tempo)
71 {
72 if (tempo < kMDMinTempo)
73 return kMDMaxSMFTempo;
74 if (tempo > kMDMaxTempo)
75 return (int32_t)(60000000.0 / kMDMaxTempo);
76 else return (int32_t)(60000000.0 / tempo);
77 }
78
79 static int32_t
80 MDSequenceSMFTempoToTempo(int32_t smfTempo)
81 {
82 if (smfTempo <= (int32_t)(60000000.0 / kMDMaxTempo))
83 return kMDMaxTempo;
84 else if (smfTempo > (int32_t)(60000000.0 / kMDMinTempo))
85 return kMDMinTempo;
86 else return (float)(60000000.0 / smfTempo);
87 }
88
89 #pragma mark ====== Error message ======
90
91 static void
92 MDSequenceSMFConvertError(MDSMFConvert *cref, const char *fmt, ...)
93 {
94 if (cref != NULL && cref->err_stream != NULL) {
95 char *p1, *p2;
96 int n1, n2;
97 va_list ap;
98 va_start(ap, fmt);
99 asprintf(&p1, "Track %d tick %d: ", cref->track_index, cref->tick);
100 vasprintf(&p2, fmt, ap);
101 va_end(ap);
102 if (p1 == NULL || p2 == NULL)
103 return; /* Ignore error */
104 n1 = (int)strlen(p1);
105 n2 = (int)strlen(p2);
106 if (FWRITE_(p1, n1, cref->err_stream) < n1 || FWRITE_(p2, n2, cref->err_stream) < n2 || PUTC('\n', cref->err_stream) == EOF)
107 return; /* Ignore error */
108 }
109 }
110
111 #pragma mark ====== Reading SMF ======
112
113 static MDStatus
114 MDSequenceReadSMFReadMessage(MDSMFConvert *cref, MDEvent *eref)
115 {
116 int32_t length;
117 unsigned char *msg;
118
119 /* Read the message length */
120 if (MDReadStreamFormat(cref->stream, "w", &length) != 1)
121 return kMDErrorUnexpectedEOF;
122
123 /* Allocate the memory */
124 /* For kMDEventSysex, append the beginning 'F0'. */
125 if (MDGetKind(eref) == kMDEventSysex)
126 length++;
127 if (MDSetMessageLength(eref, length) < 0)
128 return kMDErrorOutOfMemory;
129
130 msg = MDGetMessagePtr(eref, NULL);
131 if (MDGetKind(eref) == kMDEventSysex) {
132 msg[0] = 0xf0;
133 if (FREAD_(msg + 1, length - 1, cref->stream) < length - 1)
134 return kMDErrorUnexpectedEOF;
135 } else {
136 /* For messages other than Sysex, the data can be always treated as a C string
137 as MDSetMessageLength() automatically appends a terminating null byte */
138 if (FREAD_(msg, length, cref->stream) < length)
139 return kMDErrorUnexpectedEOF;
140 }
141 return kMDNoError;
142 }
143
144 /* Read one meta event */
145 static MDStatus
146 MDSequenceReadSMFMetaEvent(MDSMFConvert *cref, MDEvent *eref)
147 {
148 MDStatus result = kMDNoError;
149 int32_t length;
150 int n;
151 unsigned char s[8], *metaDataPtr;
152
153 n = GETC(cref->stream);
154 if (n == EOF)
155 return kMDErrorUnexpectedEOF;
156 MDSetCode(eref, n);
157
158 switch (n) {
159 case kMDMetaEndOfTrack:
160 if (cref->max_tick < cref->tick)
161 cref->max_tick = cref->tick;
162 /* Read the message length (should be always zero, but not checked) */
163 if (MDReadStreamFormat(cref->stream, "w", &length) != 1) {
164 result = kMDErrorUnexpectedEOF;
165 break;
166 }
167 MDSetKind(eref, kMDEventStop);
168 break;
169 case kMDMetaDuration: {
170 MDTickType duration;
171 MDSetKind(eref, kMDEventInternalDuration);
172 if (MDReadStreamFormat(cref->stream, "ww", &length, &duration) != 2) {
173 result = kMDErrorUnexpectedEOF;
174 break;
175 }
176 MDSetDuration(eref, duration);
177 break;
178 }
179 case kMDMetaPortNumber:
180 case kMDMetaTempo:
181 case kMDMetaSMPTE:
182 case kMDMetaTimeSignature:
183 case kMDMetaKey:
184 MDSetKind(eref, kMDEventMeta);
185 if (MDReadStreamFormat(cref->stream, "w", &length) != 1) {
186 result = kMDErrorUnexpectedEOF;
187 break;
188 }
189 if (length >= 8) {
190 result = kMDErrorWrongMetaEvent;
191 break;
192 }
193 memset(s, 0, sizeof(s));
194 if (FREAD_(s, length, cref->stream) < length) {
195 result = kMDErrorUnexpectedEOF;
196 break;
197 }
198 metaDataPtr = MDGetMetaDataPtr(eref);
199 if (n == kMDMetaPortNumber) {
200 MDSetKind(eref, kMDEventPortNumber);
201 MDSetData1(eref, s[0]);
202 } else if (n == kMDMetaTempo) {
203 MDSetKind(eref, kMDEventTempo);
204 MDSetTempo(eref, MDSequenceSMFTempoToTempo(s[0] * 65536.0f + s[1] * 256.0f + s[2]));
205 } else if (n == kMDMetaSMPTE) {
206 MDSMPTERecord *smp = MDGetSMPTERecordPtr(eref);
207 MDSetKind(eref, kMDEventSMPTE);
208 smp->hour = s[0];
209 smp->min = s[1];
210 smp->sec = s[2];
211 smp->frame = s[3];
212 smp->subframe = s[4];
213 } else if (n == kMDMetaTimeSignature) {
214 MDSetKind(eref, kMDEventTimeSignature);
215 metaDataPtr[0] = s[0];
216 metaDataPtr[1] = s[1];
217 metaDataPtr[2] = s[2];
218 metaDataPtr[3] = s[3];
219 } else if (n == kMDMetaKey) {
220 MDSetKind(eref, kMDEventKey);
221 metaDataPtr[0] = s[0];
222 metaDataPtr[1] = s[1];
223 } else {
224 result = kMDErrorWrongMetaEvent;
225 break;
226 }
227 break;
228 case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
229 case 9: case 10: case 11: case 12: case 13: case 14: case 15:
230 /* code 1-15 are reserved for various meta events */
231 MDSetKind(eref, kMDEventMetaText);
232 result = MDSequenceReadSMFReadMessage(cref, eref);
233 break;
234 default:
235 MDSetKind(eref, kMDEventMetaMessage);
236 result = MDSequenceReadSMFReadMessage(cref, eref);
237 break;
238 }
239 return result;
240 }
241
242 static int
243 MDSequenceReadOneChar(void *ptr)
244 {
245 return GETC((STREAM)ptr);
246 }
247
248 /* Read one channel event. n is the first byte (status byte, or the first data
249 byte if running status is used) */
250 static MDStatus
251 MDSequenceReadSMFChannelEvent(MDSMFConvert *cref, MDEvent *eref, int n)
252 {
253 return MDEventFromMIDIMessage(eref, n, cref->status, MDSequenceReadOneChar, cref->stream, &(cref->status));
254
255 #if 0
256 MDStatus result = kMDNoError;
257 int data1, data2;
258 unsigned char ch; /* MIDI channel */
259
260 /* Get the status byte */
261 if (n < 0x80) {
262 /* running status */
263 data1 = n;
264 n = cref->status;
265 } else {
266 cref->status = n;
267 data1 = GETC(cref->stream);
268 if (data1 == EOF)
269 return kMDErrorUnexpectedEOF;
270 }
271
272 /* Get the MD track number */
273 ch = (n & 0x0f); /* MIDI channel */
274 MDSetChannel(eref, ch);
275
276 switch (n & 0xf0) {
277 case kMDEventSMFNoteOff:
278 case kMDEventSMFNoteOn:
279 data2 = GETC(cref->stream);
280 if (data2 == EOF) {
281 result = kMDErrorUnexpectedEOF;
282 break;
283 }
284 data2 &= 0xff;
285 if ((n & 0xf0) == kMDEventSMFNoteOn && data2 != 0) {
286 /* Note on */
287 MDSetKind(eref, kMDEventNote);
288 MDSetCode(eref, data1);
289 MDSetNoteOnVelocity(eref, data2);
290 MDSetNoteOffVelocity(eref, 0);
291 MDSetDuration(eref, 0); /* Set temporary duration: 0 indicates "note-on that is not paired yet" */
292 } else {
293 /* Note off */
294 MDSetKind(eref, kMDEventInternalNoteOff);
295 MDSetCode(eref, data1);
296 MDSetNoteOnVelocity(eref, 0);
297 MDSetNoteOffVelocity(eref, data2);
298 }
299 break;
300 case kMDEventSMFKeyPressure:
301 data2 = GETC(cref->stream);
302 if (data2 == EOF) {
303 result = kMDErrorUnexpectedEOF;
304 break;
305 }
306 MDSetKind(eref, kMDEventKeyPres);
307 MDSetCode(eref, data1);
308 MDSetData1(eref, data2);
309 break;
310 case kMDEventSMFControl:
311 data2 = GETC(cref->stream);
312 if (data2 == EOF) {
313 result = kMDErrorUnexpectedEOF;
314 break;
315 }
316 MDSetKind(eref, kMDEventControl);
317 MDSetCode(eref, data1);
318 MDSetData1(eref, data2);
319 break;
320 case kMDEventSMFProgram:
321 MDSetKind(eref, kMDEventProgram);
322 MDSetData1(eref, data1);
323 break;
324 case kMDEventSMFChannelPressure:
325 MDSetKind(eref, kMDEventChanPres);
326 MDSetData1(eref, data1);
327 break;
328 case kMDEventSMFPitchBend:
329 data2 = GETC(cref->stream);
330 if (data2 == EOF) {
331 result = kMDErrorUnexpectedEOF;
332 break;
333 }
334 MDSetKind(eref, kMDEventPitchBend);
335 MDSetData1(eref, ((data1 & 0x7f) + ((data2 & 0x7f) << 7)) - 8192);
336 break;
337 default:
338 result = kMDErrorUnknownChannelEvent;
339 break;
340 } /* end switch */
341
342 return result;
343 #endif
344 }
345
346 /* Read one SMF track */
347 static MDStatus
348 MDSequenceReadSMFTrack(MDSMFConvert *cref)
349 {
350 MDEvent event;
351 MDStatus result = kMDNoError;
352 MDPointer *lastPendingNoteOn;
353 int n, count;
354 unsigned char quitFlag, skipFlag;
355 MDTickType maxTick = 0;
356 MDTickType metaDuration = 0;
357 // MDTrack *noteOffTrack;
358 // MDPointer *noteOffPtr;
359
360 /* Initialize track info */
361 cref->tick = 0;
362 cref->deltatime = 0;
363
364 cref->temptrk = MDTrackNew();
365 if (cref->temptrk == NULL)
366 return kMDErrorOutOfMemory;
367
368 // ptr = MDPointerNew(cref->temptrk);
369 // if (ptr == NULL)
370 // return kMDErrorOutOfMemory;
371
372 lastPendingNoteOn = MDPointerNew(cref->temptrk);
373 if (lastPendingNoteOn == NULL)
374 return kMDErrorOutOfMemory;
375
376 // noteOffTrack = MDTrackNew();
377 // if (noteOffTrack == NULL)
378 // return kMDErrorOutOfMemory;
379 // noteOffPtr = MDPointerNew(noteOffTrack);
380 // if (noteOffPtr == NULL)
381 // return kMDErrorOutOfMemory;
382
383 quitFlag = 0;
384 MDEventInit(&event);
385 count = 0;
386
387 while (quitFlag == 0) {
388
389 if (++count >= 1000) {
390 if (cref->callback != NULL) {
391 n = (*cref->callback)((float)FTELL(cref->stream) / cref->filesize * 100, cref->cbdata);
392 if (n == 0) {
393 result = kMDErrorUserInterrupt;
394 break;
395 }
396 }
397 count = 0;
398 }
399
400 /* Read the delta time */
401 if (MDReadStreamFormat(cref->stream, "w", &cref->deltatime) != 1) {
402 result = kMDErrorUnexpectedEOF;
403 break;
404 }
405
406 cref->tick += cref->deltatime;
407 MDSetTick(&event, cref->tick);
408 MDSetChannel(&event, 0);
409 skipFlag = 0;
410
411 /* Read the status byte */
412 n = GETC(cref->stream);
413 if (n == EOF) {
414 result = kMDErrorUnexpectedEOF;
415 break;
416 }
417
418 if (n == kMDEventSMFSysex) { /* sysex events */
419 MDSetKind(&event, kMDEventSysex);
420 MDSetChannel(&event, 16);
421 result = MDSequenceReadSMFReadMessage(cref, &event);
422 } else if (n == kMDEventSMFSysexF7) { /* sysex events (continued) */
423 MDSetKind(&event, kMDEventSysexCont);
424 MDSetChannel(&event, 16);
425 result = MDSequenceReadSMFReadMessage(cref, &event);
426 } else if (n == kMDEventSMFMeta) { /* meta events */
427 MDSetChannel(&event, 17); /* not a MIDI event */
428 result = MDSequenceReadSMFMetaEvent(cref, &event);
429 if (MDGetKind(&event) == kMDEventStop) {
430 skipFlag = quitFlag = 1;
431 } else if (MDGetKind(&event) == kMDEventMetaText) {
432 char buf[256];
433 switch (MDGetCode(&event)) {
434 case kMDMetaSequenceName:
435 MDTrackGetName(cref->temptrk, buf, sizeof buf);
436 if (buf[0] == 0) {
437 const char *p = (const char *)MDGetMessageConstPtr(&event, NULL);
438 if (strcmp(p, " ") != 0) {
439 /* A sequence name " " is equivalent to blank */
440 /* (Cf. MDSequenceWriteSMFTrackNameAndDevice()) */
441 result = MDTrackSetName(cref->temptrk, p);
442 }
443 skipFlag = 1;
444 }
445 break;
446 case kMDMetaDeviceName:
447 MDTrackGetDeviceName(cref->temptrk, buf, sizeof buf);
448 if (buf[0] == 0) {
449 result = MDTrackSetDeviceName(cref->temptrk, (const char *)MDGetMessageConstPtr(&event, NULL));
450 skipFlag = 1;
451 }
452 break;
453 case kMDMetaText: {
454 /* Begin with %% at tick 0: an extra info */
455 const char *p = (const char *)MDGetMessageConstPtr(&event, NULL);
456 if (cref->tick == 0 && strncmp(p, "%%", 2) == 0) {
457 /* key:value */
458 const char *pp = strchr(p, ':');
459 if (pp != NULL) {
460 size_t len = pp - (p + 2);
461 if (len >= sizeof(buf))
462 len = sizeof(buf) - 1;
463 strncpy(buf, p + 2, len);
464 buf[len] = 0;
465 /* Is it a known key? */
466 /* (At present, only 'color' is specially treated) */
467 /* 'keyswitch:key1,key2,...' is also recognized, but
468 it is left as a meta text and interpreted only
469 when necessary. */
470 pp = pp + 1;
471 if (strcmp(buf, "color") == 0) {
472 MDTrackSetExtraInfo(cref->temptrk, buf, pp);
473 skipFlag = 1;
474 }
475 }
476 }
477 break;
478 }
479 }
480 } else if (MDGetKind(&event) == kMDEventInternalDuration) {
481 metaDuration = MDGetDuration(&event);
482 skipFlag = 1;
483 }
484 } else { /* channel events */
485 result = MDSequenceReadSMFChannelEvent(cref, &event, n);
486 }
487
488 if (result != kMDNoError)
489 break;
490
491 if (MDGetKind(&event) == kMDEventInternalNoteOn) {
492 if (metaDuration > 0)
493 MDSetDuration(&event, metaDuration);
494 } else if (MDGetKind(&event) == kMDEventInternalNoteOff) {
495 result = MDTrackMatchNoteOff(cref->temptrk, &event, lastPendingNoteOn);
496 if (result != kMDNoError) {
497 fprintf(stderr, "Corrupsed file? orphaned note off at %d\n", (int32_t)MDGetTick(&event));
498 // break;
499 }
500 skipFlag = 1;
501 /* Register note-off into the separate track */
502 /* dprintf(2, "Note-off event encountered: tick %ld code %d vel %d\n", MDGetTick(&event), MDGetCode(&event), MDGetNoteOffVelocity(&event));
503 if (MDTrackAppendEvents(noteOffTrack, &event, 1) < 1) {
504 result = kMDErrorOutOfMemory;
505 break;
506 }
507 skipFlag = 1; */
508 }
509 metaDuration = 0;
510
511 if (!skipFlag) {
512 if (MDTrackAppendEvents(cref->temptrk, &event, 1) < 1) {
513 result = kMDErrorOutOfMemory;
514 break;
515 }
516
517 #if DEBUG_PRINT
518 {
519 char buf[1024];
520 printf("%s\n", MDEventToString(&event, buf, sizeof buf));
521 }
522 #endif
523
524 }
525 MDEventClear(&event);
526 } /* end while (quitFlag == 0) */
527
528 MDPointerRelease(lastPendingNoteOn);
529
530 /* Set the track duration */
531 if (maxTick < cref->tick)
532 maxTick = cref->tick;
533 MDTrackSetDuration(cref->temptrk, maxTick);
534
535 /* Match the note-on/note-off pairs */
536 /* result = MDTrackMatchNoteOffInTrack(cref->temptrk, noteOffTrack); */
537
538 if (result == kMDNoError) {
539 char buf[256];
540 /* Guess track name */
541 MDTrackGetName(cref->temptrk, buf, sizeof buf);
542 if (buf[0] == 0) {
543 MDTrackGuessName(cref->temptrk, buf, 256);
544 result = MDTrackSetName(cref->temptrk, buf);
545 }
546 }
547 if (result == kMDNoError) {
548 char buf[256];
549 /* Guess device name */
550 MDTrackGetDeviceName(cref->temptrk, buf, sizeof buf);
551 if (buf[0] == 0) {
552 MDTrackGuessDeviceName(cref->temptrk, buf, 256);
553 result = MDTrackSetDeviceName(cref->temptrk, buf);
554 }
555 /* Guess the device number from the device name */
556 MDTrackSetDevice(cref->temptrk, MDPlayerGetDestinationNumberFromName(buf));
557 }
558
559 if (result != kMDErrorOutOfMemory) {
560 MDSequenceInsertTrack(cref->sequence, -1, cref->temptrk);
561 MDTrackRelease(cref->temptrk); /* the track will be retained by the sequence */
562 cref->temptrk = NULL;
563 }
564
565 // MDPointerRelease(noteOffPtr);
566 // MDTrackRelease(noteOffTrack);
567
568 return result;
569 }
570
571 MDStatus
572 MDSequenceReadSMF(MDSequence *inSequence, STREAM stream, MDSequenceCallback callback, void *cbdata)
573 {
574 MDStatus result = kMDNoError;
575 MDSMFConvert conv;
576 short fmt, trkno, timebase; /* SMF format, track number, timebase */
577 int32_t size, pos;
578 char tag[8];
579
580 if (inSequence == NULL || stream == NULL)
581 return kMDErrorInternalError;
582
583 /* Initialize the convert record */
584 memset(&conv, 0, sizeof(conv));
585 conv.stream = stream;
586 conv.sequence = inSequence;
587 conv.callback = callback;
588 pos = (int32_t)FTELL(stream);
589 FSEEK(stream, 0, SEEK_END);
590 conv.track_channel = 0; /* Not to be used */
591 conv.filesize = (int32_t)FTELL(stream) - pos;
592 conv.cbdata = cbdata;
593 FSEEK(stream, pos, SEEK_SET);
594
595 /* Read the file header */
596 if (MDReadStreamFormat(conv.stream, "A4Nn3", tag, &size, &fmt, &trkno, &timebase) == 5
597 && size == 6 && strcmp(tag, "MThd") == 0) {
598 if (fmt != 0 && fmt != 1) {
599 result = kMDErrorUnsupportedSMFFormat;
600 } else {
601 conv.timebase = timebase;
602 conv.trkno = trkno;
603 MDSequenceSetTimebase(inSequence, timebase);
604 }
605 } else {
606 result = kMDErrorHeaderChunkNotFound;
607 }
608
609 /* Read each track */
610 while (result == kMDNoError && MDReadStreamFormat(conv.stream, "A4N", tag, &size) == 2) {
611 /* Check the tag */
612 if (strcmp(tag, "MTrk") == 0) {
613 result = MDSequenceReadSMFTrack(&conv);
614 if (result != kMDErrorOutOfMemory)
615 conv.track_index++;
616 else break;
617 if (--trkno <= 0)
618 break;
619 } else {
620 /* Skip this block */
621 FSEEK(stream, size, SEEK_CUR);
622 }
623 }
624 conv.trkno = conv.track_index;
625
626 #if DEBUG_PRINT
627 { /* for debug */
628 int i;
629 char buf[1024];
630 /* MDTrackPrintOneEvent(NULL, NULL); */
631 for (i = 0; i < MDSequenceGetNumberOfTracks(inSequence); i++) {
632 MDPointer *ptr;
633 MDEvent *ev;
634 MDTrack *track;
635 track = MDSequenceGetTrack(inSequence, i);
636 ptr = MDPointerNew(track);
637 while ((ev = MDPointerForward(ptr)) != NULL) {
638 printf("%ld: %s\n", (int32_t)MDPointerGetPosition(ptr), MDEventToString(ev, buf, sizeof buf));
639 }
640 MDPointerRelease(ptr);
641 }
642 /* MDTrackPrintOneEvent((MDEvent *)(-1), NULL); */
643 }
644 #endif
645
646 return result;
647 }
648
649 #pragma mark ====== Writing SMF ======
650
651 static MDStatus
652 MDSequenceWriteSMFDeltaTime(MDSMFConvert *cref, MDTickType tick)
653 {
654 cref->deltatime = tick - cref->tick;
655 if (cref->deltatime < 0)
656 MDSequenceSMFConvertError(cref, "tick disorder");
657 if (MDWriteStreamFormat(cref->stream, "w", cref->deltatime) != 1)
658 return kMDErrorCannotWriteToStream;
659 cref->tick += cref->deltatime;
660 return kMDNoError;
661 }
662
663 static MDStatus
664 MDSequenceWriteSMFWriteMessage(MDSMFConvert *cref, const unsigned char *p, int32_t length)
665 {
666 /* Write the message length */
667 if (MDWriteStreamFormat(cref->stream, "w", length) != 1)
668 return kMDErrorCannotWriteToStream;
669
670 /* Write the message body */
671 if (FWRITE_(p, length, cref->stream) < length)
672 return kMDErrorCannotWriteToStream;
673 return kMDNoError;
674 }
675
676 /* Write a special "duration" event */
677 static MDStatus
678 MDSequenceWriteSMFSpecialDurationEvent(MDSMFConvert *cref, MDEvent *eref)
679 {
680 MDTickType d;
681 int i;
682 unsigned char s[12];
683
684 if (MDGetKind(eref) != kMDEventNote) {
685 MDSequenceSMFConvertError(cref, "Internal error during MDSequenceWriteSMFSpecialDurationEvent()");
686 return kMDErrorInternalError;
687 }
688
689 /* Convert the duration to BER-compressed form */
690 d = MDGetDuration(eref);
691 i = sizeof(s) - 1;
692 s[i] = (d & 0x7f);
693 while (i > 4) {
694 d >>= 7;
695 if (d == 0)
696 break;
697 s[--i] = ((d & 0x7f) | 0x80);
698 }
699 s[i - 1] = sizeof(s) - i; /* Message length */
700 i--;
701 s[--i] = kMDMetaDuration;
702 s[--i] = kMDEventSMFMeta;
703 /* s[--i] = 0; *//* delta time */
704
705 if (FWRITE_(s + i, sizeof(s) - i, cref->stream) < sizeof(s) - i)
706 return kMDErrorCannotWriteToStream;
707
708 return kMDNoError;
709 }
710
711 /* Write one meta event */
712 static MDStatus
713 MDSequenceWriteSMFMetaEvent(MDSMFConvert *cref, MDEvent *eref)
714 {
715 int32_t length;
716 int n;
717 unsigned char s[8], *metaDataPtr;
718 const unsigned char *p;
719 MDEventKind kind = MDGetKind(eref);
720
721 n = PUTC(kMDEventSMFMeta, cref->stream);
722 if (n == EOF)
723 return kMDErrorCannotWriteToStream;
724
725 switch (kind) {
726 case kMDEventMetaText:
727 case kMDEventMetaMessage:
728 n = PUTC(MDGetCode(eref), cref->stream);
729 if (n == EOF)
730 return kMDErrorCannotWriteToStream;
731 else {
732 p = MDGetMessageConstPtr(eref, &length);
733 return MDSequenceWriteSMFWriteMessage(cref, p, length);
734 }
735 case kMDEventTempo: {
736 int32_t ntempo;
737 ntempo = MDSequenceTempoToSMFTempo(MDGetTempo(eref));
738 s[0] = ntempo / 65536;
739 s[1] = ntempo / 256;
740 s[2] = ntempo;
741 n = kMDMetaTempo;
742 length = 3;
743 break;
744 }
745 case kMDEventTimeSignature:
746 metaDataPtr = MDGetMetaDataPtr(eref);
747 n = kMDMetaTimeSignature;
748 s[0] = metaDataPtr[0];
749 s[1] = metaDataPtr[1];
750 s[2] = metaDataPtr[2];
751 s[3] = metaDataPtr[3];
752 length = 4;
753 break;
754 case kMDEventKey:
755 metaDataPtr = MDGetMetaDataPtr(eref);
756 n = kMDMetaKey;
757 s[0] = metaDataPtr[0];
758 s[1] = metaDataPtr[1];
759 length = 2;
760 break;
761 case kMDEventSMPTE: {
762 MDSMPTERecord *smp = MDGetSMPTERecordPtr(eref);
763 n = kMDMetaSMPTE;
764 s[0] = smp->hour;
765 s[1] = smp->min;
766 s[2] = smp->sec;
767 s[3] = smp->frame;
768 s[4] = smp->subframe;
769 length = 5;
770 break;
771 }
772 case kMDEventPortNumber:
773 n = kMDMetaPortNumber;
774 s[0] = MDGetData1(eref);
775 length = 1;
776 break;
777 default:
778 MDSequenceSMFConvertError(cref, "Wrong internal meta code %d", kind);
779 n = kMDMetaText; /* Replace with an empty text */
780 s[0] = 0;
781 length = 1;
782 break;
783 }
784
785 if (PUTC(n, cref->stream) == EOF)
786 return kMDErrorCannotWriteToStream;
787
788 return MDSequenceWriteSMFWriteMessage(cref, s, length);
789 }
790
791 /* Write one channel event */
792 static MDStatus
793 MDSequenceWriteSMFChannelEvent(MDSMFConvert *cref, MDEvent *eref)
794 {
795 unsigned char s[4];
796 int n;
797 int data1;
798
799 s[1] = MDGetCode(eref);
800 s[2] = data1 = MDGetData1(eref);
801 n = 3;
802 switch (MDGetKind(eref)) {
803 case kMDEventNote:
804 s[0] = kMDEventSMFNoteOn;
805 s[2] = MDGetNoteOnVelocity(eref);
806 dprintf(2, "kMDEventNote, %02x %02x %02x\n", s[0], s[1], s[2]);
807 break;
808 case kMDEventInternalNoteOff:
809 s[0] = kMDEventSMFNoteOff;
810 s[2] = MDGetNoteOffVelocity(eref);
811 dprintf(2, "kMDEventInternalNoteOff, %02x %02x %02x\n", s[0], s[1], s[2]);
812 break;
813 case kMDEventControl:
814 s[0] = kMDEventSMFControl;
815 break;
816 case kMDEventPitchBend:
817 s[0] = kMDEventSMFPitchBend;
818 s[1] = (data1 & 0x7f);
819 s[2] = ((data1 + 8192) >> 7) & 0x7f;
820 break;
821 case kMDEventProgram:
822 s[0] = kMDEventSMFProgram;
823 s[1] = data1;
824 n = 2;
825 break;
826 case kMDEventChanPres:
827 s[0] = kMDEventSMFChannelPressure;
828 s[1] = data1;
829 n = 2;
830 break;
831 case kMDEventKeyPres:
832 s[0] = kMDEventSMFKeyPressure;
833 break;
834 default:
835 MDSequenceSMFConvertError(cref, "Unknown channel event %d", MDGetKind(eref));
836 /* Replace with an empty text meta */
837 s[0] = kMDEventSMFMeta;
838 s[1] = kMDMetaText;
839 s[2] = 0;
840 if (FWRITE_(s, n, cref->stream) < n)
841 return kMDErrorCannotWriteToStream;
842 return kMDNoError;
843 }
844
845 if (cref->track_channel < 16)
846 s[0] |= cref->track_channel;
847 else
848 s[0] |= (MDGetChannel(eref) & 0x0f);
849
850 if (FWRITE_(s, n, cref->stream) < n)
851 return kMDErrorCannotWriteToStream;
852 return kMDNoError;
853 }
854
855 /* Write sequence name and device information as meta events */
856 static MDStatus
857 MDSequenceWriteSMFTrackNameAndDevice(MDSMFConvert *cref)
858 {
859 MDStatus result;
860 char buf[256];
861 int32_t dev, i;
862 const char *key, *value;
863
864 /* Sequence name */
865 MDTrackGetName(cref->temptrk, buf, sizeof buf);
866 if (buf[0] == 0) {
867 /* We will avoid an empty sequence name, because otherwise the older version
868 of Alchemusica will try to get the name from the first TEXT metaevent,
869 which causes problem when extra info is stored as a TEXT metaevent */
870 strcpy(buf, " ");
871 }
872 result = MDSequenceWriteSMFDeltaTime(cref, 0);
873 if (result != kMDNoError)
874 return result;
875 if (PUTC(kMDEventSMFMeta, cref->stream) == EOF)
876 return kMDErrorCannotWriteToStream;
877 if (PUTC(kMDMetaSequenceName, cref->stream) == EOF)
878 return kMDErrorCannotWriteToStream;
879 result = MDSequenceWriteSMFWriteMessage(cref, (unsigned char *)buf, (int)strlen(buf));
880 if (result != kMDNoError)
881 return result;
882
883 /* Device name */
884 dev = MDTrackGetDevice(cref->temptrk);
885 if (dev < 0 || MDPlayerGetDestinationName(dev, buf, sizeof buf) != kMDNoError)
886 MDTrackGetDeviceName(cref->temptrk, buf, sizeof buf);
887 result = MDSequenceWriteSMFDeltaTime(cref, 0);
888 if (result != kMDNoError)
889 return result;
890 if (PUTC(kMDEventSMFMeta, cref->stream) == EOF)
891 return kMDErrorCannotWriteToStream;
892 if (PUTC(kMDMetaDeviceName, cref->stream) == EOF)
893 return kMDErrorCannotWriteToStream;
894 result = MDSequenceWriteSMFWriteMessage(cref, (unsigned char *)buf, (int)strlen(buf));
895 if (result != kMDNoError)
896 return result;
897
898 /* Other extra info */
899 for (i = 0; (value = MDTrackGetExtraInfoAtIndex(cref->temptrk, i, &key)) != NULL; i++) {
900 char *msg;
901 asprintf(&msg, "%%%%%s:%s", key, value);
902 result = MDSequenceWriteSMFDeltaTime(cref, 0);
903 if (result != kMDNoError)
904 return result;
905 if (PUTC(kMDEventSMFMeta, cref->stream) == EOF)
906 return kMDErrorCannotWriteToStream;
907 if (PUTC(kMDMetaText, cref->stream) == EOF)
908 return kMDErrorCannotWriteToStream;
909 result = MDSequenceWriteSMFWriteMessage(cref, (unsigned char *)msg, (int)strlen(msg));
910 if (result != kMDNoError)
911 return result;
912 }
913 return result;
914 }
915
916 /* Write one SMF track */
917 static MDStatus
918 MDSequenceWriteSMFTrackWithSelection(MDSMFConvert *cref, IntGroup *pset, char eotSelected)
919 {
920 MDPointer *ptr;
921 MDEvent *eref;
922 MDStatus result = kMDNoError;
923 MDTrack *noteOffTrack;
924 MDPointer *noteOffPtr;
925 MDEvent *noteOffRef;
926 MDTickType noteOffTick;
927 int n, count;
928 int32_t nevents;
929 int idx;
930 const unsigned char sEndOfTrack[3] = { kMDEventSMFMeta, kMDMetaEndOfTrack, 0 };
931
932 /* Initialize track info */
933 cref->tick = 0;
934 cref->deltatime = 0;
935
936 ptr = MDPointerNew(cref->temptrk);
937 if (ptr == NULL)
938 return kMDErrorOutOfMemory;
939
940 noteOffTrack = MDTrackNew();
941 if (noteOffTrack == NULL)
942 return kMDErrorOutOfMemory;
943 noteOffPtr = MDPointerNew(noteOffTrack);
944 if (noteOffPtr == NULL)
945 return kMDErrorOutOfMemory;
946 noteOffTick = kMDMaxTick;
947
948 count = 0;
949 idx = -1;
950 if (pset == NULL || pset == (IntGroup *)(-1)) {
951 nevents = MDTrackGetNumberOfEvents(cref->temptrk);
952 result = MDSequenceWriteSMFTrackNameAndDevice(cref);
953 if (result != kMDNoError)
954 return result;
955 } else
956 nevents = IntGroupGetCount(pset);
957
958 while (
959 (eref =
960 ((pset == NULL || pset == (IntGroup *)(-1))
961 ? MDPointerForward(ptr)
962 : MDPointerForwardWithPointSet(ptr, pset, &idx)
963 )
964 ) != NULL && MDGetKind(eref) != kMDEventStop) {
965
966 if (MDGetKind(eref) == kMDEventNull) {
967 /* We should not have it, but sometimes we get it because of bugs */
968 MDSequenceSMFConvertError(cref, "Incorrect event");
969 continue;
970 }
971
972 if (++count >= 1000) {
973 if (cref->callback != NULL) {
974 n = (*cref->callback)(100.0f * (cref->track_index + ((float)MDPointerGetPosition(ptr) / nevents)) / cref->trkno, cref->cbdata);
975 if (n == 0) {
976 result = kMDErrorUserInterrupt;
977 break;
978 }
979 }
980 count = 0;
981 }
982
983 /* Check the note off events and output if necessary */
984 if (noteOffTick <= MDGetTick(eref)) {
985 while (1) {
986 MDPointerSetPosition(noteOffPtr, 0);
987 if ((noteOffRef = MDPointerCurrent(noteOffPtr)) != NULL && MDGetTick(noteOffRef) <= MDGetTick(eref)) {
988 dprintf(2, "a pending note-off output, tick %ld code %d vel %d\n", MDGetTick(noteOffRef), MDGetCode(noteOffRef), MDGetNoteOffVelocity(noteOffRef));
989 result = MDSequenceWriteSMFDeltaTime(cref, MDGetTick(noteOffRef));
990 if (result == kMDNoError)
991 result = MDSequenceWriteSMFChannelEvent(cref, noteOffRef);
992 if (result != kMDNoError)
993 goto last;
994 MDPointerDeleteAnEvent(noteOffPtr, NULL);
995 dprintf(2, "num of pending note-offs = %ld\n", MDTrackGetNumberOfEvents(noteOffTrack));
996 } else {
997 if (noteOffRef != NULL)
998 noteOffTick = MDGetTick(noteOffRef);
999 else
1000 noteOffTick = kMDMaxTick;
1001 break;
1002 }
1003 }
1004 }
1005
1006 /* Write the delta time */
1007 result = MDSequenceWriteSMFDeltaTime(cref, MDGetTick(eref));
1008 if (result != kMDNoError)
1009 break;
1010
1011 /* Write the status byte */
1012 if (MDIsSysexEvent(eref)) { /* sysex events */
1013 const unsigned char *p;
1014 int32_t length;
1015 p = MDGetMessageConstPtr(eref, &length);
1016 if (MDGetKind(eref) == kMDEventSysexCont)
1017 n = kMDEventSMFSysexF7;
1018 else {
1019 n = kMDEventSMFSysex;
1020 /* Skip 'F0' at the top */
1021 if (*p == 0xf0) {
1022 p++;
1023 length--;
1024 }
1025 }
1026 if (PUTC(n, cref->stream) == EOF) {
1027 result = kMDErrorCannotWriteToStream;
1028 break;
1029 }
1030 result = MDSequenceWriteSMFWriteMessage(cref, p, length);
1031 } else if (MDIsMetaEvent(eref)) { /* meta events */
1032 result = MDSequenceWriteSMFMetaEvent(cref, eref);
1033 } else { /* channel events */
1034 int overlap = 0;
1035 if (MDGetKind(eref) == kMDEventNote) {
1036 /* Register the note-off for later output */
1037 MDEvent noteOffEvent, *ep;
1038 MDEventInit(&noteOffEvent);
1039 MDSetKind(&noteOffEvent, kMDEventInternalNoteOff);
1040 MDSetCode(&noteOffEvent, MDGetCode(eref));
1041 MDSetChannel(&noteOffEvent, MDGetChannel(eref));
1042 MDSetNoteOffVelocity(&noteOffEvent, MDGetNoteOffVelocity(eref));
1043 MDSetTick(&noteOffEvent, MDGetTick(eref) + MDGetDuration(eref));
1044 #if 1
1045 /* Search from the end of registered note-off */
1046 MDPointerSetPosition(noteOffPtr, MDTrackGetNumberOfEvents(noteOffTrack));
1047 while ((ep = MDPointerBackward(noteOffPtr)) != NULL && MDGetTick(ep) > MDGetTick(&noteOffEvent)) {
1048 if (MDGetCode(ep) == MDGetCode(eref) && MDGetChannel(ep) == MDGetChannel(eref))
1049 /* Two note events are overlapping and first-in is NOT first-out */
1050 overlap = 1;
1051 }
1052 #else
1053 /* MDPointerSetPosition(noteOffPtr, 0);
1054 MDPointerJumpToTick(noteOffPtr, MDGetTick(&noteOffEvent) + 1); */
1055 #endif
1056 result = MDPointerInsertAnEvent(noteOffPtr, &noteOffEvent);
1057 if (result != kMDNoError)
1058 break;
1059 if (noteOffTick > MDGetTick(&noteOffEvent))
1060 noteOffTick = MDGetTick(&noteOffEvent);
1061 dprintf(2, "a note-off registered, tick %ld code %d vel %d\n", MDGetTick(&noteOffEvent), MDGetCode(&noteOffEvent), MDGetNoteOffVelocity(&noteOffEvent));
1062 dprintf(2, "num of pending note-offs = %ld\n", MDTrackGetNumberOfEvents(noteOffTrack));
1063 }
1064 if (overlap) {
1065 /* Write a special 'duration' meta-event */
1066 result = MDSequenceWriteSMFSpecialDurationEvent(cref, eref);
1067 if (result == kMDErrorCannotWriteToStream)
1068 break; /* Stop writing */
1069 else if (result == kMDNoError) {
1070 /* Write deltatime 0 (for next event) */
1071 if (PUTC(0, cref->stream) == EOF) {
1072 result = kMDErrorCannotWriteToStream;
1073 break;
1074 }
1075 }
1076 }
1077 result = MDSequenceWriteSMFChannelEvent(cref, eref);
1078 }
1079
1080 if (result != kMDNoError)
1081 break;
1082 } /* end while */
1083
1084 /* Write the remaining note-off events */
1085 if (result == kMDNoError && noteOffTick < kMDMaxTick) {
1086 MDPointerSetPosition(noteOffPtr, -1);
1087 while ((noteOffRef = MDPointerForward(noteOffPtr)) != NULL) {
1088 dprintf(2, "a pending note-off output, tick %ld code %d vel %d\n", MDGetTick(noteOffRef), MDGetCode(noteOffRef), MDGetNoteOffVelocity(noteOffRef));
1089 result = MDSequenceWriteSMFDeltaTime(cref, MDGetTick(noteOffRef));
1090 if (result == kMDNoError)
1091 result = MDSequenceWriteSMFChannelEvent(cref, noteOffRef);
1092 if (result != kMDNoError)
1093 break;
1094 }
1095 }
1096
1097 /* Write the end-of-track event */
1098 if (result == kMDNoError) {
1099 if (eotSelected || pset == NULL || pset == (IntGroup *)(-1))
1100 cref->deltatime = MDTrackGetDuration(cref->temptrk) - cref->tick;
1101 else
1102 cref->deltatime = 1;
1103 if (MDWriteStreamFormat(cref->stream, "w", cref->deltatime) != 1 || FWRITE_(sEndOfTrack, sizeof sEndOfTrack, cref->stream) < sizeof sEndOfTrack)
1104 result = kMDErrorCannotWriteToStream;
1105 }
1106
1107 last:
1108 MDPointerRelease(ptr);
1109 MDPointerRelease(noteOffPtr);
1110 MDTrackRelease(noteOffTrack);
1111 return result;
1112 }
1113
1114 MDStatus
1115 MDSequenceWriteSMFWithSelection(MDSequence *inSequence, IntGroup **psetArray, char *eotSelectFlags, STREAM stream, MDSequenceCallback callback, void *cbdata, STREAM err_stream)
1116 {
1117 MDStatus result = kMDNoError;
1118 MDSMFConvert conv;
1119 short trkno, trkmax;
1120 int32_t size, pos;
1121
1122 if (inSequence == NULL || stream == NULL)
1123 return kMDErrorInternalError;
1124
1125 /* Initialize the convert record */
1126 memset(&conv, 0, sizeof(conv));
1127 conv.stream = stream;
1128 conv.err_stream = err_stream;
1129 conv.sequence = inSequence;
1130 conv.timebase = MDSequenceGetTimebase(inSequence);
1131 trkmax = MDSequenceGetNumberOfTracks(inSequence);
1132 if (psetArray != NULL) {
1133 conv.trkno = 0;
1134 for (trkno = 0; trkno < trkmax; trkno++) {
1135 if (psetArray[trkno] != NULL)
1136 conv.trkno++;
1137 }
1138 } else {
1139 conv.trkno = trkmax;
1140 }
1141 conv.callback = callback;
1142 conv.cbdata = cbdata;
1143 conv.track_index = 0;
1144
1145 /* if (conv.trkno < 1)
1146 return kMDErrorInternalError; */
1147
1148 /* Write the file header */
1149 if (MDWriteStreamFormat(conv.stream, "A4Nn3", "MThd", 6L,
1150 (short)(conv.trkno == 1 ? 0 : 1), (short)conv.trkno, (short)conv.timebase) != 5)
1151 result = kMDErrorCannotWriteToStream;
1152
1153 /* Write each track */
1154 for (trkno = 0; trkno < trkmax; trkno++) {
1155 IntGroup *pset;
1156 char eotSelected;
1157 if (psetArray != NULL) {
1158 pset = psetArray[trkno];
1159 if (pset == NULL) {
1160 /* if (trkno == 0)
1161 pset = (IntGroup *)(-1); *//* An empty selection; conductor track will always be written */
1162 /* else */
1163 continue;
1164 }
1165 } else pset = NULL;
1166
1167 if (eotSelectFlags != NULL)
1168 eotSelected = eotSelectFlags[trkno];
1169 else eotSelected = 0;
1170
1171 /* Get the track */
1172 conv.temptrk = MDSequenceGetTrack(inSequence, trkno);
1173 if (conv.temptrk == NULL) {
1174 result = kMDErrorInternalError;
1175 break;
1176 }
1177 /* conv.track_index = trkno; */
1178 if (MDSequenceIsSingleChannelMode(inSequence))
1179 conv.track_channel = MDTrackGetTrackChannel(conv.temptrk) & 15;
1180 else
1181 conv.track_channel = 16;
1182 if (MDWriteStreamFormat(conv.stream, "A4N", "MTrk", 0L) == 2) {
1183 conv.pos = (int32_t)FTELL(conv.stream) - 4;
1184 /* if (pset == (IntGroup *)(-1))
1185 result = kMDNoError;
1186 else */
1187 result = MDSequenceWriteSMFTrackWithSelection(&conv, pset, eotSelected);
1188 if (result != kMDNoError) {
1189 dprintf(0, "Error %d occurred during write of SMF track\n", result);
1190 }
1191 pos = (int32_t)FTELL(conv.stream);
1192 size = pos - conv.pos - 4;
1193 FSEEK(conv.stream, conv.pos, SEEK_SET);
1194 MDWriteStreamFormat(conv.stream, "N", size);
1195 FSEEK(conv.stream, pos, SEEK_SET);
1196 if (result != kMDNoError)
1197 break;
1198 } else {
1199 result = kMDErrorCannotWriteToStream;
1200 break;
1201 }
1202 conv.track_index++;
1203 }
1204
1205 return result;
1206 }
1207
1208 MDStatus
1209 MDSequenceWriteSMF(MDSequence *inSequence, STREAM stream, MDSequenceCallback callback, void *cbdata, STREAM err_stream)
1210 {
1211 return MDSequenceWriteSMFWithSelection(inSequence, NULL, NULL, stream, callback, cbdata, err_stream);
1212 }
1213
1214 #pragma mark ====== Read/Write Catalog ======
1215
1216 MDStatus
1217 MDSequenceWriteCatalog(MDCatalog *inCatalog, STREAM stream)
1218 {
1219 char buf[64];
1220 int i;
1221 off_t pos0, pos1;
1222 pos0 = FTELL(stream);
1223 MDWriteStreamFormat(stream, "N", (int32_t)0); /* Dummy */
1224 MDWriteStreamFormat(stream, "N", (int32_t)inCatalog->num);
1225 MDWriteStreamFormat(stream, "NN", (int32_t)inCatalog->startTick, (int32_t)inCatalog->endTick);
1226 pos1 = FTELL(stream);
1227 FSEEK(stream, pos0, SEEK_SET);
1228 MDWriteStreamFormat(stream, "N", (int32_t)(pos1 - pos0 - 4));
1229 FSEEK(stream, pos1, SEEK_SET);
1230
1231 for (i = 0; i < inCatalog->num; i++) {
1232 MDCatalogTrack *cat = inCatalog->catTrack + i;
1233 pos0 = FTELL(stream);
1234 MDWriteStreamFormat(stream, "N", (int32_t)0); /* Dummy */
1235 memset(buf, 0, 64);
1236 strncpy(buf, cat->name, 63);
1237 MDWriteStreamFormat(stream, "NA64NN", (int32_t)cat->originalTrackNo, buf, (int32_t)cat->numEvents, (int32_t)cat->numMIDIEvents);
1238 pos1 = FTELL(stream);
1239 FSEEK(stream, pos0, SEEK_SET);
1240 MDWriteStreamFormat(stream, "N", (int32_t)(pos1 - pos0 - 4));
1241 FSEEK(stream, pos1, SEEK_SET);
1242 }
1243 return kMDNoError;
1244 }
1245
1246 MDCatalog *
1247 MDSequenceReadCatalog(STREAM stream)
1248 {
1249 int i;
1250 int32_t num, num2, num3;
1251 off_t pos0;
1252 MDCatalog *catalog;
1253
1254 pos0 = FTELL(stream);
1255 if (MDReadStreamFormat(stream, "N", &num) < 1)
1256 return NULL;
1257 pos0 += num - 4;
1258 MDReadStreamFormat(stream, "NNN", &num, &num2, &num3);
1259 catalog = (MDCatalog *)malloc(sizeof(MDCatalog) + (num - 1) * sizeof(MDCatalogTrack));
1260 if (catalog == NULL)
1261 return NULL;
1262 memset(catalog, 0, sizeof(MDCatalog) + (num - 1) * sizeof(MDCatalogTrack));
1263 catalog->num = num;
1264 catalog->startTick = num2;
1265 catalog->endTick = num3;
1266 FSEEK(stream, pos0, SEEK_SET);
1267 for (i = 0; i < catalog->num; i++) {
1268 MDCatalogTrack *cat = catalog->catTrack + i;
1269 MDReadStreamFormat(stream, "N", &num);
1270 pos0 += num - 4;
1271 MDReadStreamFormat(stream, "NA64NN", &num, cat->name, &num2, &num3);
1272 cat->name[63] = 0;
1273 cat->originalTrackNo = num;
1274 cat->numEvents = num2;
1275 cat->numMIDIEvents = num3;
1276 FSEEK(stream, pos0, SEEK_SET);
1277 }
1278 return catalog;
1279 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26