void CAAudioFileConverter::PrintFormats(const CAAudioChannelLayout *origSrcFileLayout) { const CAAudioChannelLayout &srcFileLayout = mSrcFile.GetFileChannelLayout(); const CAAudioChannelLayout &destFileLayout = mDestFile.GetFileChannelLayout(); // see where we've gotten if (mParams.flags & kOpt_Verbose) { printf("Formats:\n"); mSrcFile.GetFileDataFormat().PrintFormat(stdout, " ", "Input file "); if (srcFileLayout.IsValid()) { printf(" %s", CAChannelLayouts::ConstantToString(srcFileLayout.Tag())); if (srcFileLayout.IsValid() && origSrcFileLayout != NULL && srcFileLayout != *origSrcFileLayout) printf(" -- overriding layout %s in file", CAChannelLayouts::ConstantToString(origSrcFileLayout->Tag())); printf("\n"); } mDestFile.GetFileDataFormat().PrintFormat(stdout, " ", "Output file "); if (destFileLayout.IsValid()) printf(" %s\n", CAChannelLayouts::ConstantToString(destFileLayout.Tag())); if (mSrcFile.HasConverter()) { mSrcFile.GetClientDataFormat().PrintFormat(stdout, " ", "Input client "); CAShow(mSrcFile.GetConverter()); } if (mDestFile.HasConverter()) { mDestFile.GetClientDataFormat().PrintFormat(stdout, " ", "Output client"); CAShow(mDestFile.GetConverter()); } } }
static void ca_start_w(CAData *d){ OSStatus err= noErr; if (d->write_started==FALSE){ AudioStreamBasicDescription inASBD; int i; i = ca_open_w(d); if (i<0) return; inASBD = d->caOutASBD; inASBD.mSampleRate = d->rate; inASBD.mFormatID = kAudioFormatLinearPCM; inASBD.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; if (htonl(0x1234) == 0x1234) inASBD.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; inASBD.mChannelsPerFrame = d->stereo ? 2 : 1; inASBD.mBytesPerPacket = (d->bits / 8) * inASBD.mChannelsPerFrame; inASBD.mBytesPerFrame = (d->bits / 8) * inASBD.mChannelsPerFrame; inASBD.mFramesPerPacket = 1; inASBD.mBitsPerChannel = d->bits; err = AudioConverterNew( &inASBD, &d->caOutASBD, &d->caOutConverter); if(err != noErr) ms_error("AudioConverterNew %x %d", err, inASBD.mBytesPerFrame); else CAShow(d->caOutConverter); if (inASBD.mChannelsPerFrame == 1 && d->caOutASBD.mChannelsPerFrame == 2) { if (d->caOutConverter) { // This should be as large as the number of output channels, // each element specifies which input channel's data is routed to that output channel SInt32 channelMap[] = { 0, 0 }; err = AudioConverterSetProperty(d->caOutConverter, kAudioConverterChannelMap, 2*sizeof(SInt32), channelMap); } } memset((char*)&d->caOutRenderCallback, 0, sizeof(AURenderCallbackStruct)); d->caOutRenderCallback.inputProc = writeRenderProc; d->caOutRenderCallback.inputProcRefCon = d; err = AudioUnitSetProperty (d->caOutAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &d->caOutRenderCallback, sizeof(AURenderCallbackStruct)); if(err != noErr) ms_error("AudioUnitSetProperty %x", err); if(err == noErr) { if(AudioOutputUnitStart(d->caOutAudioUnit) == noErr) d->write_started=TRUE; } } }
bool FIOSAudioDevice::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) { if (FParse::Command(&Cmd, TEXT("DumpAUGraph")) && AudioUnitGraph) { CAShow(AudioUnitGraph); return true; } return FAudioDevice::Exec(InWorld, Cmd, Ar); }
static void ca_start_r(CAData *d){ OSStatus err= noErr; if (d->read_started==FALSE){ AudioStreamBasicDescription outASBD; int i; i = ca_open_r(d); if (i<0) return; outASBD = d->caInASBD; outASBD.mSampleRate = d->rate; outASBD.mFormatID = kAudioFormatLinearPCM; outASBD.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; if (htonl(0x1234) == 0x1234) outASBD.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; outASBD.mChannelsPerFrame = d->stereo ? 2 : 1; outASBD.mBytesPerPacket = (d->bits / 8) * outASBD.mChannelsPerFrame; outASBD.mBytesPerFrame = (d->bits / 8) * outASBD.mChannelsPerFrame; outASBD.mFramesPerPacket = 1; outASBD.mBitsPerChannel = d->bits; err = AudioConverterNew( &d->caInASBD, &outASBD, &d->caInConverter); if(err != noErr) ms_error("AudioConverterNew %x %d", err, outASBD.mBytesPerFrame); else CAShow(d->caInConverter); d->caInRenderCallback.inputProc = readRenderProc; d->caInRenderCallback.inputProcRefCon = d; err = AudioUnitSetProperty(d->caInAudioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &d->caInRenderCallback, sizeof(AURenderCallbackStruct)); if(AudioOutputUnitStart(d->caInAudioUnit) == noErr) d->read_started = TRUE; } }
int main(int argc, char *argv[]) { AUGraph audioGraph; NewAUGraph(&audioGraph); AudioComponentDescription cd; AUNode outputNode; AudioUnit outputUnit; cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; cd.componentType = kAudioUnitType_Output; cd.componentSubType = kAudioUnitSubType_DefaultOutput; AUGraphAddNode(audioGraph, &cd, &outputNode); AUGraphNodeInfo(audioGraph, outputNode, &cd, &outputUnit); AUNode mixerNode; AudioUnit mixerUnit; cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; cd.componentType = kAudioUnitType_Mixer; cd.componentSubType = kAudioUnitSubType_StereoMixer; AUGraphAddNode(audioGraph, &cd, &mixerNode); AUGraphNodeInfo(audioGraph, mixerNode, &cd, &mixerUnit); AUGraphConnectNodeInput(audioGraph, mixerNode, 0, outputNode, 0); AUGraphOpen(audioGraph); AUGraphInitialize(audioGraph); AUGraphStart(audioGraph); AUNode synthNode; AudioUnit synthUnit; cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; cd.componentType = kAudioUnitType_MusicDevice; cd.componentSubType = kAudioUnitSubType_DLSSynth; AUGraphAddNode(audioGraph, &cd, &synthNode); AUGraphNodeInfo(audioGraph, synthNode, &cd, &synthUnit); AUGraphConnectNodeInput(audioGraph, synthNode, 0, mixerNode, 0); AUGraphUpdate(audioGraph, NULL); CAShow(audioGraph); MusicDeviceMIDIEvent(synthUnit, 0x90, 60, 127, 0); sleep(1); MusicDeviceMIDIEvent(synthUnit, 0x90, 62, 127, 0); sleep(1); MusicDeviceMIDIEvent(synthUnit, 0x90, 64, 127, 0); sleep(1); sleep(5); return(0); }
void CCoreAudioGraph::ShowGraph() { CAShow(m_audioGraph); }
int main (int argc, const char * argv[]) { AUGraph graph = 0; AudioUnit synthUnit; OSStatus result; char* bankPath = 0; UInt8 midiChannelInUse = 0; //we're using midi channel 1... // this is the only option to main that we have... // just the full path of the sample bank... // On OS X there are known places were sample banks can be stored // Library/Audio/Sounds/Banks - so you could scan this directory and give the user options // about which sample bank to use... if (argc > 1) bankPath = const_cast<char*>(argv[1]); require_noerr (result = CreateAUGraph (graph, synthUnit), home); // if the user supplies a sound bank, we'll set that before we initialize and start playing if (bankPath) { FSSpec soundBankSpec; require_noerr (result = PathToFSSpec (bankPath, soundBankSpec), home); printf ("Setting Sound Bank:%s\n", bankPath); require_noerr (result = AudioUnitSetProperty (synthUnit, kMusicDeviceProperty_SoundBankFSSpec, kAudioUnitScope_Global, 0, &soundBankSpec, sizeof(soundBankSpec)), home); } // ok we're set up to go - initialize and start the graph require_noerr (result = AUGraphInitialize (graph), home); //set our bank require_noerr (result = MusicDeviceMIDIEvent(synthUnit, kMidiMessage_ControlChange << 4 | midiChannelInUse, kMidiMessage_BankMSBControl, 0, 0/*sample offset*/), home); require_noerr (result = MusicDeviceMIDIEvent(synthUnit, kMidiMessage_ProgramChange << 4 | midiChannelInUse, 0/*prog change num*/, 0, 0/*sample offset*/), home); CAShow (graph); // prints out the graph so we can see what it looks like... require_noerr (result = AUGraphStart (graph), home); // we're going to play an octave of MIDI notes: one a second for (int i = 0; i < 13; i++) { UInt32 noteNum = i + 60; UInt32 onVelocity = 127; UInt32 noteOnCommand = kMidiMessage_NoteOn << 4 | midiChannelInUse; printf ("Playing Note: Status: 0x%lX, Note: %ld, Vel: %ld\n", noteOnCommand, noteNum, onVelocity); require_noerr (result = MusicDeviceMIDIEvent(synthUnit, noteOnCommand, noteNum, onVelocity, 0), home); // sleep for a second usleep (1 * 1000 * 1000); require_noerr (result = MusicDeviceMIDIEvent(synthUnit, noteOnCommand, noteNum, 0, 0), home); } // ok we're done now home: if (graph) { AUGraphStop (graph); // stop playback - AUGraphDispose will do that for us but just showing you what to do DisposeAUGraph (graph); } return result; }
void start(int midiChannel, char const*const bankPath) { if (auGraph != 0) return; // don't multiply init midiChannelInUse = midiChannel; OSStatus result; //create the nodes of the graph AUNode synthNode; AudioComponentDescription cd; cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; require_noerr (result = NewAUGraph (&auGraph), home); cd.componentType = kAudioUnitType_MusicDevice; cd.componentSubType = kAudioUnitSubType_DLSSynth; require_noerr (result = AUGraphAddNode (auGraph, &cd, &synthNode), home); cd.componentType = kAudioUnitType_Effect; cd.componentSubType = kAudioUnitSubType_PeakLimiter; require_noerr (result = AUGraphAddNode (auGraph, &cd, &limiterNode), home); cd.componentType = kAudioUnitType_Output; cd.componentSubType = kAudioUnitSubType_DefaultOutput; require_noerr (result = AUGraphAddNode (auGraph, &cd, &outNode), home); require_noerr (result = AUGraphOpen (auGraph), home); require_noerr (result = AUGraphConnectNodeInput(auGraph, synthNode, 0, limiterNode, 0), home); require_noerr (result = AUGraphConnectNodeInput(auGraph, limiterNode, 0, outNode, 0), home); // ok we're good to go - get the Synth Unit... require_noerr (result = AUGraphNodeInfo(auGraph, synthNode, 0, &synthUnit), home); // if the user supplies a sound bank, we'll set that before we initialize and start playing if (bankPath) { // note: bankpath is a soundfont CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)bankPath, strlen(bankPath), false); if (url) { require_noerr (result = AudioUnitSetProperty(synthUnit, kMusicDeviceProperty_SoundBankURL, kAudioUnitScope_Global, 0, &url, sizeof(url) ), home); CFRelease(url); } } // ok we're set up to go - initialize and start the graph require_noerr (result = AUGraphInitialize (auGraph), home); //set our bank require_noerr (result = MusicDeviceMIDIEvent(synthUnit, kMidiMessage_ControlChange << 4 | midiChannelInUse, kMidiMessage_BankMSBControl, 0, 0/*sample offset*/), home); require_noerr (result = MusicDeviceMIDIEvent(synthUnit, kMidiMessage_ProgramChange << 4 | midiChannelInUse, 0/*prog change num*/, 0, 0/*sample offset*/), home); CAShow(auGraph); // prints out the graph so we can see what it looks like... require_noerr (result = AUGraphStart(auGraph), home); return; home: shutdown(); }
// _______________________________________________________________________________________ // void CAAudioFile::SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout) { LOG_FUNCTION("CAAudioFile::SetClientFormat", "%p", this); XThrowIf(!dataFormat.IsPCM(), kExtAudioFileError_NonPCMClientFormat, "non-PCM client format on audio file"); bool dataFormatChanging = (mClientDataFormat.mFormatID == 0 || mClientDataFormat != dataFormat); if (dataFormatChanging) { CloseConverter(); if (mWriteBufferList) { delete mWriteBufferList; mWriteBufferList = NULL; } mClientDataFormat = dataFormat; } if (layout && layout->IsValid()) { XThrowIf(layout->NumberChannels() != mClientDataFormat.NumberChannels(), kExtAudioFileError_InvalidChannelMap, "inappropriate channel map"); mClientChannelLayout = *layout; } bool differentLayouts; if (mClientChannelLayout.IsValid()) { if (mFileChannelLayout.IsValid()) { differentLayouts = mClientChannelLayout.Tag() != mFileChannelLayout.Tag(); #if VERBOSE_CHANNELMAP printf("two valid layouts, %s\n", differentLayouts ? "different" : "same"); #endif } else { differentLayouts = false; #if VERBOSE_CHANNELMAP printf("valid client layout, unknown file layout\n"); #endif } } else { differentLayouts = false; #if VERBOSE_CHANNELMAP if (mFileChannelLayout.IsValid()) printf("valid file layout, unknown client layout\n"); else printf("two invalid layouts\n"); #endif } if (mClientDataFormat != mFileDataFormat || differentLayouts) { // We need an AudioConverter. if (mMode == kReading) { // file -> client (decode) //mFileDataFormat.PrintFormat( stdout, "", "File: "); //mClientDataFormat.PrintFormat(stdout, "", "Client: "); if (mConverter == NULL) XThrowIfError(AudioConverterNew(&mFileDataFormat, &mClientDataFormat, &mConverter), "create audio converter"); #if VERBOSE_CONVERTER printf("CAAudioFile %p -- created converter\n", this); CAShow(mConverter); #endif // set the magic cookie, if any (for decode) if (mMagicCookie) SetConverterProperty(kAudioConverterDecompressionMagicCookie, mMagicCookieSize, mMagicCookie, mFileDataFormat.IsPCM()); // we get cookies from some AIFF's but the converter barfs on them, // so we set canFail to true for PCM SetConverterChannelLayout(false, mFileChannelLayout); SetConverterChannelLayout(true, mClientChannelLayout); // propagate leading/trailing frame counts if (mFileDataFormat.mBitsPerChannel == 0) { UInt32 propertySize; OSStatus err; AudioFilePacketTableInfo pti; propertySize = sizeof(pti); err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, &propertySize, &pti); if (err == noErr && (pti.mPrimingFrames > 0 || pti.mRemainderFrames > 0)) { AudioConverterPrimeInfo primeInfo; primeInfo.leadingFrames = pti.mPrimingFrames; primeInfo.trailingFrames = pti.mRemainderFrames; /* ignore any error. better to play it at all than not. */ /*err = */AudioConverterSetProperty(mConverter, kAudioConverterPrimeInfo, sizeof(primeInfo), &primeInfo); //XThrowIfError(err, "couldn't set prime info on converter"); } } } else if (mMode == kPreparingToCreate || mMode == kPreparingToWrite) { // client -> file (encode) if (mConverter == NULL) XThrowIfError(AudioConverterNew(&mClientDataFormat, &mFileDataFormat, &mConverter), "create audio converter"); mWriteBufferList = CABufferList::New("", mClientDataFormat); SetConverterChannelLayout(false, mClientChannelLayout); SetConverterChannelLayout(true, mFileChannelLayout); if (mMode == kPreparingToWrite) FileFormatChanged(); } else XThrowIfError(kExtAudioFileError_InvalidOperationOrder, "audio file format not yet known"); } UpdateClientMaxPacketSize(); }
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; }
void CreateMyAUGraph(MyAUGraphPlayer *player) { // create a new AUGraph CheckError(NewAUGraph(&player->graph), "NewAUGraph failed"); // generate description that will match our output device (speakers) AudioComponentDescription outputcd = {0}; outputcd.componentType = kAudioUnitType_Output; outputcd.componentSubType = kAudioUnitSubType_DefaultOutput; outputcd.componentManufacturer = kAudioUnitManufacturer_Apple; // adds a node with above description to the graph AUNode outputNode; CheckError(AUGraphAddNode(player->graph, &outputcd, &outputNode), "AUGraphAddNode[kAudioUnitSubType_DefaultOutput] failed"); // generate description that will match a generator AU of type: speech synthesizer AudioComponentDescription speechcd = {0}; speechcd.componentType = kAudioUnitType_Generator; speechcd.componentSubType = kAudioUnitSubType_SpeechSynthesis; speechcd.componentManufacturer = kAudioUnitManufacturer_Apple; // adds a node with above description to the graph AUNode speechNode; CheckError(AUGraphAddNode(player->graph, &speechcd, &speechNode), "AUGraphAddNode[kAudioUnitSubType_SpeechSynthesis] failed"); // opening the graph opens all contained audio units but does not allocate any resources yet CheckError(AUGraphOpen(player->graph), "AUGraphOpen failed"); // get the reference to the AudioUnit object for the speech synthesis graph node CheckError(AUGraphNodeInfo(player->graph, speechNode, NULL, &player->speechAU), "AUGraphNodeInfo failed"); // // debug - get the asbd // UInt32 propSize = sizeof (AudioStreamBasicDescription); // CheckError(AudioUnitGetProperty(player->speechAU, // kAudioUnitProperty_StreamFormat, // kAudioUnitScope_Output, // 0, // &player->streamFormat, // &propSize), // "Couldn't get ASBD"); #ifdef PART_II // // FUN! re-route the speech thru a reverb effect before sending to speakers // // generate description that will match out reverb effect AudioComponentDescription reverbcd = {0}; reverbcd.componentType = kAudioUnitType_Effect; reverbcd.componentSubType = kAudioUnitSubType_MatrixReverb; reverbcd.componentManufacturer = kAudioUnitManufacturer_Apple; // adds a node with above description to the graph AUNode reverbNode; CheckError(AUGraphAddNode(player->graph, &reverbcd, &reverbNode), "AUGraphAddNode[kAudioUnitSubType_MatrixReverb] failed"); // connect the output source of the speech synthesizer AU to the input source of the reverb node CheckError(AUGraphConnectNodeInput(player->graph, speechNode, 0, reverbNode, 0), "AUGraphConnectNodeInput"); // connect the output source of the reverb AU to the input source of the output node CheckError(AUGraphConnectNodeInput(player->graph, reverbNode, 0, outputNode, 0), "AUGraphConnectNodeInput"); // get the reference to the AudioUnit object for the reverb graph node AudioUnit reverbUnit; CheckError(AUGraphNodeInfo(player->graph, reverbNode, NULL, &reverbUnit), "AUGraphNodeInfo failed"); /* enum { kReverbRoomType_SmallRoom = 0, kReverbRoomType_MediumRoom = 1, kReverbRoomType_LargeRoom = 2, kReverbRoomType_MediumHall = 3, kReverbRoomType_LargeHall = 4, kReverbRoomType_Plate = 5, kReverbRoomType_MediumChamber = 6, kReverbRoomType_LargeChamber = 7, kReverbRoomType_Cathedral = 8, kReverbRoomType_LargeRoom2 = 9, kReverbRoomType_MediumHall2 = 10, kReverbRoomType_MediumHall3 = 11, kReverbRoomType_LargeHall2 = 12 }; */ // now initialize the graph (causes resources to be allocated) CheckError(AUGraphInitialize(player->graph), "AUGraphInitialize failed"); // set the reverb preset for room size // UInt32 roomType = kReverbRoomType_SmallRoom; // UInt32 roomType = kReverbRoomType_MediumRoom; UInt32 roomType = kReverbRoomType_LargeHall; // UInt32 roomType = kReverbRoomType_Cathedral; CheckError(AudioUnitSetProperty(reverbUnit, kAudioUnitProperty_ReverbRoomType, kAudioUnitScope_Global, 0, &roomType, sizeof(UInt32)), "AudioUnitSetProperty[kAudioUnitProperty_ReverbRoomType] failed"); #else // connect the output source of the speech synthesis AU to the input source of the output node CheckError(AUGraphConnectNodeInput(player->graph, speechNode, 0, outputNode, 0), "AUGraphConnectNodeInput"); // now initialize the graph (causes resources to be allocated) CheckError(AUGraphInitialize(player->graph), "AUGraphInitialize failed"); #endif CAShow(player->graph); }