00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef HAVE_CONFIG_H
00022 # include <config.h>
00023 #endif
00024
00025
00026 #if defined(MACOS) || defined(MACOSX)
00027
00028 #include <iomanip>
00029 #include <cstdlib>
00030 #include <string>
00031
00032 #include "mac_midi.h"
00033
00034 #ifdef MACOSX
00035 #include <CoreServices/CoreServices.h>
00036 #include <QuickTime/QuickTimeMusic.h>
00037 #endif
00038
00039 using std::cout;
00040 using std::endl;
00041 using std::malloc;
00042 using std::free;
00043 using std::realloc;
00044 using std::memset;
00045
00046 enum
00047 {
00048
00049 kNoteRequestEventLength = ((sizeof(NoteRequest)/sizeof(long)) + 2),
00050
00051
00052 kMarkerEventLength = 1,
00053
00054
00055 kGeneralEventLength = 2
00056 };
00057
00058 #define BUFFER_INCREMENT 5000
00059
00060 #define REST_IF_NECESSARY() do {\
00061 int timeDiff = eventPos->time - lastEventTime; \
00062 if(timeDiff) \
00063 { \
00064 timeDiff = (int)(timeDiff*tick); \
00065 qtma_StuffRestEvent(*tunePos, timeDiff); \
00066 tunePos++; \
00067 lastEventTime = eventPos->time; \
00068 } \
00069 } while(0)
00070
00071
00072 static uint32 *BuildTuneSequence(midi_event *evntlist, int ppqn, int part_poly_max[32], int part_to_inst[32], int &numParts);
00073 static uint32 *BuildTuneHeader(int part_poly_max[32], int part_to_inst[32], int numParts);
00074
00075
00076 Mac_QT_midi::Mac_QT_midi()
00077 : MidiAbstract(), mTunePlayer(0), mTuneSequence(0), mTuneHeader(0)
00078 {
00079
00080
00081 mTunePlayer = OpenDefaultComponent(kTunePlayerComponentType, 0);
00082 if( 0 == mTunePlayer )
00083 throw exult_exception("Couldn't get tune place component");
00084 }
00085
00086 Mac_QT_midi::~Mac_QT_midi(void)
00087 {
00088 if(mTunePlayer)
00089 {
00090 if(mTuneSequence)
00091 TuneStop(mTunePlayer, 0);
00092 CloseComponent(mTunePlayer);
00093 mTunePlayer = 0;
00094 }
00095 if(mTuneSequence)
00096 {
00097 free(mTuneSequence);
00098 mTuneSequence = 0;
00099 }
00100 if(mTuneHeader)
00101 {
00102 DisposePtr((Ptr)mTuneHeader);
00103 mTuneHeader = 0;
00104 }
00105 }
00106
00107
00108 void Mac_QT_midi::start_track(XMIDIEventList *elist, bool repeat)
00109 {
00110 int part_to_inst[32];
00111 int part_poly_max[32];
00112 int numParts = 0;
00113
00114
00115
00116
00117 int ppqn = 60;
00118 midi_event *evntlist = elist->events;
00119
00120 UInt32 queueFlags = 0;
00121 ComponentResult tpError;
00122
00123 memset(part_poly_max,0,sizeof(part_poly_max));
00124 memset(part_to_inst,-1,sizeof(part_to_inst));
00125
00126
00127 stop_track();
00128
00129
00130 mTuneSequence = BuildTuneSequence(evntlist, ppqn, part_poly_max, part_to_inst, numParts);
00131 if(!mTuneSequence)
00132 goto bail;
00133
00134
00135
00136 mTuneHeader = BuildTuneHeader(part_poly_max, part_to_inst, numParts);
00137 if(!mTuneHeader)
00138 goto bail;
00139
00140
00141 queueFlags = kTuneStartNow;
00142 if(repeat)
00143 queueFlags |= kTuneLoopUntil;
00144
00145
00146 tpError = TuneSetTimeScale(mTunePlayer, 1000);
00147 assert (tpError == noErr);
00148
00149
00150 tpError = TuneSetHeader(mTunePlayer, (UInt32 *)mTuneHeader);
00151 assert (tpError == noErr);
00152
00153
00154 tpError = TunePreroll(mTunePlayer);
00155 assert (tpError == noErr);
00156
00157
00158 tpError = TuneSetVolume(mTunePlayer, 0x00010000);
00159 assert (tpError == noErr);
00160
00161
00162 tpError = TuneQueue(mTunePlayer, (UInt32 *)mTuneSequence, 0x00010000, 0, 0xFFFFFFFF, queueFlags, NULL, 0);
00163 assert (tpError == noErr);
00164
00165 return;
00166
00167 bail:
00168
00169
00170 stop_track();
00171 }
00172
00173 void Mac_QT_midi::stop_track(void)
00174 {
00175 if(0 == mTuneSequence)
00176 return;
00177
00178
00179
00180
00181
00182 TuneStop(mTunePlayer, 0);
00183
00184
00185 TuneUnroll(mTunePlayer);
00186
00187
00188 free(mTuneSequence);
00189 mTuneSequence = 0;
00190
00191 if(mTuneHeader)
00192 {
00193 DisposePtr((Ptr)mTuneHeader);
00194 mTuneHeader = 0;
00195 }
00196 }
00197
00198 bool Mac_QT_midi::is_playing(void)
00199 {
00200 TuneStatus ts;
00201
00202 TuneGetStatus(mTunePlayer,&ts);
00203 return ts.queueTime != 0;
00204 }
00205
00206 const char *Mac_QT_midi::copyright(void)
00207 {
00208 return "Internal QuickTime MIDI player";
00209 }
00210
00211 uint32 *BuildTuneSequence(midi_event *evntlist, int ppqn, int part_poly_max[32], int part_to_inst[32], int &numParts)
00212 {
00213 int part_poly[32];
00214 int channel_to_part[16];
00215
00216 int channel_pan[16];
00217 int channel_vol[16];
00218 int channel_pitch_bend[16];
00219
00220 int lastEventTime = 0;
00221 int tempo = 500000;
00222 double Ippqn = 1.0 / (1000*ppqn);
00223 double tick = tempo * Ippqn;
00224 midi_event *eventPos = evntlist;
00225 uint32 *tunePos, *endPos;
00226 uint32 *tuneSequence;
00227 size_t tuneSize;
00228 #ifdef DEBUG
00229 int numEventsHandled = 0;
00230 #endif
00231
00232
00233 tuneSize = 5000;
00234 tuneSequence = (uint32 *)malloc(tuneSize * sizeof(uint32));
00235 if (tuneSequence == NULL)
00236 return NULL;
00237
00238
00239 tunePos = tuneSequence;
00240 endPos = tuneSequence + tuneSize;
00241
00242
00243 memset(part_poly,0,sizeof(part_poly));
00244
00245 memset(channel_to_part,-1,sizeof(channel_to_part));
00246 memset(channel_pan,-1,sizeof(channel_pan));
00247 memset(channel_vol,-1,sizeof(channel_vol));
00248 memset(channel_pitch_bend,-1,sizeof(channel_pitch_bend));
00249
00250
00251
00252
00253
00254
00255
00256 while(eventPos)
00257 {
00258 int status = (eventPos->status&0xF0)>>4;
00259 int channel = eventPos->status&0x0F;
00260 int part = channel_to_part[channel];
00261 int velocity, pitch;
00262 int value, controller;
00263 int bend;
00264 int newInst;
00265
00266
00267 if((tunePos+16) > endPos)
00268 {
00269
00270 uint32 *oldTuneSequence = tuneSequence;
00271
00272 tuneSize += BUFFER_INCREMENT;
00273 tuneSequence = (uint32 *)realloc(tuneSequence, tuneSize * sizeof(uint32));
00274 if(oldTuneSequence != tuneSequence)
00275 tunePos += tuneSequence - oldTuneSequence;
00276 endPos = tuneSequence + tuneSize;
00277 }
00278
00279 #if defined(DEBUG) && 0
00280 numEventsHandled++;
00281
00282 cout << std::setw(4) << numEventsHandled << ". ";
00283 cout << "Time: " << std::setw(5) << eventPos->time << " ";
00284 cout << std::hex << std::uppercase;
00285 cout << "Status 0x" << status << " Channel: 0x" << channel << " ";
00286 cout << "Data 0x" << std::setw(4) <<*(unsigned short *)(eventPos->data) << " ";
00287 cout << std::dec;
00288 cout << "Length " << eventPos->len << endl;
00289 #endif
00290
00291 switch (status)
00292 {
00293 case MIDI_STATUS_NOTE_OFF:
00294 assert(part>=0 && part<=31);
00295
00296
00297 part_poly[part]--;
00298 break;
00299 case MIDI_STATUS_NOTE_ON:
00300 if (part < 0)
00301 {
00302
00303
00304 int newInst;
00305
00306 if (channel == 9)
00307 newInst = kFirstDrumkit + 1;
00308 else
00309 newInst = kFirstGMInstrument;
00310 part = channel_to_part[channel] = numParts;
00311 part_to_inst[numParts++] = newInst;
00312 }
00313
00314 assert(part<=31);
00315
00316
00317 pitch = eventPos->data[0];
00318 velocity = eventPos->data[1];
00319
00320 if (velocity == 0)
00321 {
00322
00323 part_poly[part]--;
00324 }
00325 else
00326 {
00327
00328 int foo = ++part_poly[part];
00329 if (part_poly_max[part] < foo)
00330 part_poly_max[part] = foo;
00331
00332
00333 midi_event *noteOffPos;
00334 for(noteOffPos = eventPos; noteOffPos; noteOffPos = noteOffPos->next)
00335 {
00336 if ((noteOffPos->status&0xF0)>>4 == MIDI_STATUS_NOTE_OFF
00337 && channel == (eventPos->status&0x0F)
00338 && pitch == noteOffPos->data[0])
00339 break;
00340
00341 if ((noteOffPos->status&0xF0)>>4 == MIDI_STATUS_NOTE_ON
00342 && channel == (eventPos->status&0x0F)
00343 && pitch == noteOffPos->data[0]
00344 && 0 == noteOffPos->data[1])
00345 break;
00346 }
00347
00348
00349 if (noteOffPos)
00350 {
00351
00352 int duration = (int)((noteOffPos->time - eventPos->time)*tick);
00353
00354 REST_IF_NECESSARY();
00355
00356 if (duration < 2048 && pitch>=32 && pitch<=95 && velocity>=0 && velocity<=127)
00357 {
00358 qtma_StuffNoteEvent(*tunePos, part, pitch, velocity, duration);
00359 tunePos++;
00360 }
00361 else
00362 {
00363 qtma_StuffXNoteEvent(*tunePos, *(tunePos+1), part, pitch, velocity, duration);
00364 tunePos+=2;
00365 }
00366
00367 #if defined(DEBUG) && 0
00368 cout << std::setw(4) << numEventsHandled << ". ";
00369 cout << "NOTE ON duration " << std::setw(4) << duration << " ";
00370 cout << "Channel " << std::setw(2) << channel << " ";
00371 cout << "Part " << std::setw(2) << part << " ";
00372 cout << "Pitch " << std::setw(2) << pitch << " ";
00373 cout << "Velocity " << std::setw(2) << velocity << endl;
00374 #endif
00375 }
00376 }
00377 break;
00378 case MIDI_STATUS_AFTERTOUCH:
00379 COUT("MIDI_STATUS_AFTERTOUCH");
00380 break;
00381 case MIDI_STATUS_CONTROLLER:
00382 controller = eventPos->data[0];
00383 value = eventPos->data[1];
00384
00385 switch(controller)
00386 {
00387 case 0:
00388 break;
00389 case kControllerVolume:
00390 if(channel_vol[channel] != value<<8)
00391 {
00392 channel_vol[channel] = value<<8;
00393 if(part>=0 && part<=31)
00394 {
00395 REST_IF_NECESSARY();
00396 qtma_StuffControlEvent(*tunePos, part, kControllerVolume, channel_vol[channel]);
00397 tunePos++;
00398 }
00399 }
00400 break;
00401 case kControllerPan:
00402 if(channel_pan[channel] != ((value << 1) + 256))
00403 {
00404 channel_pan[channel] = ((value << 1) + 256);
00405 if(part>=0 && part<=31)
00406 {
00407 REST_IF_NECESSARY();
00408 qtma_StuffControlEvent(*tunePos, part, kControllerPan, channel_pan[channel]);
00409 tunePos++;
00410 }
00411 }
00412 break;
00413 default:
00414 COUT("CONTROLLER not handled: "<< controller);
00415 break;
00416 }
00417
00418 break;
00419 case MIDI_STATUS_PROG_CHANGE:
00420
00421 newInst = eventPos->data[0];
00422
00423 if (channel == 9)
00424 newInst += kFirstDrumkit;
00425 else
00426 newInst += kFirstGMInstrument;
00427
00428 if(newInst != part_to_inst[part])
00429 {
00430
00431
00432 part = channel_to_part[channel] = numParts;
00433 part_to_inst[numParts++] = newInst;
00434
00435 if(channel_vol[channel] >= 0)
00436 {
00437 REST_IF_NECESSARY();
00438 qtma_StuffControlEvent(*tunePos, part, kControllerVolume, channel_vol[channel]);
00439 tunePos++;
00440 }
00441 if(channel_pan[channel] >= 0)
00442 {
00443 REST_IF_NECESSARY();
00444 qtma_StuffControlEvent(*tunePos, part, kControllerPan, channel_pan[channel]);
00445 tunePos++;
00446 }
00447 if(channel_pitch_bend[channel] >= 0)
00448 {
00449 REST_IF_NECESSARY();
00450 qtma_StuffControlEvent(*tunePos, part, kControllerPitchBend, channel_pitch_bend[channel]);
00451 tunePos++;
00452 }
00453 }
00454 break;
00455 case MIDI_STATUS_PRESSURE:
00456 COUT("MIDI_STATUS_PRESSURE");
00457 break;
00458 case MIDI_STATUS_PITCH_WHEEL:
00459
00460
00461
00462 bend = eventPos->data[0] & 0x7f | (eventPos->data[1] & 0x7f) << 7;
00463
00464
00465 bend -= 0x2000;
00466
00467
00468 bend <<= 4;
00469
00470
00471 if(channel_pitch_bend[channel] == bend)
00472 break;
00473
00474 channel_pitch_bend[channel] = bend;
00475 if(part>=0 && part<=31)
00476 {
00477
00478 REST_IF_NECESSARY();
00479 qtma_StuffControlEvent(*tunePos, part, kControllerPitchBend, bend);
00480 tunePos++;
00481 }
00482 break;
00483 case MIDI_STATUS_SYSEX:
00484 if (eventPos->status == 0xFF && eventPos->data[0] == 0x51)
00485 {
00486 tempo = (eventPos->buffer[0] << 16) +
00487 (eventPos->buffer[1] << 8) +
00488 eventPos->buffer[2];
00489
00490 tick = tempo * Ippqn;
00491 }
00492 break;
00493 }
00494
00495
00496 eventPos = eventPos->next;
00497 }
00498
00499
00500 *tunePos = kEndMarkerValue;
00501
00502 return tuneSequence;
00503 }
00504
00505
00506 uint32 *BuildTuneHeader(int part_poly_max[32], int part_to_inst[32], int numParts)
00507 {
00508 uint32 *myHeader;
00509 uint32 *myPos1, *myPos2;
00510 NoteRequest *myNoteRequest;
00511 NoteAllocator myNoteAllocator;
00512 ComponentResult myErr = noErr;
00513
00514 myHeader = NULL;
00515 myNoteAllocator = NULL;
00516
00517
00518
00519
00520 myNoteAllocator = OpenDefaultComponent(kNoteAllocatorComponentType,0);
00521 if (myNoteAllocator == NULL)
00522 goto bail;
00523
00524
00525
00526
00527 myHeader = (uint32 *)
00528 NewPtrClear((numParts * kNoteRequestEventLength + kMarkerEventLength) * sizeof(uint32));
00529 if (myHeader == NULL)
00530 goto bail;
00531
00532 myPos1 = myHeader;
00533
00534
00535
00536
00537 for(int part = 0; part < numParts; ++part)
00538 {
00539
00540
00541
00542 myPos2 = myPos1 + (kNoteRequestEventLength - 1);
00543 qtma_StuffGeneralEvent(*myPos1, *myPos2, part, kGeneralEventNoteRequest, kNoteRequestEventLength);
00544 myNoteRequest = (NoteRequest *)(myPos1 + 1);
00545 myNoteRequest->info.flags = 0;
00546 #if defined(MACOS) || defined(MACOSX)
00547 myNoteRequest->info.polyphony.bigEndianValue = EndianS32_LtoB(part_poly_max[part]);
00548 myNoteRequest->info.typicalPolyphony.bigEndianValue = EndianS32_LtoB(0x00010000);
00549 #else
00550 myNoteRequest->info.polyphony = part_poly_max[part];
00551 myNoteRequest->info.typicalPolyphony = 0x00010000;
00552 #endif
00553 myErr = NAStuffToneDescription(myNoteAllocator,part_to_inst[part],&myNoteRequest->tone);
00554 if (myErr != noErr)
00555 goto bail;
00556
00557
00558 myPos1 += kNoteRequestEventLength;
00559 }
00560
00561 *myPos1 = kEndMarkerValue;
00562
00563
00564 bail:
00565 if(myNoteAllocator)
00566 CloseComponent(myNoteAllocator);
00567
00568
00569 if (myErr != noErr) {
00570 DisposePtr((Ptr)myHeader);
00571 myHeader = NULL;
00572 }
00573
00574 return myHeader;
00575 }
00576
00577 #endif