int main (int argc, const char * argv[]) { if (argc == 1) { fprintf (stderr, "%s\n", usageStr); exit(0); } char* filePath = 0; bool shouldPlay = false; bool shouldSetBank = false; bool shouldUseMIDIEndpoint = false; bool shouldPrint = true; bool waitAtEnd = false; bool diskStream = false; OSType dataFormat = 0; Float64 srate = 0; const char* outputFilePath = 0; MusicSequenceLoadFlags loadFlags = 0; char* bankPath = 0; Float32 startTime = 0; UInt32 numFrames = 512; std::set<int> trackSet; for (int i = 1; i < argc; ++i) { if (!strcmp ("-p", argv[i])) { shouldPlay = true; } else if (!strcmp ("-w", argv[i])) { waitAtEnd = true; } else if (!strcmp ("-d", argv[i])) { diskStream = true; } else if (!strcmp ("-b", argv[i])) { shouldSetBank = true; if (++i == argc) goto malformedInput; bankPath = const_cast<char*>(argv[i]); } else if (!strcmp ("-n", argv[i])) { shouldPrint = false; } else if ((filePath == 0) && (argv[i][0] == '/' || argv[i][0] == '~')) { filePath = const_cast<char*>(argv[i]); } else if (!strcmp ("-s", argv[i])) { if (++i == argc) goto malformedInput; sscanf (argv[i], "%f", &startTime); } else if (!strcmp ("-t", argv[i])) { int index; if (++i == argc) goto malformedInput; sscanf (argv[i], "%d", &index); trackSet.insert(--index); } else if (!strcmp("-e", argv[i])) { shouldUseMIDIEndpoint = true; } else if (!strcmp("-c", argv[i])) { loadFlags = kMusicSequenceLoadSMF_ChannelsToTracks; } else if (!strcmp ("-i", argv[i])) { if (++i == argc) goto malformedInput; sscanf (argv[i], "%lu", (unsigned long*)(&numFrames)); } else if (!strcmp ("-f", argv[i])) { if (i + 3 >= argc) goto malformedInput; outputFilePath = argv[++i]; StrToOSType (argv[++i], dataFormat); sscanf (argv[++i], "%lf", &srate); } else { malformedInput: fprintf (stderr, "%s\n", usageStr); exit (1); } } if (filePath == 0) { fprintf (stderr, "You have to specify a MIDI file to print or play\n"); fprintf (stderr, "%s\n", usageStr); exit (1); } if (shouldUseMIDIEndpoint && outputFilePath) { printf ("can't write a file when you try to play out to a MIDI Endpoint\n"); exit (1); } MusicSequence sequence; OSStatus result; FailIf ((result = LoadSMF (filePath, sequence, loadFlags)), fail, "LoadSMF"); if (shouldPrint) CAShow (sequence); if (shouldPlay) { AUGraph graph = 0; AudioUnit theSynth = 0; FailIf ((result = MusicSequenceGetAUGraph (sequence, &graph)), fail, "MusicSequenceGetAUGraph"); FailIf ((result = AUGraphOpen (graph)), fail, "AUGraphOpen"); FailIf ((result = GetSynthFromGraph (graph, theSynth)), fail, "GetSynthFromGraph"); FailIf ((result = AudioUnitSetProperty (theSynth, kAudioUnitProperty_CPULoad, kAudioUnitScope_Global, 0, &maxCPULoad, sizeof(maxCPULoad))), fail, "AudioUnitSetProperty: kAudioUnitProperty_CPULoad"); if (shouldUseMIDIEndpoint) { MIDIClientRef theMidiClient; MIDIClientCreate(CFSTR("Play Sequence"), NULL, NULL, &theMidiClient); ItemCount destCount = MIDIGetNumberOfDestinations(); if (destCount == 0) { fprintf (stderr, "No MIDI Endpoints to play to.\n"); exit(1); } FailIf ((result = MusicSequenceSetMIDIEndpoint (sequence, MIDIGetDestination(0))), fail, "MusicSequenceSetMIDIEndpoint"); } else { if (shouldSetBank) { CFURLRef soundBankURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8*)bankPath, strlen(bankPath), false); printf ("Setting Sound Bank:%s\n", bankPath); result = AudioUnitSetProperty (theSynth, kMusicDeviceProperty_SoundBankURL, kAudioUnitScope_Global, 0, &soundBankURL, sizeof(soundBankURL)); if (soundBankURL) CFRelease(soundBankURL); FailIf (result, fail, "AudioUnitSetProperty: kMusicDeviceProperty_SoundBankURL"); } if (diskStream) { UInt32 value = diskStream; FailIf ((result = AudioUnitSetProperty (theSynth, kMusicDeviceProperty_StreamFromDisk, kAudioUnitScope_Global, 0, &value, sizeof(value))), fail, "AudioUnitSetProperty: kMusicDeviceProperty_StreamFromDisk"); } if (outputFilePath) { // need to tell synth that is going to render a file. UInt32 value = 1; FailIf ((result = AudioUnitSetProperty (theSynth, kAudioUnitProperty_OfflineRender, kAudioUnitScope_Global, 0, &value, sizeof(value))), fail, "AudioUnitSetProperty: kAudioUnitProperty_OfflineRender"); } FailIf ((result = SetUpGraph (graph, numFrames, srate, (outputFilePath != NULL))), fail, "SetUpGraph"); if (shouldPrint) { printf ("Sample Rate: %.1f \n", srate); printf ("Disk Streaming is enabled: %c\n", (diskStream ? 'T' : 'F')); } FailIf ((result = AUGraphInitialize (graph)), fail, "AUGraphInitialize"); if (shouldPrint) CAShow (graph); } MusicPlayer player; FailIf ((result = NewMusicPlayer (&player)), fail, "NewMusicPlayer"); FailIf ((result = MusicPlayerSetSequence (player, sequence)), fail, "MusicPlayerSetSequence"); // figure out sequence length UInt32 ntracks; FailIf ((MusicSequenceGetTrackCount (sequence, &ntracks)), fail, "MusicSequenceGetTrackCount"); MusicTimeStamp sequenceLength = 0; bool shouldPrintTracks = shouldPrint && !trackSet.empty(); if (shouldPrintTracks) printf ("Only playing specified tracks:\n\t"); for (UInt32 i = 0; i < ntracks; ++i) { MusicTrack track; MusicTimeStamp trackLength; UInt32 propsize = sizeof(MusicTimeStamp); FailIf ((result = MusicSequenceGetIndTrack(sequence, i, &track)), fail, "MusicSequenceGetIndTrack"); FailIf ((result = MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, &trackLength, &propsize)), fail, "MusicTrackGetProperty: kSequenceTrackProperty_TrackLength"); if (trackLength > sequenceLength) sequenceLength = trackLength; if (!trackSet.empty() && (trackSet.find(i) == trackSet.end())) { Boolean mute = true; FailIf ((result = MusicTrackSetProperty(track, kSequenceTrackProperty_MuteStatus, &mute, sizeof(mute))), fail, "MusicTrackSetProperty: kSequenceTrackProperty_MuteStatus"); } else if (shouldPrintTracks) { printf ("%d, ", int(i+1)); } } if (shouldPrintTracks) printf ("\n"); // now I'm going to add 8 beats on the end for the reverb/long releases to tail off... sequenceLength += 8; FailIf ((result = MusicPlayerSetTime (player, startTime)), fail, "MusicPlayerSetTime"); FailIf ((result = MusicPlayerPreroll (player)), fail, "MusicPlayerPreroll"); if (shouldPrint) { printf ("Ready to play: %s, %.2f beats long\n\t<Enter> to continue: ", filePath, sequenceLength); getc(stdin); } startRunningTime = CAHostTimeBase::GetTheCurrentTime(); /* if (waitAtEnd && graph) AUGraphStart(graph); */ FailIf ((result = MusicPlayerStart (player)), fail, "MusicPlayerStart"); if (outputFilePath) WriteOutputFile (outputFilePath, dataFormat, srate, sequenceLength, shouldPrint, graph, numFrames, player); else PlayLoop (player, graph, sequenceLength, shouldPrint, waitAtEnd); FailIf ((result = MusicPlayerStop (player)), fail, "MusicPlayerStop"); if (shouldPrint) printf ("finished playing\n"); /* if (waitAtEnd) { CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, false); if (graph) AUGraphStop(graph); if (shouldPrint) printf ("disposing\n"); } */ // this shows you how you should dispose of everything FailIf ((result = DisposeMusicPlayer (player)), fail, "DisposeMusicPlayer"); FailIf ((result = DisposeMusicSequence(sequence)), fail, "DisposeMusicSequence"); // don't own the graph so don't dispose it (the seq owns it as we never set it ourselves, we just got it....) } else { FailIf ((result = DisposeMusicSequence(sequence)), fail, "DisposeMusicSequence"); } while (waitAtEnd) CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25, false); return 0; fail: if (shouldPrint) printf ("Error = %ld\n", (long)result); return result; }
int main (int argc, const char * argv[]) { if (argc == 1) { fprintf (stderr, "%s\n", usageStr); exit(0); } char* filePath = 0; bool shouldPlay = false; bool shouldSetBank = false; bool shouldUseMIDIEndpoint = false; bool shouldPrint = true; bool waitAtEnd = false; bool diskStream = false; OSType dataFormat = 0; Float64 srate = 0; const char* outputFilePath = 0; MusicSequenceLoadFlags loadFlags = 0; char* bankPath = 0; Float32 startTime = 0; UInt32 numFrames = 512; for (int i = 1; i < argc; ++i) { if (!strcmp ("-p", argv[i])) { shouldPlay = true; } else if (!strcmp ("-w", argv[i])) { waitAtEnd = true; } else if (!strcmp ("-d", argv[i])) { diskStream = true; } else if (!strcmp ("-b", argv[i])) { shouldSetBank = true; if (++i == argc) goto malformedInput; bankPath = const_cast<char*>(argv[i]); } else if (!strcmp ("-n", argv[i])) { shouldPrint = false; } else if ((filePath == 0) && (argv[i][0] == '/' || argv[i][0] == '~')) { filePath = const_cast<char*>(argv[i]); } else if (!strcmp ("-t", argv[i])) { if (++i == argc) goto malformedInput; sscanf (argv[i], "%f", &startTime); } else if (!strcmp("-e", argv[i])) { shouldUseMIDIEndpoint = true; } else if (!strcmp("-c", argv[i])) { loadFlags = kMusicSequenceLoadSMF_ChannelsToTracks; } else if (!strcmp ("-i", argv[i])) { if (++i == argc) goto malformedInput; sscanf (argv[i], "%ld", &numFrames); } else if (!strcmp ("-f", argv[i])) { if (i + 3 >= argc) goto malformedInput; outputFilePath = argv[++i]; str2OSType (argv[++i], dataFormat); sscanf (argv[++i], "%lf", &srate); } else { malformedInput: fprintf (stderr, "%s\n", usageStr); exit (1); } } if (filePath == 0) { fprintf (stderr, "You have to specify a MIDI file to print or play\n"); fprintf (stderr, "%s\n", usageStr); exit (1); } if (shouldUseMIDIEndpoint && outputFilePath) { printf ("can't write a file when you try to play out to a MIDI Endpoint\n"); exit (1); } MusicSequence sequence; OSStatus result; require_noerr (result = LoadSMF (filePath, sequence, loadFlags), fail); if (shouldPrint) CAShow (sequence); if (shouldPlay) { AUGraph graph = 0; AudioUnit theSynth = 0; require_noerr (result = MusicSequenceGetAUGraph (sequence, &graph), fail); require_noerr (result = AUGraphOpen (graph), fail); require_noerr (result = GetSynthFromGraph (graph, theSynth), fail); require_noerr (result = AudioUnitSetProperty (theSynth, kAudioUnitProperty_CPULoad, kAudioUnitScope_Global, 0, &maxCPULoad, sizeof(maxCPULoad)), fail); if (shouldUseMIDIEndpoint) { MIDIClientRef theMidiClient; MIDIClientCreate(CFSTR("Play Sequence"), NULL, NULL, &theMidiClient); ItemCount destCount = MIDIGetNumberOfDestinations(); if (destCount == 0) { fprintf (stderr, "No MIDI Endpoints to play to.\n"); exit(1); } require_noerr (result = MusicSequenceSetMIDIEndpoint (sequence, MIDIGetDestination(0)), fail); } else { if (shouldSetBank) { FSRef soundBankRef; require_noerr (result = FSPathMakeRef ((const UInt8*)bankPath, &soundBankRef, 0), fail); printf ("Setting Sound Bank:%s\n", bankPath); require_noerr (result = AudioUnitSetProperty (theSynth, kMusicDeviceProperty_SoundBankFSRef, kAudioUnitScope_Global, 0, &soundBankRef, sizeof(soundBankRef)), fail); } if (diskStream) { UInt32 value = diskStream; require_noerr (result = AudioUnitSetProperty (theSynth, kMusicDeviceProperty_StreamFromDisk, kAudioUnitScope_Global, 0, &value, sizeof(value)), fail); } if (outputFilePath) { // need to tell synth that is going to render a file. UInt32 value = 1; require_noerr (result = AudioUnitSetProperty (theSynth, kAudioUnitProperty_OfflineRender, kAudioUnitScope_Global, 0, &value, sizeof(value)), fail); } require_noerr (result = SetUpGraph (graph, numFrames, srate, (outputFilePath != NULL)), fail); if (shouldPrint) { printf ("Sample Rate: %.1f \n", srate); printf ("Disk Streaming is enabled: %c\n", (diskStream ? 'T' : 'F')); } require_noerr (result = AUGraphInitialize (graph), fail); if (shouldPrint) CAShow (graph); } MusicPlayer player; require_noerr (result = NewMusicPlayer (&player), fail); require_noerr (result = MusicPlayerSetSequence (player, sequence), fail); // figure out sequence length UInt32 ntracks; require_noerr(MusicSequenceGetTrackCount (sequence, &ntracks), fail); MusicTimeStamp sequenceLength = 0; for (UInt32 i = 0; i < ntracks; ++i) { MusicTrack track; MusicTimeStamp trackLength; UInt32 propsize = sizeof(MusicTimeStamp); require_noerr (result = MusicSequenceGetIndTrack(sequence, i, &track), fail); require_noerr (result = MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, &trackLength, &propsize), fail); if (trackLength > sequenceLength) sequenceLength = trackLength; } // now I'm going to add 8 beats on the end for the reverb/long releases to tail off... sequenceLength += 8; require_noerr (result = MusicPlayerSetTime (player, startTime), fail); require_noerr (result = MusicPlayerPreroll (player), fail); if (shouldPrint) { printf ("Ready to play: %s, %.2f beats long\n\t<Enter> to continue: ", filePath, sequenceLength); getc(stdin); } startRunningTime = AudioGetCurrentHostTime (); require_noerr (result = MusicPlayerStart (player), fail); if (outputFilePath) WriteOutputFile (outputFilePath, dataFormat, srate, sequenceLength, shouldPrint, graph, numFrames, player); else PlayLoop (player, graph, sequenceLength, shouldPrint, waitAtEnd); require_noerr (result = MusicPlayerStop (player), fail); if (shouldPrint) printf ("finished playing\n"); // this shows you how you should dispose of everything require_noerr (result = DisposeMusicPlayer (player), fail); require_noerr (result = DisposeMusicSequence(sequence), fail); // don't own the graph so don't dispose it (the seq owns it as we never set it ourselves, we just got it....) } else { require_noerr (result = DisposeMusicSequence(sequence), fail); } while (waitAtEnd) CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25, false); return 0; fail: if (shouldPrint) printf ("Error = %ld\n", result); return result; }