OSStatus CAPlayThrough::MakeGraph() { OSStatus err = noErr; AudioComponentDescription varispeedDesc,outDesc, mixerDesc; //Q:Why do we need a varispeed unit? //A:If the input device and the output device are running at different sample rates //we will need to move the data coming to the graph slower/faster to avoid a pitch change. varispeedDesc.componentType = kAudioUnitType_FormatConverter; varispeedDesc.componentSubType = kAudioUnitSubType_Varispeed; varispeedDesc.componentManufacturer = kAudioUnitManufacturer_Apple; varispeedDesc.componentFlags = 0; varispeedDesc.componentFlagsMask = 0; outDesc.componentType = kAudioUnitType_Output; outDesc.componentSubType = kAudioUnitSubType_DefaultOutput; outDesc.componentManufacturer = kAudioUnitManufacturer_Apple; outDesc.componentFlags = 0; outDesc.componentFlagsMask = 0; mixerDesc.componentType = kAudioUnitType_Mixer; mixerDesc.componentSubType = kAudioUnitSubType_StereoMixer; mixerDesc.componentManufacturer = kAudioUnitManufacturer_Apple; mixerDesc.componentFlags = 0; mixerDesc.componentFlagsMask = 0; ////////////////////////// ///MAKE NODES //This creates a node in the graph that is an AudioUnit, using //the supplied ComponentDescription to find and open that unit err = AUGraphAddNode(mGraph, &varispeedDesc, &mVarispeedNode); checkErr(err); //add a mixer node after the input to use for metering err = AUGraphAddNode(mGraph, &mixerDesc, &mMixerNode); checkErr(err); err = AUGraphAddNode(mGraph, &outDesc, &mOutputNode); checkErr(err); //Get Audio Units from AUGraph node err = AUGraphNodeInfo(mGraph, mVarispeedNode, NULL, &mVarispeedUnit); checkErr(err); //get the mixer node err = AUGraphNodeInfo(mGraph, mMixerNode, NULL, &mMixerUnit); checkErr(err); err = AUGraphNodeInfo(mGraph, mOutputNode, NULL, &mOutputUnit); checkErr(err); // don't connect nodes until the varispeed unit has input and output formats set return err; }
/* we're looking for the sequence output audiounit. */ static OSStatus GetSequenceAudioUnit(MusicSequence sequence, AudioUnit *aunit) { AUGraph graph; UInt32 nodecount, i; OSStatus err; err = MusicSequenceGetAUGraph(sequence, &graph); if (err != noErr) return err; err = AUGraphGetNodeCount(graph, &nodecount); if (err != noErr) return err; for (i = 0; i < nodecount; i++) { AUNode node; if (AUGraphGetIndNode(graph, i, &node) != noErr) continue; /* better luck next time. */ #if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 /* this is deprecated, but works back to 10.0 */ { struct ComponentDescription desc; UInt32 classdatasize = 0; void *classdata = NULL; err = AUGraphGetNodeInfo(graph, node, &desc, &classdatasize, &classdata, aunit); if (err != noErr) continue; else if (desc.componentType != kAudioUnitType_Output) continue; else if (desc.componentSubType != kAudioUnitSubType_DefaultOutput) continue; } #else /* not deprecated, but requires 10.5 or later */ { # if !defined(AUDIO_UNIT_VERSION) || ((AUDIO_UNIT_VERSION + 0) < 1060) /* AUGraphAddNode () is changed to take an AudioComponentDescription* * desc parameter instead of a ComponentDescription* in the 10.6 SDK. * AudioComponentDescription is in 10.6 or newer, but it is actually * the same as struct ComponentDescription with 20 bytes of size and * the same offsets of all members, therefore, is binary compatible. */ # define AudioComponentDescription ComponentDescription # endif AudioComponentDescription desc; if (AUGraphNodeInfo(graph, node, &desc, aunit) != noErr) continue; else if (desc.componentType != kAudioUnitType_Output) continue; else if (desc.componentSubType != kAudioUnitSubType_DefaultOutput) continue; } #endif return noErr; /* found it! */ } return kAUGraphErr_NodeNotFound; }
OSStatus FCoreAudioSoundSource::CreateAudioUnit( OSType Type, OSType SubType, OSType Manufacturer, AudioStreamBasicDescription* InputFormat, AudioStreamBasicDescription* OutputFormat, AUNode* OutNode, AudioUnit* OutUnit ) { AudioComponentDescription Desc; Desc.componentFlags = 0; Desc.componentFlagsMask = 0; Desc.componentType = Type; Desc.componentSubType = SubType; Desc.componentManufacturer = Manufacturer; OSStatus Status = AUGraphAddNode( AudioDevice->GetAudioUnitGraph(), &Desc, OutNode ); if( Status == noErr ) { Status = AUGraphNodeInfo( AudioDevice->GetAudioUnitGraph(), *OutNode, NULL, OutUnit ); } if( Status == noErr ) { if( InputFormat ) { Status = AudioUnitSetProperty( *OutUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, InputFormat, sizeof( AudioStreamBasicDescription ) ); } if( Status == noErr ) { if( OutputFormat ) { Status = AudioUnitSetProperty( *OutUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, OutputFormat, sizeof( AudioStreamBasicDescription ) ); } } } return Status; }
bool CCoreAudioUnit::Open(AUGraph audioGraph, AudioComponentDescription desc) { if (m_audioUnit) Close(); OSStatus ret; m_Initialized = false; ret = AUGraphAddNode(audioGraph, &desc, &m_audioNode); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error add m_outputNode. Error = %s", GetError(ret).c_str()); return false; } ret = AUGraphNodeInfo(audioGraph, m_audioNode, NULL, &m_audioUnit); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error getting m_outputNode. Error = %s", GetError(ret).c_str()); return false; } m_audioGraph = audioGraph; m_Initialized = true; Start(); return true; }
OSStatus get_next_node_info() { return AUGraphNodeInfo( m_graph, m_node_details[m_node_count].m_node, NULL, &m_node_details[m_node_count].m_unit); }
/** Set the volume of the current sequence. */ static void DoSetVolume() { if (_sequence == NULL) return; AUGraph graph; MusicSequenceGetAUGraph(_sequence, &graph); AudioUnit output_unit = NULL; /* Get output audio unit */ UInt32 node_count = 0; AUGraphGetNodeCount(graph, &node_count); for (UInt32 i = 0; i < node_count; i++) { AUNode node; AUGraphGetIndNode(graph, i, &node); AudioUnit unit; OSType comp_type = 0; #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) if (MacOSVersionIsAtLeast(10, 5, 0)) { /* The 10.6 SDK has changed the function prototype of * AUGraphNodeInfo. This is a binary compatible change, * but we need to get the type declaration right or * risk compilation errors. The header AudioComponent.h * was introduced in 10.6 so use it to decide which * type definition to use. */ #ifdef __AUDIOCOMPONENT_H__ AudioComponentDescription desc; #else ComponentDescription desc; #endif AUGraphNodeInfo(graph, node, &desc, &unit); comp_type = desc.componentType; } else #endif { #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) ComponentDescription desc; AUGraphGetNodeInfo(graph, node, &desc, NULL, NULL, &unit); comp_type = desc.componentType; #endif } if (comp_type == kAudioUnitType_Output) { output_unit = unit; break; } } if (output_unit == NULL) { DEBUG(driver, 1, "cocoa_m: Failed to get output node to set volume"); return; } Float32 vol = _volume / 127.0f; // 0 - +127 -> 0.0 - 1.0 AudioUnitSetParameter(output_unit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, vol, 0); }
AudioUnitNode::AudioUnitNode(AUGraph graph, const AudioComponentDescription& cd) : mGraph(graph) { OSStatus err; err = AUGraphAddNode(graph, &cd, &mNode); if ((int)err == -2005) { AudioNodeException exception("badComponentType."); throw exception; } err = AUGraphNodeInfo(graph, mNode, NULL, &mUnit); }
/* we're looking for the sequence output audiounit. */ static OSStatus GetSequenceAudioUnit(MusicSequence sequence, AudioUnit *aunit) { AUGraph graph; UInt32 nodecount, i; OSStatus err; err = MusicSequenceGetAUGraph(sequence, &graph); if (err != noErr) return err; err = AUGraphGetNodeCount(graph, &nodecount); if (err != noErr) return err; for (i = 0; i < nodecount; i++) { AUNode node; if (AUGraphGetIndNode(graph, i, &node) != noErr) continue; /* better luck next time. */ #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 /* this is deprecated, but works back to 10.0 */ { struct ComponentDescription desc; UInt32 classdatasize = 0; void *classdata = NULL; err = AUGraphGetNodeInfo(graph, node, &desc, &classdatasize, &classdata, aunit); if (err != noErr) continue; else if (desc.componentType != kAudioUnitType_Output) continue; else if (desc.componentSubType != kAudioUnitSubType_DefaultOutput) continue; } #else /* not deprecated, but requires 10.5 or later */ { AudioComponentDescription desc; if (AUGraphNodeInfo(graph, node, &desc, aunit) != noErr) continue; else if (desc.componentType != kAudioUnitType_Output) continue; else if (desc.componentSubType != kAudioUnitSubType_DefaultOutput) continue; } #endif return noErr; /* found it! */ } return kAUGraphErr_NodeNotFound; }
OSStatus GetSynthFromGraph (AUGraph& inGraph, AudioUnit& outSynth) { UInt32 nodeCount; OSStatus result = noErr; FailIf ((result = AUGraphGetNodeCount (inGraph, &nodeCount)), fail, "AUGraphGetNodeCount"); for (UInt32 i = 0; i < nodeCount; ++i) { AUNode node; FailIf ((result = AUGraphGetIndNode(inGraph, i, &node)), fail, "AUGraphGetIndNode"); AudioComponentDescription desc; FailIf ((result = AUGraphNodeInfo(inGraph, node, &desc, 0)), fail, "AUGraphNodeInfo"); if (desc.componentType == kAudioUnitType_MusicDevice) { FailIf ((result = AUGraphNodeInfo(inGraph, node, 0, &outSynth)), fail, "AUGraphNodeInfo"); return noErr; } } fail: // didn't find the synth AU return -1; }
OSStatus SetUpGraph (AUGraph &inGraph, UInt32 numFrames, Float64 &sampleRate, bool isOffline) { OSStatus result = noErr; AudioUnit outputUnit = 0; AUNode outputNode; // the frame size is the I/O size to the device // the device is going to run at a sample rate it is set at // so, when we set this, we also have to set the max frames for the graph nodes UInt32 nodeCount; FailIf ((result = AUGraphGetNodeCount (inGraph, &nodeCount)), home, "AUGraphGetNodeCount"); for (int i = 0; i < (int)nodeCount; ++i) { AUNode node; FailIf ((result = AUGraphGetIndNode(inGraph, i, &node)), home, "AUGraphGetIndNode"); AudioComponentDescription desc; AudioUnit unit; FailIf ((result = AUGraphNodeInfo(inGraph, node, &desc, &unit)), home, "AUGraphNodeInfo"); if (desc.componentType == kAudioUnitType_Output) { if (outputUnit == 0) { outputUnit = unit; FailIf ((result = AUGraphNodeInfo(inGraph, node, 0, &outputUnit)), home, "AUGraphNodeInfo"); if (!isOffline) { // these two properties are only applicable if its a device we're playing too FailIf ((result = AudioUnitSetProperty (outputUnit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Output, 0, &numFrames, sizeof(numFrames))), home, "AudioUnitSetProperty: kAudioDevicePropertyBufferFrameSize"); FailIf ((result = AudioUnitAddPropertyListener (outputUnit, kAudioDeviceProcessorOverload, OverlaodListenerProc, 0)), home, "AudioUnitAddPropertyListener: kAudioDeviceProcessorOverload"); // if we're rendering to the device, then we render at its sample rate UInt32 theSize; theSize = sizeof(sampleRate); FailIf ((result = AudioUnitGetProperty (outputUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sampleRate, &theSize)), home, "AudioUnitGetProperty: kAudioUnitProperty_SampleRate"); } else { // remove device output node and add generic output FailIf ((result = AUGraphRemoveNode (inGraph, node)), home, "AUGraphRemoveNode"); desc.componentSubType = kAudioUnitSubType_GenericOutput; FailIf ((result = AUGraphAddNode (inGraph, &desc, &node)), home, "AUGraphAddNode"); FailIf ((result = AUGraphNodeInfo(inGraph, node, NULL, &unit)), home, "AUGraphNodeInfo"); outputUnit = unit; outputNode = node; // we render the output offline at the desired sample rate FailIf ((result = AudioUnitSetProperty (outputUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sampleRate, sizeof(sampleRate))), home, "AudioUnitSetProperty: kAudioUnitProperty_SampleRate"); } // ok, lets start the loop again now and do it all... i = -1; } } else { // we only have to do this on the output side // as the graph's connection mgmt will propogate this down. if (outputUnit) { // reconnect up to the output unit if we're offline if (isOffline && desc.componentType != kAudioUnitType_MusicDevice) { FailIf ((result = AUGraphConnectNodeInput (inGraph, node, 0, outputNode, 0)), home, "AUGraphConnectNodeInput"); } FailIf ((result = AudioUnitSetProperty (unit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sampleRate, sizeof(sampleRate))), home, "AudioUnitSetProperty: kAudioUnitProperty_SampleRate"); } } FailIf ((result = AudioUnitSetProperty (unit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &numFrames, sizeof(numFrames))), home, "AudioUnitSetProperty: kAudioUnitProperty_MaximumFramesPerSlice"); } home: return result; }
void MakeSimpleGraph (AUGraph &theGraph, CAAudioUnit &fileAU, CAStreamBasicDescription &fileFormat, AudioFileID audioFile) { XThrowIfError (NewAUGraph (&theGraph), "NewAUGraph"); CAComponentDescription cd; // output node cd.componentType = kAudioUnitType_Output; cd.componentSubType = kAudioUnitSubType_DefaultOutput; cd.componentManufacturer = kAudioUnitManufacturer_Apple; AUNode outputNode; XThrowIfError (AUGraphAddNode (theGraph, &cd, &outputNode), "AUGraphAddNode"); // file AU node AUNode fileNode; cd.componentType = kAudioUnitType_Generator; cd.componentSubType = kAudioUnitSubType_AudioFilePlayer; XThrowIfError (AUGraphAddNode (theGraph, &cd, &fileNode), "AUGraphAddNode"); // connect & setup XThrowIfError (AUGraphOpen (theGraph), "AUGraphOpen"); // install overload listener to detect when something is wrong AudioUnit anAU; XThrowIfError (AUGraphNodeInfo(theGraph, fileNode, NULL, &anAU), "AUGraphNodeInfo"); fileAU = CAAudioUnit (fileNode, anAU); // prepare the file AU for playback // set its output channels XThrowIfError (fileAU.SetNumberChannels (kAudioUnitScope_Output, 0, fileFormat.NumberChannels()), "SetNumberChannels"); // set the output sample rate of the file AU to be the same as the file: XThrowIfError (fileAU.SetSampleRate (kAudioUnitScope_Output, 0, fileFormat.mSampleRate), "SetSampleRate"); // load in the file XThrowIfError (fileAU.SetProperty(kAudioUnitProperty_ScheduledFileIDs, kAudioUnitScope_Global, 0, &audioFile, sizeof(audioFile)), "SetScheduleFile"); XThrowIfError (AUGraphConnectNodeInput (theGraph, fileNode, 0, outputNode, 0), "AUGraphConnectNodeInput"); // AT this point we make sure we have the file player AU initialized // this also propogates the output format of the AU to the output unit XThrowIfError (AUGraphInitialize (theGraph), "AUGraphInitialize"); // workaround a race condition in the file player AU usleep (10 * 1000); // if we have a surround file, then we should try to tell the output AU what the order of the channels will be if (fileFormat.NumberChannels() > 2) { UInt32 layoutSize = 0; OSStatus err; XThrowIfError (err = AudioFileGetPropertyInfo (audioFile, kAudioFilePropertyChannelLayout, &layoutSize, NULL), "kAudioFilePropertyChannelLayout"); if (!err && layoutSize) { char* layout = new char[layoutSize]; err = AudioFileGetProperty(audioFile, kAudioFilePropertyChannelLayout, &layoutSize, layout); XThrowIfError (err, "Get Layout From AudioFile"); // ok, now get the output AU and set its layout XThrowIfError (AUGraphNodeInfo(theGraph, outputNode, NULL, &anAU), "AUGraphNodeInfo"); err = AudioUnitSetProperty (anAU, kAudioUnitProperty_AudioChannelLayout, kAudioUnitScope_Input, 0, layout, layoutSize); XThrowIfError (err, "kAudioUnitProperty_AudioChannelLayout"); delete [] layout; } } }
void setupAUGraph(MyMIDIPlayer *player) { CheckError(NewAUGraph(&player->graph), "Couldn't open AU Graph"); // 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"); AudioComponentDescription instrumentcd = {0}; instrumentcd.componentManufacturer = kAudioUnitManufacturer_Apple; instrumentcd.componentType = kAudioUnitType_MusicDevice; instrumentcd.componentSubType = kAudioUnitSubType_Sampler; // changed! AUNode instrumentNode; CheckError(AUGraphAddNode(player->graph, &instrumentcd, &instrumentNode), "AUGraphAddNode[kAudioUnitSubType_DLSSynth] 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 instrument graph node CheckError(AUGraphNodeInfo(player->graph, instrumentNode, NULL, &player->instrumentUnit), "AUGraphNodeInfo failed"); // connect the output source of the instrument AU to the input source of the output node CheckError(AUGraphConnectNodeInput(player->graph, instrumentNode, 0, outputNode, 0), "AUGraphConnectNodeInput"); // now initialize the graph (causes resources to be allocated) CheckError(AUGraphInitialize(player->graph), "AUGraphInitialize failed"); // configure the AUSampler // 2nd parameter obviously needs to be a full path on your system, and 3rd param is its length in characters CFURLRef presetURL = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, "/Users/cadamson/Library/Audio/Presets/Apple/AUSampler/ch12-aupreset.aupreset", 77, false); // load preset file into a CFDataRef CFDataRef presetData = NULL; SInt32 errorCode = noErr; Boolean gotPresetData = CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, presetURL, &presetData, NULL, NULL, &errorCode); CheckError(errorCode, "couldn't load .aupreset data"); CheckError(!gotPresetData, "couldn't load .aupreset data"); // convert this into a property list CFPropertyListFormat presetPlistFormat = {0}; CFErrorRef presetPlistError = NULL; CFPropertyListRef presetPlist = CFPropertyListCreateWithData(kCFAllocatorSystemDefault, presetData, kCFPropertyListImmutable, &presetPlistFormat, &presetPlistError); if (presetPlistError) { printf ("Couldn't create plist object for .aupreset"); return; } // set this plist as the kAudioUnitProperty_ClassInfo on _auSampler if (presetPlist) { CheckError(AudioUnitSetProperty(player->instrumentUnit, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &presetPlist, sizeof(presetPlist)), "Couldn't set aupreset plist as sampler's class info"); } }
CoreAudioChkError(AUGraphAddNode(*theGraph, &cd, &outputNode), "AUGraphAddNode Output",); /* Initialize and add the AU node */ AUNode fileNode; cd.componentType = kAudioUnitType_Generator; cd.componentSubType = kAudioUnitSubType_AudioFilePlayer; CoreAudioChkError(AUGraphAddNode(*theGraph, &cd, &fileNode), "AUGraphAddNode AU",); /* Make connections */ CoreAudioChkError(AUGraphOpen(*theGraph), "AUGraphOpen",); /* Set Schedule properties and initialize the graph with the file */ AudioUnit anAU; memset(&anAU, 0, sizeof(anAU)); CoreAudioChkError(AUGraphNodeInfo(*theGraph, fileNode, NULL, &anAU), "AUGraphNodeInfo",); *fileAU = anAU; CoreAudioChkError(AudioUnitSetProperty(*fileAU, kAudioUnitProperty_ScheduledFileIDs, kAudioUnitScope_Global, 0, &audioFile, sizeof(audioFile)), "SetScheduleFile",); CoreAudioChkError(AUGraphConnectNodeInput(*theGraph, fileNode, 0, outputNode, 0), "AUGraphConnectNodeInput",); CoreAudioChkError(AUGraphInitialize(*theGraph), "AUGraphInitialize",); } #elif HAVE_CANBERRA #include <canberra.h> #include <canberra-gtk.h> #endif
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 WriteOutputFile (const char* outputFilePath, OSType dataFormat, Float64 srate, MusicTimeStamp sequenceLength, bool shouldPrint, AUGraph inGraph, UInt32 numFrames, MusicPlayer player) { // delete existing output file TestFile (outputFilePath, true); OSStatus result = 0; UInt32 size; CAStreamBasicDescription outputFormat; outputFormat.mChannelsPerFrame = 2; outputFormat.mSampleRate = srate; outputFormat.mFormatID = dataFormat; AudioFileTypeID destFileType; CAAudioFileFormats::Instance()->InferFileFormatFromFilename (outputFilePath, destFileType); if (dataFormat == kAudioFormatLinearPCM) { outputFormat.mBytesPerPacket = outputFormat.mChannelsPerFrame * 2; outputFormat.mFramesPerPacket = 1; outputFormat.mBytesPerFrame = outputFormat.mBytesPerPacket; outputFormat.mBitsPerChannel = 16; if (destFileType == kAudioFileWAVEType) outputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; else outputFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; } else { // use AudioFormat API to fill out the rest. size = sizeof(outputFormat); require_noerr (result = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &size, &outputFormat), fail); } if (shouldPrint) { printf ("Writing to file: %s with format:\n* ", outputFilePath); outputFormat.Print(); } FSRef parentDir; CFStringRef destFileName; require_noerr (result = PosixPathToParentFSRefAndName(outputFilePath, parentDir, destFileName), fail); ExtAudioFileRef outfile; result = ExtAudioFileCreateNew (&parentDir, destFileName, destFileType, &outputFormat, NULL, &outfile); CFRelease (destFileName); require_noerr (result, fail); AudioUnit outputUnit; UInt32 nodeCount; require_noerr (result = AUGraphGetNodeCount (inGraph, &nodeCount), fail); for (UInt32 i = 0; i < nodeCount; ++i) { AUNode node; require_noerr (result = AUGraphGetIndNode(inGraph, i, &node), fail); ComponentDescription desc; require_noerr (result = AUGraphNodeInfo(inGraph, node, &desc, NULL), fail); if (desc.componentType == kAudioUnitType_Output) { require_noerr (result = AUGraphNodeInfo(inGraph, node, 0, &outputUnit), fail); break; } } { CAStreamBasicDescription clientFormat; size = sizeof(clientFormat); require_noerr (result = AudioUnitGetProperty (outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &clientFormat, &size), fail); size = sizeof(clientFormat); require_noerr (result = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat), fail); { MusicTimeStamp currentTime; AUOutputBL outputBuffer (clientFormat, numFrames); AudioTimeStamp tStamp; memset (&tStamp, 0, sizeof(AudioTimeStamp)); tStamp.mFlags = kAudioTimeStampSampleTimeValid; int i = 0; int numTimesFor10Secs = (int)(10. / (numFrames / srate)); do { outputBuffer.Prepare(); AudioUnitRenderActionFlags actionFlags = 0; require_noerr (result = AudioUnitRender (outputUnit, &actionFlags, &tStamp, 0, numFrames, outputBuffer.ABL()), fail); tStamp.mSampleTime += numFrames; require_noerr (result = ExtAudioFileWrite(outfile, numFrames, outputBuffer.ABL()), fail); require_noerr (result = MusicPlayerGetTime (player, ¤tTime), fail); if (shouldPrint && (++i % numTimesFor10Secs == 0)) printf ("current time: %6.2f beats\n", currentTime); } while (currentTime < sequenceLength); } } // close ExtAudioFileDispose(outfile); return; fail: printf ("Problem: %ld\n", result); exit(1); }
bool FIOSAudioDevice::InitializeHardware() { SIZE_T SampleSize = sizeof(AudioSampleType); double GraphSampleRate = 44100.0; if (!SetHardwareSampleRate(GraphSampleRate) || !SetAudioSessionActive(true)) { HandleError(TEXT("Failed to establish the audio session!")); return false; } // Retrieve the actual hardware sample rate GetHardwareSampleRate(GraphSampleRate); // Linear PCM stream format MixerFormat.mFormatID = kAudioFormatLinearPCM; MixerFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; MixerFormat.mBytesPerPacket = SampleSize; MixerFormat.mFramesPerPacket = 1; MixerFormat.mBytesPerFrame = SampleSize; MixerFormat.mChannelsPerFrame = 1; MixerFormat.mBitsPerChannel = 8 * SampleSize; MixerFormat.mSampleRate = GraphSampleRate; OSStatus Status = NewAUGraph(&AudioUnitGraph); if (Status != noErr) { HandleError(TEXT("Failed to create audio unit graph!")); return false; } AudioComponentDescription UnitDescription; // Setup audio output unit UnitDescription.componentType = kAudioUnitType_Output; UnitDescription.componentSubType = kAudioUnitSubType_RemoteIO; UnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple; UnitDescription.componentFlags = 0; UnitDescription.componentFlagsMask = 0; Status = AUGraphAddNode(AudioUnitGraph, &UnitDescription, &OutputNode); if (Status != noErr) { HandleError(TEXT("Failed to initialize audio output node!"), true); return false; } // Setup audo mixer unit UnitDescription.componentType = kAudioUnitType_Mixer; UnitDescription.componentSubType = kAudioUnitSubType_AU3DMixerEmbedded; UnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple; UnitDescription.componentFlags = 0; UnitDescription.componentFlagsMask = 0; Status = AUGraphAddNode(AudioUnitGraph, &UnitDescription, &MixerNode); if (Status != noErr) { HandleError(TEXT("Failed to initialize audio mixer node!"), true); return false; } Status = AUGraphOpen(AudioUnitGraph); if (Status != noErr) { HandleError(TEXT("Failed to open audio unit graph"), true); return false; } Status = AUGraphNodeInfo(AudioUnitGraph, OutputNode, NULL, &OutputUnit); if (Status != noErr) { HandleError(TEXT("Failed to retrieve output unit reference!"), true); return false; } Status = AUGraphNodeInfo(AudioUnitGraph, MixerNode, NULL, &MixerUnit); if (Status != noErr) { HandleError(TEXT("Failed to retrieve mixer unit reference!"), true); return false; } uint32 BusCount = MaxChannels * CHANNELS_PER_BUS; Status = AudioUnitSetProperty(MixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &BusCount, sizeof(BusCount)); if (Status != noErr) { HandleError(TEXT("Failed to set kAudioUnitProperty_ElementCount for audio mixer unit!"), true); return false; } // Initialize sound source early on, allowing for render callback hookups InitSoundSources(); // Setup the mixer unit sample rate Status = AudioUnitSetProperty(MixerUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &GraphSampleRate, sizeof(GraphSampleRate)); if (Status != noErr) { HandleError(TEXT("Failed to set kAudioUnitProperty_SampleRate for audio mixer unit!"), true); return false; } // Connect mixer node output to output node input Status = AUGraphConnectNodeInput(AudioUnitGraph, MixerNode, 0, OutputNode, 0); if (Status != noErr) { HandleError(TEXT("Failed to connect mixer node to output node!"), true); return false; } // Initialize and start the audio unit graph Status = AUGraphInitialize(AudioUnitGraph); if (Status == noErr) { Status = AUGraphStart(AudioUnitGraph); } if (Status != noErr) { HandleError(TEXT("Failed to start audio graph!"), true); return false; } return true; }
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); }
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); }
/** * Initializes the audio device and creates sources. * * @return true if initialization was successful, false otherwise */ bool FCoreAudioDevice::InitializeHardware() { if (IsRunningDedicatedServer()) { return false; } // Load ogg and vorbis dlls if they haven't been loaded yet LoadVorbisLibraries(); InverseTransform = FMatrix::Identity; for( SInt32 Index = 0; Index < MAX_AUDIOCHANNELS; ++Index ) { Mixer3DInputStatus[ Index ] = false; } for( SInt32 Index = 0; Index < MAX_MULTICHANNEL_AUDIOCHANNELS; ++Index ) { MatrixMixerInputStatus[ Index ] = false; } // Make sure the output audio device exists AudioDeviceID HALDevice; UInt32 Size = sizeof( AudioDeviceID ); AudioObjectPropertyAddress PropertyAddress; PropertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; PropertyAddress.mScope = kAudioObjectPropertyScopeGlobal; PropertyAddress.mElement = kAudioObjectPropertyElementMaster; OSStatus Status = AudioObjectGetPropertyData( kAudioObjectSystemObject, &PropertyAddress, 0, NULL, &Size, &HALDevice ); if( Status != noErr ) { UE_LOG(LogInit, Log, TEXT( "No audio devices found!" ) ); return false; } Status = NewAUGraph( &AudioUnitGraph ); if( Status != noErr ) { UE_LOG(LogInit, Log, TEXT( "Failed to create audio unit graph!" ) ); return false; } AudioComponentDescription Desc; Desc.componentFlags = 0; Desc.componentFlagsMask = 0; Desc.componentType = kAudioUnitType_Output; Desc.componentSubType = kAudioUnitSubType_DefaultOutput; Desc.componentManufacturer = kAudioUnitManufacturer_Apple; Status = AUGraphAddNode( AudioUnitGraph, &Desc, &OutputNode ); if( Status == noErr ) { Status = AUGraphOpen( AudioUnitGraph ); if( Status == noErr ) { Status = AUGraphNodeInfo( AudioUnitGraph, OutputNode, NULL, &OutputUnit ); if( Status == noErr ) { Status = AudioUnitInitialize( OutputUnit ); } } } if( Status != noErr ) { UE_LOG(LogInit, Log, TEXT( "Failed to initialize audio output unit!" ) ); Teardown(); return false; } Desc.componentFlags = 0; Desc.componentFlagsMask = 0; Desc.componentType = kAudioUnitType_Mixer; Desc.componentSubType = kAudioUnitSubType_3DMixer; Desc.componentManufacturer = kAudioUnitManufacturer_Apple; Status = AUGraphAddNode( AudioUnitGraph, &Desc, &Mixer3DNode ); if( Status == noErr ) { Status = AUGraphNodeInfo( AudioUnitGraph, Mixer3DNode, NULL, &Mixer3DUnit ); if( Status == noErr ) { Status = AudioUnitInitialize( Mixer3DUnit ); } } if( Status != noErr ) { UE_LOG(LogInit, Log, TEXT( "Failed to initialize audio 3D mixer unit!" ) ); Teardown(); return false; } Desc.componentFlags = 0; Desc.componentFlagsMask = 0; Desc.componentType = kAudioUnitType_Mixer; Desc.componentSubType = kAudioUnitSubType_MatrixMixer; Desc.componentManufacturer = kAudioUnitManufacturer_Apple; Status = AUGraphAddNode( AudioUnitGraph, &Desc, &MatrixMixerNode ); if( Status == noErr ) { Status = AUGraphNodeInfo( AudioUnitGraph, MatrixMixerNode, NULL, &MatrixMixerUnit ); // Set number of buses for input uint32 NumBuses = MAX_MULTICHANNEL_AUDIOCHANNELS; Size = sizeof( NumBuses ); Status = AudioUnitSetProperty( MatrixMixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &NumBuses, Size ); if( Status == noErr ) { // Set number fo buses for output NumBuses = 1; Status = AudioUnitSetProperty( MatrixMixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Output, 0, &NumBuses, Size ); } if( Status != noErr ) { UE_LOG(LogInit, Log, TEXT( "Failed to setup audio matrix mixer unit!" ) ); Teardown(); return false; } // Get default input stream format Size = sizeof( AudioStreamBasicDescription ); Status = AudioUnitGetProperty( MatrixMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &MatrixMixerInputFormat, &Size ); // Set output stream format to SPEAKER_COUT (6 channels) MatrixMixerInputFormat.mChannelsPerFrame = SPEAKER_COUNT; MatrixMixerInputFormat.mFramesPerPacket = 1; MatrixMixerInputFormat.mBytesPerPacket = MatrixMixerInputFormat.mBytesPerFrame; MatrixMixerInputFormat.mFormatFlags |= kAudioFormatFlagIsNonInterleaved; for( int32 Index = 0; Index < MAX_MULTICHANNEL_AUDIOCHANNELS; Index++ ) { Status = AudioUnitSetProperty( MatrixMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, Index, &MatrixMixerInputFormat, Size ); if( Status != noErr ) { UE_LOG(LogInit, Log, TEXT( "Failed to setup audio matrix mixer unit input format!" ) ); Teardown(); return false; } } // Set output stream format Size = sizeof( AudioStreamBasicDescription ); Status = AudioUnitGetProperty( MatrixMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &MatrixMixerOutputFormat, &Size ); if( Status != noErr ) { UE_LOG(LogInit, Log, TEXT( "Failed to setup audio matrix mixer unit output format!" ) ); Teardown(); return false; } // Initialize Matrix Mixer unit Status = AudioUnitInitialize( MatrixMixerUnit ); if( Status != noErr ) { UE_LOG(LogInit, Log, TEXT( "Failed to initialize audio matrix mixer unit!" ) ); Teardown(); return false; } // Enable Output AudioUnitSetParameter( MatrixMixerUnit, kMatrixMixerParam_Enable, kAudioUnitScope_Output, 0, 1.0, 0 ); // Set Output volume AudioUnitSetParameter( MatrixMixerUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Output, 0, 1.0, 0 ); AudioUnitSetParameter( MatrixMixerUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Output, 1, 1.0, 0 ); // Set Master volume AudioUnitSetParameter( MatrixMixerUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Global, 0xFFFFFFFF, 1.0, 0 ); } Size = sizeof( AudioStreamBasicDescription ); Status = AudioUnitGetProperty( Mixer3DUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &Mixer3DFormat, &Size ); if( Status == noErr ) { // Connect 3D Mixer to Output node Status = AUGraphConnectNodeInput( AudioUnitGraph, Mixer3DNode, 0, OutputNode, 0 ); } if( Status != noErr ) { UE_LOG(LogInit, Log, TEXT( "Failed to start audio graph!" ) ); Teardown(); return false; } // Connect Matrix Mixer to 3D Mixer node Status = AUGraphConnectNodeInput( AudioUnitGraph, MatrixMixerNode, 0, Mixer3DNode, 0 ); Mixer3DInputStatus[0] = true; if( Status != noErr ) { UE_LOG(LogInit, Log, TEXT( "Failed to start audio graph!" ) ); Teardown(); return false; } Status = AUGraphInitialize( AudioUnitGraph ); if( Status == noErr ) { Status = AUGraphStart( AudioUnitGraph ); } if( Status != noErr ) { UE_LOG(LogInit, Log, TEXT( "Failed to start audio graph!" ) ); Teardown(); return false; } return true; }
OutputImplAudioUnit::OutputImplAudioUnit() : mAvailableBuses(), OutputImpl() { OSStatus err = noErr; NewAUGraph( &mGraph ); AudioComponentDescription cd; cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; //output node cd.componentType = kAudioUnitType_Output; cd.componentSubType = CINDER_AUDIOUNIT_OUTPUT_TYPE; //connect & setup AUGraphOpen( mGraph ); //initialize component - todo add error checking if( AUGraphAddNode( mGraph, &cd, &mOutputNode ) != noErr ) { std::cout << "Error 1!" << std::endl; } if( AUGraphNodeInfo( mGraph, mOutputNode, NULL, &mOutputUnit ) != noErr ) { std::cout << "Error 2!" << std::endl; } UInt32 dsize; #if defined( CINDER_MAC ) //get default output device id and set it as the outdevice for the output unit, unnessary on the iphone dsize = sizeof( AudioDeviceID ); err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &dsize, &mOutputDeviceId ); if( err != noErr ) { std::cout << "Error getting default output device" << std::endl; } err = AudioUnitSetProperty( mOutputUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &mOutputDeviceId, sizeof( mOutputDeviceId ) ); if( err != noErr ) { std::cout << "Error setting current output device" << std::endl; } #endif //Tell the output unit not to reset timestamps //Otherwise sample rate changes will cause sync los UInt32 startAtZero = 0; err = AudioUnitSetProperty( mOutputUnit, kAudioOutputUnitProperty_StartTimestampsAtZero, kAudioUnitScope_Global, 0, &startAtZero, sizeof( startAtZero ) ); if( err != noErr ) { std::cout << "Error telling output unit not to reset timestamps" << std::endl; } //stereo mixer node cd.componentType = kAudioUnitType_Mixer; cd.componentSubType = kAudioUnitSubType_MultiChannelMixer;//kAudioUnitSubType_StereoMixer; AUGraphAddNode( mGraph, &cd, &mMixerNode ); //setup mixer AU err = AUGraphNodeInfo( mGraph, mMixerNode, NULL, &mMixerUnit ); if( err ) { std::cout << "Error 4" << std::endl; } //TODO: cleanup error checking in all of this //check the element count, if it's less than our default element count, increase, or else just leave it alone err = AudioUnitGetProperty( mMixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &mNumberBuses, &dsize ); if( err ) { std::cout << "Error getting mixer unit input elements" << std::endl; } if( mNumberBuses < sDefaultNumberBuses ) { mNumberBuses = sDefaultNumberBuses; err = AudioUnitSetProperty( mMixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &mNumberBuses, sizeof(mNumberBuses) ); if( err ) { std::cout << "Error setting mixer unit input elements" << std::endl; } } for( uint32_t i = 1; i <= mNumberBuses; i++ ) { mAvailableBuses.push( mNumberBuses - i ); } AUGraphConnectNodeInput( mGraph, mMixerNode, 0, mOutputNode, 0 ); AudioStreamBasicDescription outDesc; UInt32 size = sizeof( outDesc ); err = AudioUnitGetProperty( mOutputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &outDesc, &size ); if( err ) { std::cout << "Error getting output unit stream format" << std::endl; } AUGraphInitialize( mGraph ); //Do all StreamFormat getting/setting after initialization, //since that's when the output unit is actually hooked up to the hardware dsize = sizeof( AudioStreamBasicDescription ); mPlayerDescription = new AudioStreamBasicDescription; err = AudioUnitGetProperty( mOutputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, mPlayerDescription, &dsize ); if( err ) { std::cout << "Error reading output unit stream format" << std::endl; } err = AudioUnitSetProperty( mMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, mPlayerDescription, dsize ); if( err ) { std::cout << "Error setting mixer unit output stream format" << std::endl; } err = AudioUnitSetProperty( mOutputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, mPlayerDescription, dsize ); if( err ) { std::cout << "Error setting output unit input stream format" << std::endl; } //race condition work around?? usleep( 10 * 1000 ); //TODO: tell the output AU about the order of the channels if there are more than 2 // turn metering ON //UInt32 data = 1; //AudioUnitSetProperty( mMixerUnit, kAudioUnitProperty_MeteringMode, kAudioUnitScope_Global, 0, &data, sizeof(data) ); err = AudioUnitSetParameter( mMixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Output, 0, CINDER_DEFAULT_VOLUME, 0 ); if( err ) { std::cout << "error setting default volume" << std::cout; } err = AUGraphStart( mGraph ); if( err ) { //throw } }
void CreateMyAUGraph(MyAUGraphPlayer *player) { // create a new AUGraph CheckError(NewAUGraph(&player->graph), "NewAUGraph failed"); // generate description that will match default output // ComponentDescription outputcd = {0}; // outputcd.componentType = kAudioUnitType_Output; // outputcd.componentSubType = kAudioUnitSubType_DefaultOutput; // outputcd.componentManufacturer = kAudioUnitManufacturer_Apple; // // Component comp = FindNextComponent(NULL, &outputcd); // if (comp == NULL) { // printf ("can't get output unit"); exit (-1); // } AudioComponentDescription outputcd = {0}; outputcd.componentType = kAudioUnitType_Output; outputcd.componentSubType = kAudioUnitSubType_DefaultOutput; outputcd.componentManufacturer = kAudioUnitManufacturer_Apple; AudioComponent comp = AudioComponentFindNext(NULL, &outputcd); if (comp == NULL) { printf ("can't get output unit"); exit (-1); } // adds a node with above description to the graph AUNode outputNode; CheckError(AUGraphAddNode(player->graph, &outputcd, &outputNode), "AUGraphAddNode[kAudioUnitSubType_DefaultOutput] failed"); #ifdef PART_II // add a mixer to the graph, AudioComponentDescription mixercd = {0}; mixercd.componentType = kAudioUnitType_Mixer; mixercd.componentSubType = kAudioUnitSubType_StereoMixer; // doesn't work: kAudioUnitSubType_MatrixMixer mixercd.componentManufacturer = kAudioUnitManufacturer_Apple; AUNode mixerNode; CheckError(AUGraphAddNode(player->graph, &mixercd, &mixerNode), "AUGraphAddNode[kAudioUnitSubType_StereoMixer] failed"); // adds a node with above description to the graph AudioComponentDescription speechcd = {0}; speechcd.componentType = kAudioUnitType_Generator; speechcd.componentSubType = kAudioUnitSubType_SpeechSynthesis; speechcd.componentManufacturer = kAudioUnitManufacturer_Apple; AUNode speechNode; CheckError(AUGraphAddNode(player->graph, &speechcd, &speechNode), "AUGraphAddNode[kAudioUnitSubType_AudioFilePlayer] 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 objects for the various nodes CheckError(AUGraphNodeInfo(player->graph, outputNode, NULL, &player->outputUnit), "AUGraphNodeInfo failed"); CheckError(AUGraphNodeInfo(player->graph, speechNode, NULL, &player->speechUnit), "AUGraphNodeInfo failed"); AudioUnit mixerUnit; CheckError(AUGraphNodeInfo(player->graph, mixerNode, NULL, &mixerUnit), "AUGraphNodeInfo failed"); // set ASBDs here UInt32 propertySize = sizeof (AudioStreamBasicDescription); CheckError(AudioUnitSetProperty(player->outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &player->streamFormat, propertySize), "Couldn't set stream format on output unit"); // problem: badComponentInstance (-2147450879) CheckError(AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &player->streamFormat, propertySize), "Couldn't set stream format on mixer unit bus 0"); CheckError(AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &player->streamFormat, propertySize), "Couldn't set stream format on mixer unit bus 1"); // connections // mixer output scope / bus 0 to outputUnit input scope / bus 0 // mixer input scope / bus 0 to render callback (from ringbuffer, which in turn is from inputUnit) // mixer input scope / bus 1 to speech unit output scope / bus 0 CheckError(AUGraphConnectNodeInput(player->graph, mixerNode, 0, outputNode, 0), "Couldn't connect mixer output(0) to outputNode (0)"); CheckError(AUGraphConnectNodeInput(player->graph, speechNode, 0, mixerNode, 1), "Couldn't connect speech synth unit output (0) to mixer input (1)"); AURenderCallbackStruct callbackStruct; callbackStruct.inputProc = GraphRenderProc; callbackStruct.inputProcRefCon = player; CheckError(AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &callbackStruct, sizeof(callbackStruct)), "Couldn't set render callback on mixer unit"); #else // 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 output graph node CheckError(AUGraphNodeInfo(player->graph, outputNode, NULL, &player->outputUnit), "AUGraphNodeInfo failed"); // set the stream format on the output unit's input scope UInt32 propertySize = sizeof (AudioStreamBasicDescription); CheckError(AudioUnitSetProperty(player->outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &player->streamFormat, propertySize), "Couldn't set stream format on output unit"); AURenderCallbackStruct callbackStruct; callbackStruct.inputProc = GraphRenderProc; callbackStruct.inputProcRefCon = player; CheckError(AudioUnitSetProperty(player->outputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &callbackStruct, sizeof(callbackStruct)), "Couldn't set render callback on output unit"); #endif // now initialize the graph (causes resources to be allocated) CheckError(AUGraphInitialize(player->graph), "AUGraphInitialize failed"); player->firstOutputSampleTime = -1; printf ("Bottom of CreateSimpleAUGraph()\n"); }
int MidiDriver_CORE::open() { OSStatus err = 0; if (isOpen()) return MERR_ALREADY_OPEN; // Open the Music Device. RequireNoErr(NewAUGraph(&_auGraph)); AUNode outputNode, synthNode; #if USE_DEPRECATED_COREAUDIO_API ComponentDescription desc; #else AudioComponentDescription desc; #endif // The default output device desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_DefaultOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; #if USE_DEPRECATED_COREAUDIO_API RequireNoErr(AUGraphNewNode(_auGraph, &desc, 0, NULL, &outputNode)); #else RequireNoErr(AUGraphAddNode(_auGraph, &desc, &outputNode)); #endif // The built-in default (softsynth) music device desc.componentType = kAudioUnitType_MusicDevice; desc.componentSubType = kAudioUnitSubType_DLSSynth; desc.componentManufacturer = kAudioUnitManufacturer_Apple; #if USE_DEPRECATED_COREAUDIO_API RequireNoErr(AUGraphNewNode(_auGraph, &desc, 0, NULL, &synthNode)); #else RequireNoErr(AUGraphAddNode(_auGraph, &desc, &synthNode)); #endif // Connect the softsynth to the default output RequireNoErr(AUGraphConnectNodeInput(_auGraph, synthNode, 0, outputNode, 0)); // Open and initialize the whole graph RequireNoErr(AUGraphOpen(_auGraph)); RequireNoErr(AUGraphInitialize(_auGraph)); // Get the music device from the graph. #if USE_DEPRECATED_COREAUDIO_API RequireNoErr(AUGraphGetNodeInfo(_auGraph, synthNode, NULL, NULL, NULL, &_synth)); #else RequireNoErr(AUGraphNodeInfo(_auGraph, synthNode, NULL, &_synth)); #endif // Load custom soundfont, if specified if (ConfMan.hasKey("soundfont")) { FSRef fsref; FSSpec fsSpec; const char *soundfont = ConfMan.get("soundfont").c_str(); err = FSPathMakeRef ((const byte *)soundfont, &fsref, NULL); if (err == noErr) { err = FSGetCatalogInfo (&fsref, kFSCatInfoNone, NULL, NULL, &fsSpec, NULL); } if (err == noErr) { // TODO: We should really check here whether the file contains an // actual soundfont... err = AudioUnitSetProperty ( _synth, kMusicDeviceProperty_SoundBankFSSpec, kAudioUnitScope_Global, 0, &fsSpec, sizeof(fsSpec) ); } if (err != noErr) warning("Failed loading custom sound font '%s' (error %ld)\n", soundfont, (long)err); } #ifdef COREAUDIO_DISABLE_REVERB // Disable reverb mode, as that sucks up a lot of CPU power, which can // be painful on low end machines. // TODO: Make this customizable via a config key? UInt32 usesReverb = 0; AudioUnitSetProperty (_synth, kMusicDeviceProperty_UsesInternalReverb, kAudioUnitScope_Global, 0, &usesReverb, sizeof (usesReverb)); #endif // Finally: Start the graph! RequireNoErr(AUGraphStart(_auGraph)); return 0; bail: if (_auGraph) { AUGraphStop(_auGraph); DisposeAUGraph(_auGraph); _auGraph = 0; } return MERR_CANNOT_CONNECT; }
void WriteOutputFile (const char* outputFilePath, OSType dataFormat, Float64 srate, MusicTimeStamp sequenceLength, bool shouldPrint, AUGraph inGraph, UInt32 numFrames, MusicPlayer player) { OSStatus result = 0; UInt32 size; CAStreamBasicDescription outputFormat; outputFormat.mChannelsPerFrame = 2; outputFormat.mSampleRate = srate; outputFormat.mFormatID = dataFormat; AudioFileTypeID destFileType; CAAudioFileFormats::Instance()->InferFileFormatFromFilename (outputFilePath, destFileType); if (dataFormat == kAudioFormatLinearPCM) { outputFormat.mBytesPerPacket = outputFormat.mChannelsPerFrame * 2; outputFormat.mFramesPerPacket = 1; outputFormat.mBytesPerFrame = outputFormat.mBytesPerPacket; outputFormat.mBitsPerChannel = 16; if (destFileType == kAudioFileWAVEType) outputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; else outputFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; } else { // use AudioFormat API to fill out the rest. size = sizeof(outputFormat); FailIf ((result = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &size, &outputFormat)), fail, ""); } if (shouldPrint) { printf ("Writing to file: %s with format:\n* ", outputFilePath); outputFormat.Print(); } CFURLRef url; url = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8*)outputFilePath, strlen(outputFilePath), false); // create output file, delete existing file ExtAudioFileRef outfile; result = ExtAudioFileCreateWithURL(url, destFileType, &outputFormat, NULL, kAudioFileFlags_EraseFile, &outfile); if (url) CFRelease (url); FailIf (result, fail, "ExtAudioFileCreateWithURL"); AudioUnit outputUnit; outputUnit = NULL; UInt32 nodeCount; FailIf ((result = AUGraphGetNodeCount (inGraph, &nodeCount)), fail, "AUGraphGetNodeCount"); for (UInt32 i = 0; i < nodeCount; ++i) { AUNode node; FailIf ((result = AUGraphGetIndNode(inGraph, i, &node)), fail, "AUGraphGetIndNode"); AudioComponentDescription desc; FailIf ((result = AUGraphNodeInfo(inGraph, node, &desc, NULL)), fail, "AUGraphNodeInfo"); if (desc.componentType == kAudioUnitType_Output) { FailIf ((result = AUGraphNodeInfo(inGraph, node, 0, &outputUnit)), fail, "AUGraphNodeInfo"); break; } } FailIf ((result = (outputUnit == NULL)), fail, "outputUnit == NULL"); { CAStreamBasicDescription clientFormat = CAStreamBasicDescription(); size = sizeof(clientFormat); FailIf ((result = AudioUnitGetProperty (outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &clientFormat, &size)), fail, "AudioUnitGetProperty: kAudioUnitProperty_StreamFormat"); size = sizeof(clientFormat); FailIf ((result = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat)), fail, "ExtAudioFileSetProperty: kExtAudioFileProperty_ClientDataFormat"); { MusicTimeStamp currentTime; AUOutputBL outputBuffer (clientFormat, numFrames); AudioTimeStamp tStamp; memset (&tStamp, 0, sizeof(AudioTimeStamp)); tStamp.mFlags = kAudioTimeStampSampleTimeValid; int i = 0; int numTimesFor10Secs = (int)(10. / (numFrames / srate)); do { outputBuffer.Prepare(); AudioUnitRenderActionFlags actionFlags = 0; FailIf ((result = AudioUnitRender (outputUnit, &actionFlags, &tStamp, 0, numFrames, outputBuffer.ABL())), fail, "AudioUnitRender"); tStamp.mSampleTime += numFrames; FailIf ((result = ExtAudioFileWrite(outfile, numFrames, outputBuffer.ABL())), fail, "ExtAudioFileWrite"); FailIf ((result = MusicPlayerGetTime (player, ¤tTime)), fail, "MusicPlayerGetTime"); if (shouldPrint && (++i % numTimesFor10Secs == 0)) printf ("current time: %6.2f beats\n", currentTime); } while (currentTime < sequenceLength); } } // close ExtAudioFileDispose(outfile); return; fail: printf ("Problem: %ld\n", (long)result); exit(1); }
int QBSoundMac::initGraph() { OSStatus err; mAudioFormat.mSampleRate = 44100.000000; mAudioFormat.mFormatID = kAudioFormatLinearPCM; #ifdef __FLOAT_BUFFER__ mAudioFormat.mFormatFlags = 0 | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsFloat #if __BIG_ENDIAN__ | kLinearPCMFormatFlagIsBigEndian #endif ; mAudioFormat.mBytesPerPacket = 8; mAudioFormat.mFramesPerPacket = 1; mAudioFormat.mBytesPerFrame = 8; mAudioFormat.mChannelsPerFrame = 2; mAudioFormat.mBitsPerChannel = 32; mAudioFormat.mReserved = 0; #else mAudioFormat.mFormatFlags = 0 | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger #if __BIG_ENDIAN__ | kLinearPCMFormatFlagIsBigEndian #endif ; mAudioFormat.mBytesPerPacket = 4; mAudioFormat.mFramesPerPacket = 1; mAudioFormat.mBytesPerFrame = 4; mAudioFormat.mChannelsPerFrame = 2; mAudioFormat.mBitsPerChannel = 16; mAudioFormat.mReserved = 0; #endif err = NewAUGraph(&mGraph); #if !TARGET_OS_IPHONE AudioComponentDescription description; description.componentSubType = kAudioUnitSubType_DefaultOutput; #else AudioComponentDescription description; description.componentSubType = kAudioUnitSubType_RemoteIO; #endif description.componentType = kAudioUnitType_Output; description.componentManufacturer = kAudioUnitManufacturer_Apple; description.componentFlags = 0; description.componentFlagsMask = 0; #if 1 err = AUGraphAddNode(mGraph,&description,&mOutputNode); #else err = AUGraphNewNode(mGraph,&description, 0, NULL, &mOutputNode); #endif err = AUGraphOpen(mGraph); #if 1 err = AUGraphNodeInfo(mGraph,mOutputNode,NULL,&mAudioUnit); #else err = AUGraphGetNodeInfo(mGraph,mOutputNode,NULL,NULL,NULL,&mAudioUnit); #endif err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &mAudioFormat, sizeof(AudioStreamBasicDescription)); { AURenderCallbackStruct input; input.inputProc = callback; input.inputProcRefCon = this; err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(input)); } // { // AudioUnitSetParameter (mAudioUnit, // kHALOutputParam_Volume, // kAudioUnitScope_Global,0,1,0); // } err = AUGraphInitialize(mGraph); //err = AUGraphStart(mGraph); //pthread_mutex_init(&mLoaderThreadMutex,NULL); #ifdef __USE_OGG_VORBIS__ mThreadEnd = false; pthread_create(&mLoaderThread,NULL,LoaderThreadProc,this); #endif // mOpenGraph = false; // mInitGraph = false; // startAUGraph(); //printf("openAUGraph\n"); return err; }