private static void CheckGraphError(AUGraphError error, string msg) { if (error != AUGraphError.OK) { throw new AudioSystemInternalException(msg + " [Error=" + error + "]."); } }
void SetupAUGraph() { graph = new AUGraph(); AudioComponentDescription mixerDescription = new AudioComponentDescription(); mixerDescription.ComponentType = AudioComponentType.Mixer; mixerDescription.ComponentSubType = (int)AudioTypeMixer.MultiChannel; mixerDescription.ComponentFlags = 0; mixerDescription.ComponentFlagsMask = 0; mixerDescription.ComponentManufacturer = AudioComponentManufacturerType.Apple; AudioComponentDescription outputDesciption = new AudioComponentDescription(); outputDesciption.ComponentType = AudioComponentType.Output; outputDesciption.ComponentSubType = (int)AudioTypeOutput.System; outputDesciption.ComponentFlags = 0; outputDesciption.ComponentFlagsMask = 0; outputDesciption.ComponentManufacturer = AudioComponentManufacturerType.Apple; int mixerNode = graph.AddNode(mixerDescription); int outputNode = graph.AddNode(outputDesciption); AUGraphError error = graph.ConnnectNodeInput(mixerNode, 0, outputNode, 0); Assert.AreEqual(AUGraphError.OK, error); graph.Open(); mMixer = graph.GetNodeInfo(mixerNode); AudioUnitStatus status = mMixer.SetElementCount(AudioUnitScopeType.Input, 0); Assert.AreEqual(AudioUnitStatus.OK, status); }
public AudioUnit?GetNodeInfo(int node, out AudioComponentDescription cd, out AUGraphError error) { error = AUGraphNodeInfo(GetCheckedHandle(), node, out cd, out var ptr); if (error != AUGraphError.OK || ptr == IntPtr.Zero) { return(null); } return(new AudioUnit(ptr, false)); }
void restartAudioProcessingGraph() { AUGraphError result = AUGraphError.OK; if (processingGraph != null) { result = processingGraph.Start(); } if (result != AUGraphError.OK) { throw new Exception("Unable to restart the audio processing graph. Error code: " + result); } }
// AudioComponentDescription struct in only correctly fixed for unified // Following current Api behaviour of returning an AudioUnit instead of an error public AudioUnit GetNodeInfo(int node, out AudioComponentDescription cd, out AUGraphError error) { if (Handle == IntPtr.Zero) { throw new ObjectDisposedException("AUGraph"); } IntPtr ptr; error = AUGraphNodeInfo(Handle, node, out cd, out ptr); if (error != AUGraphError.OK || ptr == IntPtr.Zero) { return(null); } return(new AudioUnit(ptr)); }
bool createAUGraph() { AUGraphError result = 0; int samplerNode, ioNode; var cd = new AudioComponentDescription() { ComponentManufacturer = AudioComponentManufacturerType.Apple, ComponentFlags = 0, ComponentFlagsMask = 0 }; processingGraph = new AUGraph(); cd.ComponentType = AudioComponentType.MusicDevice; cd.ComponentSubType = (int)AudioTypeMusicDevice.Sampler; //0x73616d70; samplerNode = processingGraph.AddNode(cd); cd.ComponentType = AudioComponentType.Output; cd.ComponentSubType = (int)AudioTypeOutput.Remote; //0x72696f63; ioNode = processingGraph.AddNode(cd); processingGraph.Open(); result = processingGraph.ConnnectNodeInput(samplerNode, 0, ioNode, 0); if (result != AUGraphError.OK) { throw new Exception("Unable to open the audio processing graph. Error code: " + result); } samplerUnit = processingGraph.GetNodeInfo(samplerNode); ioUnit = processingGraph.GetNodeInfo(ioNode); return(true); }
private static void CheckGraphError(AUGraphError error, string msg) { if (error != AUGraphError.OK) throw new AudioSystemInternalException(msg + " [Error=" + error + "]."); }
void StreamPropertyListenerProc(object sender, PropertyFoundEventArgs args) { if (args.Property == AudioFileStreamProperty.DataFormat) { dataFormat = audioFileStream.DataFormat; return; } if (args.Property != AudioFileStreamProperty.ReadyToProducePackets) { return; } if (audioQueue != null) { // TODO: dispose old queue and its tap throw new NotImplementedException(); } audioQueue = new OutputAudioQueue(dataFormat); audioQueue.BufferCompleted += HandleBufferCompleted; AudioQueueStatus status; aqTap = audioQueue.CreateProcessingTap(TapProc, AudioQueueProcessingTapFlags.PreEffects, out status); if (status != AudioQueueStatus.Ok) { throw new ApplicationException("Could not create AQ tap"); } // create an augraph to process in the tap. needs to convert from tapFormat to effect format and back /* note: this is invalidname's recipe to do an in-place effect when a format conversion is needed * before and after the effect, usually because effects want floats, and everything else in iOS * core audio works with ints (or, in rare cases, fixed-point). * the graph looks like this: * [render-callback] -> [converter] -> [effect] -> [converter] -> [generic-output] * prior to calling AudioUnitRender() on generic-output the ioData to a pointer that render-callback * knows about, and NULLs the ioData provided to AudioUnitRender(). the NULL tells generic-output to * pull from its upstream units (ie, the augraph), and copying off the ioData pointer allows the * render-callback to provide it to the front of the stream. in some locales, this kind of shell game * is described as "batshit crazy", but it seems to work pretty well in practice. */ auGraph = new AUGraph(); auGraph.Open(); int effectNode = auGraph.AddNode(AudioComponentDescription.CreateConverter(AudioTypeConverter.NewTimePitch)); effectUnit = auGraph.GetNodeInfo(effectNode); int convertToEffectNode = auGraph.AddNode(AudioComponentDescription.CreateConverter(AudioTypeConverter.AU)); convertToEffectUnit = auGraph.GetNodeInfo(convertToEffectNode); int convertFromEffectNode = auGraph.AddNode(AudioComponentDescription.CreateConverter(AudioTypeConverter.AU)); convertFromEffectUnit = auGraph.GetNodeInfo(convertFromEffectNode); int genericOutputNode = auGraph.AddNode(AudioComponentDescription.CreateOutput(AudioTypeOutput.Generic)); genericOutputUnit = auGraph.GetNodeInfo(genericOutputNode); // set the format conversions throughout the graph AudioStreamBasicDescription effectFormat = effectUnit.GetAudioFormat(AudioUnitScopeType.Output); var tapFormat = aqTap.ProcessingFormat; convertToEffectUnit.SetAudioFormat(tapFormat, AudioUnitScopeType.Input); convertToEffectUnit.SetAudioFormat(effectFormat, AudioUnitScopeType.Output); convertFromEffectUnit.SetAudioFormat(effectFormat, AudioUnitScopeType.Input); convertFromEffectUnit.SetAudioFormat(tapFormat, AudioUnitScopeType.Output); genericOutputUnit.SetAudioFormat(tapFormat, AudioUnitScopeType.Input); genericOutputUnit.SetAudioFormat(tapFormat, AudioUnitScopeType.Output); // set maximum fames per slice higher (4096) so we don't get kAudioUnitErr_TooManyFramesToProcess const uint maxFramesPerSlice = 4096; if (convertToEffectUnit.SetMaximumFramesPerSlice(maxFramesPerSlice, AudioUnitScopeType.Global) != AudioUnitStatus.OK) { throw new ApplicationException(); } if (effectUnit.SetMaximumFramesPerSlice(maxFramesPerSlice, AudioUnitScopeType.Global) != AudioUnitStatus.OK) { throw new ApplicationException(); } if (convertFromEffectUnit.SetMaximumFramesPerSlice(maxFramesPerSlice, AudioUnitScopeType.Global) != AudioUnitStatus.OK) { throw new ApplicationException(); } if (genericOutputUnit.SetMaximumFramesPerSlice(maxFramesPerSlice, AudioUnitScopeType.Global) != AudioUnitStatus.OK) { throw new ApplicationException(); } // connect the nodes AUGraphError err = auGraph.ConnnectNodeInput(convertToEffectNode, 0, effectNode, 0); if (err != AUGraphError.OK) { throw new InvalidOperationException(); } err = auGraph.ConnnectNodeInput(effectNode, 0, convertFromEffectNode, 0); if (err != AUGraphError.OK) { throw new InvalidOperationException(); } err = auGraph.ConnnectNodeInput(convertFromEffectNode, 0, genericOutputNode, 0); if (err != AUGraphError.OK) { throw new InvalidOperationException(); } renderTimeStamp.SampleTime = 0; renderTimeStamp.Flags = AudioTimeStamp.AtsFlags.SampleTimeValid; // set up the callback into the first convert unit if (convertToEffectUnit.SetRenderCallback(ConvertInputRenderCallback, AudioUnitScopeType.Global) != AudioUnitStatus.NoError) { throw new ApplicationException(); } var res = auGraph.Initialize(); if (res != AUGraphError.OK) { throw new ApplicationException(); } }
// AudioComponentDescription struct in only correctly fixed for unified // Following current Api behaviour of returning an AudioUnit instead of an error public AudioUnit GetNodeInfo (int node, out AudioComponentDescription cd, out AUGraphError error) { if (Handle == IntPtr.Zero) throw new ObjectDisposedException ("AUGraph"); IntPtr ptr; error = AUGraphNodeInfo (Handle, node, out cd, out ptr); if (error != AUGraphError.OK || ptr == IntPtr.Zero) return null; return new AudioUnit (ptr); }