CAUOutputDevice *CCoreAudioGraph::CreateUnit(AEAudioFormat &format) { if (!m_audioUnit || !m_mixerUnit) return NULL; AudioStreamBasicDescription fmt = {0}; AudioStreamBasicDescription inputFormat = {0}; AudioStreamBasicDescription outputFormat = {0}; int busNumber = GetFreeBus(); if (busNumber == INVALID_BUS) return NULL; OSStatus ret; // create output unit CAUOutputDevice *outputUnit = new CAUOutputDevice(); if (!outputUnit->Open(m_audioGraph, kAudioUnitType_FormatConverter, kAudioUnitSubType_AUConverter, kAudioUnitManufacturer_Apple)) goto error; m_audioUnit->GetFormatDesc(format, &inputFormat, &fmt); // get the format frm the mixer if (!m_mixerUnit->GetFormat(&outputFormat, kAudioUnitScope_Input, kOutputBus)) goto error; if (!outputUnit->SetFormat(&inputFormat, kAudioUnitScope_Input, kOutputBus)) goto error; if (!outputUnit->SetFormat(&outputFormat, kAudioUnitScope_Output, kOutputBus)) goto error; ret = AUGraphConnectNodeInput(m_audioGraph, outputUnit->GetNode(), 0, m_mixerUnit->GetNode(), busNumber); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::CreateUnit: " "Error connecting outputUnit. Error = %s", GetError(ret).c_str()); goto error; } // TODO: setup mixmap, get free bus number for connection outputUnit->SetBus(busNumber); if (m_mixMap || m_mixMap->IsValid()) { UInt32 inputNumber = outputUnit->GetBus(); int channelOffset = GetMixerChannelOffset(inputNumber); CCoreAudioMixMap::SetMixingMatrix(m_mixerUnit, m_mixMap, &inputFormat, &fmt, channelOffset); } AUGraphUpdate(m_audioGraph, NULL); m_auUnitList.push_back(outputUnit); return outputUnit; error: delete outputUnit; return NULL; }
CAUOutputDevice *CCoreAudioGraph::CreateUnit(AEAudioFormat &format) { if (!m_audioUnit || !m_mixerUnit) return NULL; std::string formatString; AudioStreamBasicDescription inputFormat; AudioStreamBasicDescription outputFormat; OSStatus ret; int busNumber = GetFreeBus(); if (busNumber == INVALID_BUS) return NULL; // create output unit CAUOutputDevice *outputUnit = new CAUOutputDevice(); if (!outputUnit->Open(m_audioGraph, kAudioUnitType_FormatConverter, kAudioUnitSubType_AUConverter, kAudioUnitManufacturer_Apple)) goto error; m_audioUnit->GetFormatDesc(format, &inputFormat); // get the format frm the mixer if (!m_mixerUnit->GetFormat(&outputFormat, kAudioUnitScope_Input, kOutputBus)) goto error; if (!outputUnit->SetFormat(&outputFormat, kAudioUnitScope_Output, kOutputBus)) goto error; if (!outputUnit->SetFormat(&inputFormat, kAudioUnitScope_Input, kOutputBus)) goto error; ret = AUGraphConnectNodeInput(m_audioGraph, outputUnit->GetNode(), 0, m_mixerUnit->GetNode(), busNumber); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::CreateUnit: Error connecting outputUnit. Error = %s", GetError(ret).c_str()); goto error; } // TODO: setup mixmap, get free bus number for connection outputUnit->SetBus(busNumber); AUGraphUpdate(m_audioGraph, NULL); printf("Add unit\n\n"); ShowGraph(); printf("\n"); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Input Stream Format %s", StreamDescriptionToString(inputFormat, formatString)); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Output Stream Format %s", StreamDescriptionToString(outputFormat, formatString)); m_auUnitList.push_back(outputUnit); return outputUnit; error: delete outputUnit; return NULL; }
OSStatus CAPlayThrough::Init(AudioDeviceID input, AudioDeviceID output) { OSStatus err = noErr; //Note: You can interface to input and output devices with "output" audio units. //Please keep in mind that you are only allowed to have one output audio unit per graph (AUGraph). //As you will see, this sample code splits up the two output units. The "output" unit that will //be used for device input will not be contained in a AUGraph, while the "output" unit that will //interface the default output device will be in a graph. //Setup AUHAL for an input device err = SetupAUHAL(input); checkErr(err); //Setup Graph containing Varispeed Unit & Default Output Unit err = SetupGraph(output); checkErr(err); err = SetupBuffers(); checkErr(err); // the varispeed unit should only be conected after the input and output formats have been set err = AUGraphConnectNodeInput(mGraph, mVarispeedNode, 0, mOutputNode, 0); checkErr(err); err = AUGraphInitialize(mGraph); checkErr(err); //Add latency between the two devices ComputeThruOffset(); return err; }
OSStatus connect_next_node() { return AUGraphConnectNodeInput( m_graph, m_node_details[m_node_count].m_node, 0, m_node_details[m_node_count - 1].m_node, 0); }
OSStatus FCoreAudioSoundSource::ConnectAudioUnit( AUNode DestNode, uint32 DestInputNumber, AUNode OutNode, AudioUnit OutUnit ) { OSStatus Status = AudioUnitInitialize( OutUnit ); if( Status == noErr ) { Status = AUGraphConnectNodeInput( AudioDevice->GetAudioUnitGraph(), OutNode, 0, DestNode, DestInputNumber ); } return Status; }
/* This call creates the Graph and the Synth unit... */ static OSStatus CreateAUGraph(void) { OSStatus result; /* Create the nodes of the graph */ AUNode synthNode, limiterNode, outNode; ComponentDescription cd; cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; result = NewAUGraph(&s_graph); if (result != 0) return result; cd.componentType = kAudioUnitType_MusicDevice; cd.componentSubType = kAudioUnitSubType_DLSSynth; result = AUGraphNewNode(s_graph, &cd, 0, NULL, &synthNode); if (result != 0) return result; cd.componentType = kAudioUnitType_Effect; cd.componentSubType = kAudioUnitSubType_PeakLimiter; result = AUGraphNewNode(s_graph, &cd, 0, NULL, &limiterNode); if (result != 0) return result; cd.componentType = kAudioUnitType_Output; cd.componentSubType = kAudioUnitSubType_DefaultOutput; result = AUGraphNewNode(s_graph, &cd, 0, NULL, &outNode); if (result != 0) return result; result = AUGraphOpen(s_graph); if (result != 0) return result; result = AUGraphConnectNodeInput(s_graph, synthNode, 0, limiterNode, 0); if (result != 0) return result; result = AUGraphConnectNodeInput(s_graph, limiterNode, 0, outNode, 0); if (result != 0) return result; /* Ok we're good to go - get the Synth Unit... */ result = AUGraphGetNodeInfo(s_graph, synthNode, 0, 0, 0, &s_synthUnit); return result; }
// This call creates the Graph and the Synth unit... OSStatus CreateAUGraph (AUGraph &outGraph, AudioUnit &outSynth) { OSStatus result; //create the nodes of the graph AUNode synthNode, limiterNode, outNode; ComponentDescription cd; cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; require_noerr (result = NewAUGraph (&outGraph), home); cd.componentType = kAudioUnitType_MusicDevice; cd.componentSubType = kAudioUnitSubType_DLSSynth; require_noerr (result = AUGraphNewNode (outGraph, &cd, 0, NULL, &synthNode), home); cd.componentType = kAudioUnitType_Effect; cd.componentSubType = kAudioUnitSubType_PeakLimiter; require_noerr (result = AUGraphNewNode (outGraph, &cd, 0, NULL, &limiterNode), home); cd.componentType = kAudioUnitType_Output; cd.componentSubType = kAudioUnitSubType_DefaultOutput; require_noerr (result = AUGraphNewNode (outGraph, &cd, 0, NULL, &outNode), home); require_noerr (result = AUGraphOpen (outGraph), home); require_noerr (result = AUGraphConnectNodeInput (outGraph, synthNode, 0, limiterNode, 0), home); require_noerr (result = AUGraphConnectNodeInput (outGraph, limiterNode, 0, outNode, 0), home); // ok we're good to go - get the Synth Unit... require_noerr (result = AUGraphGetNodeInfo(outGraph, synthNode, 0, 0, 0, &outSynth), home); home: return result; }
bool AudioConnection::connect(AudioGraph *graph) { if (m_connected || !m_sourceAudioNode) return true; DEBUG_AUDIO_GRAPH("Connection" << int(this) << "connect" << int(m_sourceAudioNode) << m_sourceOutputBus << "->" << int(m_sinkAudioNode) << m_sinkInputBus) AUNode sourceOut = m_sourceAudioNode->getOutputAUNode(); AUNode sinkIn = m_sinkAudioNode->getInputAUNode(); OSStatus err = AUGraphConnectNodeInput(graph->audioGraphRef(), sourceOut, m_sourceOutputBus, sinkIn, m_sinkInputBus); m_connected = (err == noErr) ? true : false; return m_connected; }
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"); } }
int main(int argc, char *argv[]) { WindowRef window; HIViewRef content; HIViewRef combo; HIViewRef group; HIViewRef check; HIViewRef text; HIViewRef slider; HIViewRef quit; MenuRef menu; HIRect rect; // Window bounds Rect bounds = {0, 0, 436, 590}; // Create window CreateNewWindow(kDocumentWindowClass, kWindowStandardFloatingAttributes | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute | kWindowCompositingAttribute, &bounds, &window); // Set the title SetWindowTitleWithCFString(window, CFSTR("Accordion")); // Create an application menu CreateNewMenu(0, 0, &menu); // Set menu title SetMenuTitleWithCFString(menu, CFStringCreateWithPascalString(kCFAllocatorDefault, "\p\024", kCFStringEncodingMacRoman)); // Create an about item InsertMenuItemTextWithCFString(menu, CFSTR("About Accordion"), 0, 0, kHICommandAbout); // Insert the menu InsertMenu(menu, 0); // Create a standard window menu CreateStandardWindowMenu(0, &menu); // Insert the menu InsertMenu(menu, 0); // Show and position the window ShowWindow(window); RepositionWindow(window, NULL, kWindowCascadeOnMainScreen); // Find the window content HIViewFindByID(HIViewGetRoot(window), kHIViewWindowContentID, &content); // Set bounds for group box bounds.bottom = 92; bounds.right = 550; // Create group box CreateGroupBoxControl(window, &bounds, NULL, true, &group); // Place in the window HIViewAddSubview(content, group); HIViewPlaceInSuperviewAt(group, 20, 20); // Bounds of text bounds.bottom = 16; bounds.right = 74; // Create static text CreateStaticTextControl(window, &bounds, CFSTR("Instrument:"), NULL, &text); // Place in the group box HIViewAddSubview(group, text); HIViewPlaceInSuperviewAt(text, 16, 18); // Bounds of combo box rect.size.height = 20; rect.size.width = 168; // Create combo box HIComboBoxCreate(&rect, CFSTR(" Accordion"), NULL, NULL, kHIComboBoxStandardAttributes, &combo); // Set visible and set command ID HIViewSetVisible(combo, true); HIViewSetCommandID(combo, kCommandInst); // Add the instruments for (int i = 0; i < Length(instruments); i++) { HIComboBoxAppendTextItem(combo, CFStringCreateWithCString(kCFAllocatorDefault, instruments[i], kCFStringEncodingMacRoman), NULL); // Set the current instrument if (strcmp(instruments[i], " Accordion") == 0) instrument = i; } // Place in the group box HIViewAddSubview(group, combo); HIViewPlaceInSuperviewAt(combo, 102, 16); // Bounds of check box bounds.bottom = 18; bounds.right = 121; // Create check box CreateCheckBoxControl(window, &bounds, CFSTR("Reverse"), false, true, &check); // Set the control ID and the command ID HIViewSetID(check, kHIViewIDReverse); HIViewSetCommandID(check, kCommandReverse); // Place in the group box HIViewAddSubview(group, check); HIViewPlaceInSuperviewAt(check, 286, 17); // Bounds of text bounds.bottom = 16; bounds.right = 32; // Create static text CreateStaticTextControl(window, &bounds, CFSTR("Key:"), NULL, &text); // Place in the group box HIViewAddSubview(group, text); HIViewPlaceInSuperviewAt(text, 400, 18); // Bounds of combo box rect.size.width = 90; // Create combo box HIComboBoxCreate(&rect, CFSTR(" A/D/G"), NULL, NULL, kHIComboBoxStandardAttributes, &combo); // Set visible and set command ID HIViewSetVisible(combo, true); HIViewSetID(combo, kHIViewIDKey); HIViewSetCommandID(combo, kCommandKey); // Add keys for (int i = 0; i < Length(keys); i++) { HIComboBoxAppendTextItem(combo, CFStringCreateWithCString(kCFAllocatorDefault, keys[i], kCFStringEncodingMacRoman), NULL); // Set current key if (strcmp(keys[i], " A/D/G") == 0) key = i; } // Place in the group box HIViewAddSubview(group, combo); HIViewPlaceInSuperviewAt(combo, 440, 16); // Bounds of text bounds.bottom = 16; bounds.right = 54; // Create static text CreateStaticTextControl(window, &bounds, CFSTR("Volume:"), NULL, &text); // Place in the group box HIViewAddSubview(group, text); HIViewPlaceInSuperviewAt(text, 16, 56); // Bounds of slider bounds.bottom = 16; bounds.right = 168; // Create slider CreateSliderControl(window, &bounds, MAXVOL, 0, MAXVOL, kControlSliderDoesNotPoint, 0, false, NULL, &slider); // Set command ID HIViewSetCommandID(slider, kCommandVolume); // Place in the group box HIViewAddSubview(group, slider); HIViewPlaceInSuperviewAt(slider, 100, 58); // Bounds of check box bounds.bottom = 18; bounds.right = 121; // Create check box CreateCheckBoxControl(window, &bounds, CFSTR("Notes"), false, true, &check); // Set the control ID and the command ID HIViewSetID(check, kHIViewIDNote); HIViewSetCommandID(check, kCommandNote); // Place in the group box HIViewAddSubview(group, check); HIViewPlaceInSuperviewAt(check, 286, 56); // Bounds of push button bounds.bottom = 20; bounds.right = 90; // Create push button CreatePushButtonControl(window, &bounds, CFSTR("Quit"), &quit); // Set command ID HIViewSetCommandID(quit, kHICommandQuit); // Place in the group box HIViewAddSubview(group, quit); HIViewPlaceInSuperviewAt(quit, 440, 54); // Group box bounds bounds.bottom = 48; bounds.right = 550; // Create group box CreateGroupBoxControl(window, &bounds, NULL, true, &group); // Place in the window HIViewAddSubview(content, group); HIViewPlaceInSuperviewAt(group, 20, 132); // Font style ControlFontStyleRec style; style.flags = kControlUseFontMask|kControlUseJustMask; style.font = kControlFontBigSystemFont; style.just = teCenter; // Bounds of text bounds.bottom = 16; bounds.right = 550; // Create static text CreateStaticTextControl(window, &bounds, CFSTR("Accordion"), &style, &text); // Place in the group box HIViewAddSubview(group, text); HIViewPlaceInSuperviewAt(text, 0, 8); // Bounds of text bounds.bottom = 16; bounds.right = 550; // Create static text CreateStaticTextControl(window, &bounds, CFSTR("Play accordion on your keyboard"), &style, &text); // Place in the group box HIViewAddSubview(group, text); HIViewPlaceInSuperviewAt(text, 0, 24); // Group box bounds bounds.bottom = 196; bounds.right = 550; // Create group box CreateGroupBoxControl(window, &bounds, NULL, true, &group); // Place in the window HIViewAddSubview(content, group); HIViewPlaceInSuperviewAt(group, 20, 200); // Button bounds bounds.bottom = SIZE; bounds.right = SIZE; // Create row of bass buttons for (int i = 0; i < Length(bassdisplay); i++) { int x = 15 + 44 * i; int y = 15; // Create button CreateBevelButtonControl(window, &bounds, NULL, kControlBevelButtonNormalBevel, kControlBehaviorPushbutton, NULL, 0, 0, 0, &bassdisplay[i]); // Place in the group box HIViewAddSubview(group, bassdisplay[i]); HIViewPlaceInSuperviewAt(bassdisplay[i], x, y); } // Create three rows of buttons for (int i = 0; i < Length(display); i++) { for (int j = 0; j < ((i == 1)? Length(display[i]): Length(display[i]) - 1); j++) { int x = (i == 1)? 37 + 44 * j: 59 + 44 * j; int y = 59 + 44 * i; // Create button CreateBevelButtonControl(window, &bounds, NULL, kControlBevelButtonNormalBevel, kControlBehaviorPushbutton, NULL, 0, 0, 0, &display[i][j]); // Place in the group box HIViewAddSubview(group, display[i][j]); HIViewPlaceInSuperviewAt(display[i][j], x, y); } } // Create spacebar button CreateBevelButtonControl(window, &bounds, NULL, kControlBevelButtonNormalBevel, kControlBehaviorPushbutton, NULL, 0, 0, 0, &spacebar); // Place in the group box HIViewAddSubview(group, spacebar); HIViewPlaceInSuperviewAt(spacebar, 16, 147); // Group box bounds, wider than the window to hide rounded corners bounds.bottom = 20; bounds.right = 598; // Create group box for fake status bar CreateGroupBoxControl(window, &bounds, NULL, false, &group); // Place in window at negative offset to hide rounded corners HIViewAddSubview(content, group); HIViewPlaceInSuperviewAt(group, -4, 416); // Text bounds bounds.bottom = 16; bounds.right = 590; // Font style style.flags = kControlUseFontMask|kControlUseJustMask; style.font = kControlFontSmallSystemFont; style.just = teCenter; // Create static text CreateStaticTextControl(window, &bounds, CFSTR("Press the keyboard keys as accordion buttons " "and the space bar as the bellows. 3rd button start."), &style, &text); // Place in group box HIViewAddSubview(group, text); HIViewPlaceInSuperviewAt(text, 0, 2); // Application events type spec EventTypeSpec applicationEvents[] = {{kEventClassApplication, kEventAppFrontSwitched}}; // Install event handler InstallApplicationEventHandler(NewEventHandlerUPP(ApplicationHandler), Length(applicationEvents), applicationEvents, NULL, NULL); // Mouse events type spec EventTypeSpec mouseEvents[] = {{kEventClassMouse, kEventMouseDown}}; // Install event handler on the event dispatcher, so that we can // see mouse events before the default handler gets them InstallEventHandler(GetEventDispatcherTarget(), NewEventHandlerUPP(MouseHandler), Length(mouseEvents), mouseEvents, NULL, NULL); // Window events type spec EventTypeSpec windowEvents[] = {{kEventClassWindow, kEventWindowClose}}; // Install event handler InstallWindowEventHandler(window, NewEventHandlerUPP(WindowHandler), Length(windowEvents), windowEvents, NULL, NULL); // Combo box events type spec EventTypeSpec comboBoxEvents[] = {{kEventClassHIComboBox, kEventComboBoxListItemSelected}}; // Install event handler InstallApplicationEventHandler(NewEventHandlerUPP(ComboBoxHandler), Length(comboBoxEvents), comboBoxEvents, NULL, NULL); // Command events type spec EventTypeSpec commandEvents[] = {{kEventClassCommand, kEventCommandProcess}}; // Install event handler InstallApplicationEventHandler(NewEventHandlerUPP(CommandHandler), Length(commandEvents), commandEvents, NULL, NULL); // Keyboard events type spec EventTypeSpec keyboardEvents[] = {{kEventClassKeyboard, kEventRawKeyDown}, {kEventClassKeyboard, kEventRawKeyUp}, {kEventClassKeyboard, kEventRawKeyModifiersChanged}}; // Install event handler on the event dispatcher InstallEventHandler(GetEventDispatcherTarget(), NewEventHandlerUPP(KeyboardHandler), Length(keyboardEvents), keyboardEvents, NULL, NULL); // Audio Unit graph AUGraph graph; // Audio Unit synthesizer and output node AUNode synthNode; AUNode outNode; // Component description ComponentDescription cd; cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; do { // New AU graph OSStatus status = NewAUGraph(&graph); if (status != noErr) { DisplayAlert(CFSTR("NewAUGraph"), CFSTR("Can't create a new AUGraph"), status); break; } // Synthesizer cd.componentType = kAudioUnitType_MusicDevice; cd.componentSubType = kAudioUnitSubType_DLSSynth; // New synthesizer node status = AUGraphNewNode(graph, &cd, 0, NULL, &synthNode); if (status != noErr) { DisplayAlert(CFSTR("AUGraphNewNode"), CFSTR("Can't create a new AUGraph node"), status); break; } // Output cd.componentType = kAudioUnitType_Output; cd.componentSubType = kAudioUnitSubType_DefaultOutput; // New output node status = AUGraphNewNode(graph, &cd, 0, NULL, &outNode); if (status != noErr) { DisplayAlert(CFSTR("AUGraphNewNode"), CFSTR("Can't create a new AUGraph node"), status); break; } // Open graph status = AUGraphOpen(graph); if (status != noErr) { DisplayAlert(CFSTR("AUGraphOpen"), CFSTR("Can't open AUGraph"), status); break; } // Connect synthesizer node to output node status = AUGraphConnectNodeInput(graph, synthNode, 0, outNode, 0); if (status != noErr) { DisplayAlert(CFSTR("AUGraphConnectNodeInput"), CFSTR("Can't connect AUGraph input node"), status); break; } // Get a synthesizer unit status = AUGraphGetNodeInfo(graph, synthNode, NULL, 0, NULL, &synthUnit); if (status != noErr) { DisplayAlert(CFSTR("AUGraphGetNodeInfo"), CFSTR("Can't get AUGraph node info"), status); break; } // Initialise status = AUGraphInitialize(graph); if (status != noErr) { DisplayAlert(CFSTR("AUGraphInitialize"), CFSTR("Can't initialize AUGraph"), status); break; } // Start status = AUGraphStart(graph); if (status != noErr) { DisplayAlert(CFSTR("AUGraphStart"), CFSTR("Can't start AUGraph"), status); break; } // Show the graph // CAShow(graph); } while (false); // Change instrument ChangeInstrument(instrument); // Run the application event loop RunApplicationEventLoop(); // Stop the graph AUGraphStop(graph); // Dispose of the graph DisposeAUGraph(graph); // Exit return 0; }
void AudioUnitNode::input(AudioNode &node, UInt32 srcOutputCh, UInt32 inputCh) { ioValidate(node, srcOutputCh, inputCh); checkError(AUGraphConnectNodeInput(node.getAUGraph(), node.getAUNode(), srcOutputCh, getAUNode(), inputCh), "Fail AUGraphConnectNodeInput"); }
JNIEXPORT jint JNICALL Java_com_apple_audio_toolbox_AUGraph_AUGraphConnectNodeInput (JNIEnv *, jclass, jint inGraph, jint inSourceNode, jint inSourceOutputNumber, jint inDestNode, jint inDestInputNumber) { return (jint)AUGraphConnectNodeInput((AUGraph)inGraph, (AUNode)inSourceNode, (UInt32)inSourceOutputNumber, (AUNode)inDestNode, (UInt32)inDestInputNumber); }
bool CCoreAudioGraph::Open(ICoreAudioSource *pSource, AEAudioFormat &format, AudioDeviceID deviceId, bool allowMixing, AudioChannelLayoutTag layoutTag) { AudioStreamBasicDescription fmt = {0}; AudioStreamBasicDescription inputFormat = {0}; AudioStreamBasicDescription outputFormat = {0}; m_deviceId = deviceId; m_allowMixing = allowMixing; OSStatus ret = NewAUGraph(&m_audioGraph); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " "Error create audio grpah. Error = %s", GetError(ret).c_str()); return false; } ret = AUGraphOpen(m_audioGraph); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " "Error open audio grpah. Error = %s", GetError(ret).c_str()); return false; } // get output unit if (m_audioUnit) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " "Error audio unit already open. double call ?"); return false; } m_audioUnit = new CAUOutputDevice(); if (!m_audioUnit->Open(m_audioGraph, kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple)) return false; m_audioUnit->SetBus(GetFreeBus()); m_audioUnit->GetFormatDesc(format, &inputFormat, &fmt); if (!m_audioUnit->EnableInputOuput()) return false; if (!m_audioUnit->SetCurrentDevice(deviceId)) return false; if (allowMixing) { delete m_mixMap; m_mixMap = CCoreAudioMixMap::CreateMixMap(m_audioUnit, format, layoutTag); if (m_mixMap || m_mixMap->IsValid()) { // maximum input channel ber input bus //fmt.mChannelsPerFrame = MAXIMUM_MIXER_CHANNELS; // get output unit if (m_inputUnit) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error mixer unit already open. double call ?"); return false; } m_inputUnit = new CAUOutputDevice(); if (!m_inputUnit->Open(m_audioGraph, kAudioUnitType_FormatConverter, kAudioUnitSubType_AUConverter, kAudioUnitManufacturer_Apple)) return false; if (!m_inputUnit->SetFormat(&inputFormat, kAudioUnitScope_Input, kOutputBus)) return false; if (!m_inputUnit->SetFormat(&fmt, kAudioUnitScope_Output, kOutputBus)) return false; // get mixer unit if (m_mixerUnit) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error mixer unit already open. double call ?"); return false; } m_mixerUnit = new CAUMatrixMixer(); if (!m_mixerUnit->Open(m_audioGraph, kAudioUnitType_Mixer, kAudioUnitSubType_MatrixMixer, kAudioUnitManufacturer_Apple)) return false; // set number of input buses if (!m_mixerUnit->SetInputBusCount(MAX_CONNECTION_LIMIT)) return false; // set number of output buses if (!m_mixerUnit->SetOutputBusCount(1)) return false; if (!m_mixerUnit->SetInputBusFormat(MAX_CONNECTION_LIMIT, &fmt)) return false; if (!m_mixerUnit->SetFormat(&fmt, kAudioUnitScope_Output, kOutputBus)) return false; ret = AUGraphConnectNodeInput(m_audioGraph, m_mixerUnit->GetNode(), 0, m_audioUnit->GetNode(), 0); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " "Error connecting m_m_mixerNode. Error = %s", GetError(ret).c_str()); return false; } m_mixerUnit->SetBus(0); // configure output unit int busNumber = GetFreeBus(); ret = AUGraphConnectNodeInput(m_audioGraph, m_inputUnit->GetNode(), 0, m_mixerUnit->GetNode(), busNumber); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " "Error connecting m_converterNode. Error = %s", GetError(ret).c_str()); return false; } m_inputUnit->SetBus(busNumber); ret = AUGraphUpdate(m_audioGraph, NULL); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " "Error update graph. Error = %s", GetError(ret).c_str()); return false; } ret = AUGraphInitialize(m_audioGraph); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " "Error initialize graph. Error = %s", GetError(ret).c_str()); return false; } // Update format structure to reflect the desired format from the mixer // The output format of the mixer is identical to the input format, except for the channel count fmt.mChannelsPerFrame = m_mixMap->GetOutputChannels(); UInt32 inputNumber = m_inputUnit->GetBus(); int channelOffset = GetMixerChannelOffset(inputNumber); if (!CCoreAudioMixMap::SetMixingMatrix(m_mixerUnit, m_mixMap, &inputFormat, &fmt, channelOffset)) return false; // Regenerate audio format and copy format for the Output AU outputFormat = fmt; } else { outputFormat = inputFormat; } } else { outputFormat = inputFormat; } if (!m_audioUnit->SetFormat(&outputFormat, kAudioUnitScope_Input, kOutputBus)) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " "Error setting input format on audio device. Channel count %d, set it to %d", (int)outputFormat.mChannelsPerFrame, format.m_channelLayout.Count()); outputFormat.mChannelsPerFrame = format.m_channelLayout.Count(); if (!m_audioUnit->SetFormat(&outputFormat, kAudioUnitScope_Input, kOutputBus)) return false; } std::string formatString; // asume we are in dd-wave mode if (!m_inputUnit) { if (!m_audioUnit->SetFormat(&inputFormat, kAudioUnitScope_Output, kInputBus)) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " "Error setting Device Output Stream Format %s", StreamDescriptionToString(inputFormat, formatString)); } } ret = AUGraphUpdate(m_audioGraph, NULL); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " "Error update graph. Error = %s", GetError(ret).c_str()); return false; } AudioStreamBasicDescription inputDesc_end, outputDesc_end; m_audioUnit->GetFormat(&inputDesc_end, kAudioUnitScope_Input, kOutputBus); m_audioUnit->GetFormat(&outputDesc_end, kAudioUnitScope_Output, kInputBus); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Input Stream Format %s", StreamDescriptionToString(inputDesc_end, formatString)); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Output Stream Format %s", StreamDescriptionToString(outputDesc_end, formatString)); if (m_mixerUnit) { m_mixerUnit->GetFormat(&inputDesc_end, kAudioUnitScope_Input, kOutputBus); m_mixerUnit->GetFormat(&outputDesc_end, kAudioUnitScope_Output, kOutputBus); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Input Stream Format %s", StreamDescriptionToString(inputDesc_end, formatString)); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Output Stream Format %s", StreamDescriptionToString(outputDesc_end, formatString)); } if (m_inputUnit) { m_inputUnit->GetFormat(&inputDesc_end, kAudioUnitScope_Input, kOutputBus); m_inputUnit->GetFormat(&outputDesc_end, kAudioUnitScope_Output, kOutputBus); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Input Stream Format %s", StreamDescriptionToString(inputDesc_end, formatString)); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Output Stream Format %s", StreamDescriptionToString(outputDesc_end, formatString)); } ret = AUGraphInitialize(m_audioGraph); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: " "Error initialize graph. Error = %s", GetError(ret).c_str()); return false; } UInt32 bufferFrames = m_audioUnit->GetBufferFrameSize(); if (!m_audioUnit->SetMaxFramesPerSlice(bufferFrames)) return false; SetInputSource(pSource); return Start(); }
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"); }
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; } } }
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 const char *sound_description[NUM_SOUNDS] = { N_("Starting GNU Backgammon"), N_("Exiting GNU Backgammon"), N_("Agree"), N_("Doubling"), N_("Drop"), N_("Chequer movement"),
bool FCoreAudioSoundSource::AttachToAUGraph() { AudioChannel = FindFreeAudioChannel(); OSStatus ErrorStatus = noErr; AUNode DestNode = -1; int32 DestInputNumber = 0; AudioStreamBasicDescription* StreamFormat = NULL; if( Buffer->NumChannels < 3 ) { ErrorStatus = AudioConverterNew( &Buffer->PCMFormat, &AudioDevice->Mixer3DFormat, &CoreAudioConverter ); DestNode = AudioDevice->GetMixer3DNode(); MixerInputNumber = DestInputNumber = AudioDevice->GetFreeMixer3DInput(); uint32 SpatialSetting = ( Buffer->NumChannels == 1 ) ? kSpatializationAlgorithm_SoundField : kSpatializationAlgorithm_StereoPassThrough; AudioUnitSetProperty( AudioDevice->GetMixer3DUnit(), kAudioUnitProperty_SpatializationAlgorithm, kAudioUnitScope_Input, MixerInputNumber, &SpatialSetting, sizeof( SpatialSetting ) ); AudioUnitSetParameter( AudioDevice->GetMixer3DUnit(), k3DMixerParam_Distance, kAudioUnitScope_Input, MixerInputNumber, 1.0f, 0 ); StreamFormat = &AudioDevice->Mixer3DFormat; } else { MixerInputNumber = DestInputNumber = AudioDevice->GetFreeMatrixMixerInput(); DestNode = AudioDevice->GetMatrixMixerNode(); StreamFormat = &AudioDevice->MatrixMixerInputFormat; ErrorStatus = AudioConverterNew( &Buffer->PCMFormat, &AudioDevice->MatrixMixerInputFormat, &CoreAudioConverter ); bool bIs6ChannelOGG = Buffer->NumChannels == 6 && (Buffer->DecompressionState || WaveInstance->WaveData->bDecompressedFromOgg); AudioDevice->SetupMatrixMixerInput( DestInputNumber, bIs6ChannelOGG ); } if( ErrorStatus != noErr ) { UE_LOG(LogCoreAudio, Warning, TEXT("CoreAudioConverter creation failed, error code %d"), ErrorStatus); } int FiltersNeeded = 0; #if EQ_ENABLED bool bNeedEQFilter = IsEQFilterApplied(); if( bNeedEQFilter ) { ++FiltersNeeded; } #else bool bNeedEQFilter = false; #endif #if RADIO_ENABLED bool bNeedRadioFilter = Effects->bRadioAvailable && WaveInstance->bApplyRadioFilter; if( bNeedRadioFilter ) { ++FiltersNeeded; } #else bool bNeedRadioFilter = false; #endif #if REVERB_ENABLED bool bNeedReverbFilter = bReverbApplied; if( bNeedReverbFilter ) { ++FiltersNeeded; } #else bool bNeedReverbFilter = false; #endif if( FiltersNeeded > 0 ) { uint32 BusCount = FiltersNeeded + ( bNeedEQFilter ? 0 : 1 ); // one for each filter, plus one for dry voice if there's no EQ filter // Prepare Voice Merger SAFE_CA_CALL( CreateAudioUnit( kAudioUnitType_Mixer, kAudioUnitSubType_MatrixMixer, kAudioUnitManufacturer_Apple, NULL, NULL, &StreamMergerNode, &StreamMergerUnit ) ); // Set Bus Counts uint32 NumBuses = BusCount; SAFE_CA_CALL( AudioUnitSetProperty( StreamMergerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &NumBuses, sizeof(uint32) ) ); NumBuses = 1; SAFE_CA_CALL( AudioUnitSetProperty( StreamMergerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Output, 0, &NumBuses, sizeof(uint32) ) ); // Set Input Formats for( int32 InputIndex = 0; InputIndex < BusCount; ++InputIndex ) { SAFE_CA_CALL( AudioUnitSetProperty( StreamMergerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, InputIndex, StreamFormat, sizeof( AudioStreamBasicDescription ) ) ); } // Set Output Format SAFE_CA_CALL( AudioUnitSetProperty( StreamMergerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, StreamFormat, sizeof( AudioStreamBasicDescription ) ) ); SAFE_CA_CALL( AudioUnitInitialize( StreamMergerUnit ) ); // Set Master volume SAFE_CA_CALL( AudioUnitSetParameter( StreamMergerUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Global, 0xFFFFFFFF, 1.0, 0 ) ); // Enable Output SAFE_CA_CALL( AudioUnitSetParameter( StreamMergerUnit, kMatrixMixerParam_Enable, kAudioUnitScope_Output, 0, 1.0, 0 ) ); // Set Output volumes for( int32 ChannelIndex = 0; ChannelIndex < StreamFormat->mChannelsPerFrame; ++ChannelIndex ) { SAFE_CA_CALL( AudioUnitSetParameter( StreamMergerUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Output, ChannelIndex, 1.0, 0 ) ); } for( int32 InputIndex = 0; InputIndex < BusCount; ++InputIndex ) { // Enable Input SAFE_CA_CALL( AudioUnitSetParameter( StreamMergerUnit, kMatrixMixerParam_Enable, kAudioUnitScope_Input, InputIndex, 1.0, 0 ) ); } for( int32 ChannelIndex = 0; ChannelIndex < StreamFormat->mChannelsPerFrame; ++ChannelIndex ) { for( int32 InputBusIndex = 0; InputBusIndex < BusCount; ++InputBusIndex ) { int32 InputChannelIndex = InputBusIndex*StreamFormat->mChannelsPerFrame + ChannelIndex; // Set Input Channel Volume SAFE_CA_CALL( AudioUnitSetParameter( StreamMergerUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Input, InputChannelIndex, 1.0, 0 ) ); // Set Crossfade Volume - each input channel goes to specific output channel. The rest of connections is left at zero. SAFE_CA_CALL( AudioUnitSetParameter( StreamMergerUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Global, ( InputChannelIndex << 16 ) | ChannelIndex, 1.0, 0 ) ); } } SAFE_CA_CALL( AUGraphConnectNodeInput( AudioDevice->GetAudioUnitGraph(), StreamMergerNode, 0, DestNode, DestInputNumber ) ); DestNode = StreamMergerNode; DestInputNumber = 0; // Prepare and initialize stream splitter SAFE_CA_CALL( CreateAudioUnit( kAudioUnitType_Mixer, kAudioUnitSubType_MatrixMixer, kAudioUnitManufacturer_Apple, NULL, NULL, &StreamSplitterNode, &StreamSplitterUnit ) ); // Set bus counts NumBuses = 1; SAFE_CA_CALL( AudioUnitSetProperty( StreamSplitterUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &NumBuses, sizeof(uint32) ) ); NumBuses = BusCount; SAFE_CA_CALL( AudioUnitSetProperty( StreamSplitterUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Output, 0, &NumBuses, sizeof(uint32) ) ); // Set Input format SAFE_CA_CALL( AudioUnitSetProperty( StreamSplitterUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, StreamFormat, sizeof( AudioStreamBasicDescription ) ) ); // Set Output formats for( int32 OutputIndex = 0; OutputIndex < BusCount; ++OutputIndex ) { SAFE_CA_CALL( AudioUnitSetProperty( StreamSplitterUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, OutputIndex, StreamFormat, sizeof( AudioStreamBasicDescription ) ) ); } SAFE_CA_CALL( AudioUnitInitialize( StreamSplitterUnit ) ); // Set Master volume SAFE_CA_CALL( AudioUnitSetParameter( StreamSplitterUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Global, 0xFFFFFFFF, 1.0, 0 ) ); // Enable Input SAFE_CA_CALL( AudioUnitSetParameter( StreamSplitterUnit, kMatrixMixerParam_Enable, kAudioUnitScope_Input, 0, 1.0, 0 ) ); // Set Input Volumes for( int32 ChannelIndex = 0; ChannelIndex < StreamFormat->mChannelsPerFrame; ++ChannelIndex ) { SAFE_CA_CALL( AudioUnitSetParameter( StreamSplitterUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Input, ChannelIndex, 1.0, 0 ) ); } for( int32 OutputIndex = 0; OutputIndex < BusCount; ++OutputIndex ) { // Enable Output SAFE_CA_CALL( AudioUnitSetParameter( StreamSplitterUnit, kMatrixMixerParam_Enable, kAudioUnitScope_Output, OutputIndex, 1.0, 0 ) ); } for( int32 ChannelIndex = 0; ChannelIndex < StreamFormat->mChannelsPerFrame; ++ChannelIndex ) { for( int32 OutputBusIndex = 0; OutputBusIndex < BusCount; ++OutputBusIndex ) { int32 OutputChannelIndex = OutputBusIndex*StreamFormat->mChannelsPerFrame + ChannelIndex; // Set Output Channel Volume SAFE_CA_CALL( AudioUnitSetParameter( StreamSplitterUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Output, OutputChannelIndex, 1.0, 0 ) ); // Set Crossfade Volume - each output channel goes from specific input channel. The rest of connections is left at zero. SAFE_CA_CALL( AudioUnitSetParameter( StreamSplitterUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Global, ( ChannelIndex << 16 ) | OutputChannelIndex, 1.0, 0 ) ); } } // Prepare and connect appropriate filters #if EQ_ENABLED if( bNeedEQFilter ) { SAFE_CA_CALL( CreateAndConnectAudioUnit( kAudioUnitType_Effect, kAudioUnitSubType_AUFilter, kAudioUnitManufacturer_Apple, DestNode, DestInputNumber, StreamFormat, StreamFormat, &EQNode, &EQUnit ) ); SAFE_CA_CALL( AUGraphConnectNodeInput( AudioDevice->GetAudioUnitGraph(), StreamSplitterNode, DestInputNumber, EQNode, 0 ) ); } else #endif { // Add direct connection between stream splitter and stream merger, for dry voice SAFE_CA_CALL( AUGraphConnectNodeInput( AudioDevice->GetAudioUnitGraph(), StreamSplitterNode, 0, StreamMergerNode, 0 ) ); // Silencing dry voice (for testing) // for( int32 ChannelIndex = 0; ChannelIndex < StreamFormat->mChannelsPerFrame; ++ChannelIndex ) // { // SAFE_CA_CALL( AudioUnitSetParameter( StreamSplitterUnit, kMatrixMixerParam_Volume, kAudioUnitScope_Output, ChannelIndex, 0.0, 0 ) ); // } // SAFE_CA_CALL( AudioUnitSetParameter( StreamSplitterUnit, kMatrixMixerParam_Enable, kAudioUnitScope_Output, 0, 0.0, 0 ) ); } ++DestInputNumber; #if RADIO_ENABLED if( bNeedRadioFilter ) { SAFE_CA_CALL( CreateAndConnectAudioUnit( kAudioUnitType_Effect, 'Rdio', 'Epic', DestNode, DestInputNumber, StreamFormat, StreamFormat, &RadioNode, &RadioUnit ) ); SAFE_CA_CALL( AUGraphConnectNodeInput( AudioDevice->GetAudioUnitGraph(), StreamSplitterNode, DestInputNumber, RadioNode, 0 ) ); ++DestInputNumber; } #endif #if REVERB_ENABLED if( bNeedReverbFilter ) { SAFE_CA_CALL( CreateAndConnectAudioUnit( kAudioUnitType_Effect, kAudioUnitSubType_MatrixReverb, kAudioUnitManufacturer_Apple, DestNode, DestInputNumber, StreamFormat, StreamFormat, &ReverbNode, &ReverbUnit ) ); SAFE_CA_CALL( AUGraphConnectNodeInput( AudioDevice->GetAudioUnitGraph(), StreamSplitterNode, DestInputNumber, ReverbNode, 0 ) ); ++DestInputNumber; } #endif DestNode = StreamSplitterNode; DestInputNumber = 0; } SAFE_CA_CALL( CreateAndConnectAudioUnit( kAudioUnitType_FormatConverter, kAudioUnitSubType_AUConverter, kAudioUnitManufacturer_Apple, DestNode, DestInputNumber, StreamFormat, StreamFormat, &SourceNode, &SourceUnit ) ); if( ErrorStatus == noErr ) { AURenderCallbackStruct Input; Input.inputProc = &CoreAudioRenderCallback; Input.inputProcRefCon = this; SAFE_CA_CALL( AudioUnitSetProperty( SourceUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &Input, sizeof( Input ) ) ); SAFE_CA_CALL( AUGraphUpdate( AudioDevice->GetAudioUnitGraph(), NULL ) ); GAudioChannels[AudioChannel] = this; } return ErrorStatus == noErr; }
void I_InitMusic (void) { #ifdef UNIX struct stat buf; if(stat("/etc/timidity.cfg", &buf) && stat("/etc/timidity/timidity.cfg", &buf)) Args.AppendArg("-nomusic"); #endif if(Args.CheckParm("-nomusic")) { Printf (PRINT_HIGH, "I_InitMusic: Music playback disabled\n"); return; } #ifdef OSX NewAUGraph(&graph); ComponentDescription d; d.componentType = kAudioUnitType_MusicDevice; d.componentSubType = kAudioUnitSubType_DLSSynth; d.componentManufacturer = kAudioUnitManufacturer_Apple; d.componentFlags = 0; d.componentFlagsMask = 0; AUGraphNewNode(graph, &d, 0, NULL, &synth); d.componentType = kAudioUnitType_Output; d.componentSubType = kAudioUnitSubType_DefaultOutput; d.componentManufacturer = kAudioUnitManufacturer_Apple; d.componentFlags = 0; d.componentFlagsMask = 0; AUGraphNewNode(graph, &d, 0, NULL, &output); if(AUGraphConnectNodeInput(graph, synth, 0, output, 0) != noErr) { Printf (PRINT_HIGH, "I_InitMusic: AUGraphConnectNodeInput failed\n"); return; } if(AUGraphOpen(graph) != noErr) { Printf (PRINT_HIGH, "I_InitMusic: AUGraphOpen failed\n"); return; } if(AUGraphInitialize(graph) != noErr) { Printf (PRINT_HIGH, "I_InitMusic: AUGraphInitialize failed\n"); return; } if(AUGraphGetNodeInfo(graph, output, NULL, NULL, NULL, &unit) != noErr) { Printf (PRINT_HIGH, "I_InitMusic: AUGraphGetNodeInfo failed\n"); return; } if(NewMusicPlayer(&player) != noErr) { Printf (PRINT_HIGH, "I_InitMusic: Music player creation failed using AudioToolbox\n"); return; } Printf (PRINT_HIGH, "I_InitMusic: Music playback enabled using AudioToolbox\n"); #else Printf (PRINT_HIGH, "I_InitMusic: Music playback enabled\n"); #endif music_initialized = 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); }
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; }
/** * 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 } }
MidiDevice * openMidiDevice (int errorLevel, const char *device) { MidiDevice *midi; int result; AUNode synthNode, outNode; ComponentDescription cd; UInt32 propVal; if (!(midi = malloc(sizeof(*midi)))) { logMallocError(); return NULL; } /* Create a graph with a software synth and a default output unit. */ cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; if ((result = NewAUGraph(&midi->graph)) != noErr) { logMessage(errorLevel, "Can't create audio graph component: %d", result); goto err; } cd.componentType = kAudioUnitType_MusicDevice; cd.componentSubType = kAudioUnitSubType_DLSSynth; if ((result = AUGraphNewNode(midi->graph, &cd, 0, NULL, &synthNode)) != noErr) { logMessage(errorLevel, "Can't create software synthersizer component: %d", result); goto err; } cd.componentType = kAudioUnitType_Output; cd.componentSubType = kAudioUnitSubType_DefaultOutput; if ((result = AUGraphNewNode(midi->graph, &cd, 0, NULL, &outNode)) != noErr) { logMessage(errorLevel, "Can't create default output audio component: %d", result); goto err; } if ((result = AUGraphOpen(midi->graph)) != noErr) { logMessage(errorLevel, "Can't open audio graph component: %d", result); goto err; } if ((result = AUGraphConnectNodeInput(midi->graph, synthNode, 0, outNode, 0)) != noErr) { logMessage(errorLevel, "Can't connect synth audio component to output: %d", result); goto err; } if ((result = AUGraphGetNodeInfo(midi->graph, synthNode, 0, 0, 0, &midi->synth)) != noErr) { logMessage(errorLevel, "Can't get audio component for software synth: %d", result); goto err; } if ((result = AUGraphInitialize(midi->graph)) != noErr) { logMessage(errorLevel, "Can't initialize audio graph: %d", result); goto err; } /* Turn off the reverb. The value range is -120 to 40 dB. */ propVal = false; if ((result = AudioUnitSetProperty(midi->synth, kMusicDeviceProperty_UsesInternalReverb, kAudioUnitScope_Global, 0, &propVal, sizeof(propVal))) != noErr) { /* So, having reverb isn't that critical, is it? */ logMessage(LOG_DEBUG, "Can't turn of software synth reverb: %d", result); } /* TODO: Maybe just start the graph when we are going to use it? */ if ((result = AUGraphStart(midi->graph)) != noErr) { logMessage(errorLevel, "Can't start audio graph component: %d", result); goto err; } return midi; err: if (midi->graph) DisposeAUGraph(midi->graph); free(midi); return NULL; }
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(); }
bool CCoreAudioGraph::Open(ICoreAudioSource *pSource, AEAudioFormat &format, bool allowMixing) { OSStatus ret; AudioStreamBasicDescription inputFormat; AudioStreamBasicDescription outputFormat; m_allowMixing = allowMixing; ret = NewAUGraph(&m_audioGraph); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error create audio grpah. Error = %s", GetError(ret).c_str()); return false; } ret = AUGraphOpen(m_audioGraph); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error open audio grpah. Error = %s", GetError(ret).c_str()); return false; } // get output unit if (m_audioUnit) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error audio unit already open. double call ?"); return false; } m_audioUnit = new CAUOutputDevice(); if (!m_audioUnit->Open(m_audioGraph, kAudioUnitType_Output, kAudioUnitSubType_RemoteIO, kAudioUnitManufacturer_Apple)) return false; if (!m_audioUnit->EnableInputOuput()) return false; m_audioUnit->GetFormatDesc(format, &inputFormat); //if(!allowMixing) //{ if (!m_audioUnit->SetFormat(&inputFormat, kAudioUnitScope_Input, kOutputBus)) return false; if (!m_audioUnit->SetFormat(&inputFormat, kAudioUnitScope_Output, kInputBus)) return false; //} if (allowMixing) { // get mixer unit if (m_mixerUnit) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error mixer unit already open. double call ?"); return false; } m_mixerUnit = new CAUMultiChannelMixer(); if (!m_mixerUnit->Open(m_audioGraph, kAudioUnitType_Mixer, kAudioUnitSubType_MultiChannelMixer, kAudioUnitManufacturer_Apple)) return false; // set number of input buses if (!m_mixerUnit->SetInputBusCount(MAX_CONNECTION_LIMIT)) return false; //if(!m_mixerUnit->SetFormat(&fmt, kAudioUnitScope_Output, kOutputBus)) // return false; m_mixerUnit->SetBus(0); if (!m_audioUnit->GetFormat(&outputFormat, kAudioUnitScope_Input, kOutputBus)) return false; /* if(!m_mixerUnit->SetInputBusFormat(MAX_CONNECTION_LIMIT, &outputFormat)) return false; */ ret = AUGraphConnectNodeInput(m_audioGraph, m_mixerUnit->GetNode(), 0, m_audioUnit->GetNode(), 0); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error connecting m_m_mixerNode. Error = %s", GetError(ret).c_str()); return false; } // get output unit if (m_inputUnit) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error mixer unit already open. double call ?"); return false; } m_inputUnit = new CAUOutputDevice(); if (!m_inputUnit->Open(m_audioGraph, kAudioUnitType_FormatConverter, kAudioUnitSubType_AUConverter, kAudioUnitManufacturer_Apple)) return false; if (!m_inputUnit->SetFormat(&inputFormat, kAudioUnitScope_Input, kOutputBus)) return false; /* if(!m_inputUnit->SetFormat(&outputFormat, kAudioUnitScope_Output, kOutputBus)) return false; */ // configure output unit int busNumber = GetFreeBus(); ret = AUGraphConnectNodeInput(m_audioGraph, m_inputUnit->GetNode(), 0, m_mixerUnit->GetNode(), busNumber); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error connecting m_converterNode. Error = %s", GetError(ret).c_str()); return false; } m_inputUnit->SetBus(busNumber); ret = AUGraphUpdate(m_audioGraph, NULL); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error update graph. Error = %s", GetError(ret).c_str()); return false; } ret = AUGraphInitialize(m_audioGraph); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error initialize graph. Error = %s", GetError(ret).c_str()); return false; } // Regenerate audio format and copy format for the Output AU } ret = AUGraphUpdate(m_audioGraph, NULL); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error update graph. Error = %s", GetError(ret).c_str()); return false; } std::string formatString; AudioStreamBasicDescription inputDesc_end, outputDesc_end; m_audioUnit->GetFormat(&inputDesc_end, kAudioUnitScope_Input, kOutputBus); m_audioUnit->GetFormat(&outputDesc_end, kAudioUnitScope_Output, kInputBus); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Input Stream Format %s", StreamDescriptionToString(inputDesc_end, formatString)); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Output Stream Format %s", StreamDescriptionToString(outputDesc_end, formatString)); if (m_mixerUnit) { m_mixerUnit->GetFormat(&inputDesc_end, kAudioUnitScope_Input, kOutputBus); m_mixerUnit->GetFormat(&outputDesc_end, kAudioUnitScope_Output, kOutputBus); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Input Stream Format %s", StreamDescriptionToString(inputDesc_end, formatString)); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Output Stream Format %s", StreamDescriptionToString(outputDesc_end, formatString)); } if (m_inputUnit) { m_inputUnit->GetFormat(&inputDesc_end, kAudioUnitScope_Input, kOutputBus); m_inputUnit->GetFormat(&outputDesc_end, kAudioUnitScope_Output, kOutputBus); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Input Stream Format %s", StreamDescriptionToString(inputDesc_end, formatString)); CLog::Log(LOGINFO, "CCoreAudioGraph::Open: Output Stream Format %s", StreamDescriptionToString(outputDesc_end, formatString)); } ret = AUGraphInitialize(m_audioGraph); if (ret) { CLog::Log(LOGERROR, "CCoreAudioGraph::Open: Error initialize graph. Error = %s", GetError(ret).c_str()); return false; } UInt32 bufferFrames = m_audioUnit->GetBufferFrameSize(); m_audioUnit->SetMaxFramesPerSlice(bufferFrames); if (m_inputUnit) m_inputUnit->SetMaxFramesPerSlice(bufferFrames); SetInputSource(pSource); ShowGraph(); return Start(); }
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; }
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); }
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; }