AVAudioEngine

RSS for tag

Use a group of connected audio node objects to generate and process audio signals and perform audio input and output.

Posts under AVAudioEngine tag

200 Posts

Post

Replies

Boosts

Views

Activity

If not AVMIDIRecorder, then what?
For AVAudioPlayer, there is corresponding AVAudioRecorder. For AVMIDIPLayer, I found nothing for recording from the system's active MIDI input device. Can I record midi events from the system’s active input midi device, without resolving to low level CoreMidi? After configuring AVAudioUnitSampler with just a few lines of code, import AVFoundation var engine = AVAudioEngine() let unit = AVAudioUnitSampler() engine.attach(unit) engine.connect(unit, to: engine.outputNode, format: engine.outputNode.outputFormat (forBus:0)) try! unit.loadInstrument(at:sndurl) //url to .sf2 file try! engine.start() I could send midi events programmatically. // feeding AVAudioUnitMIDIInstrument with midi data let range = (0..<100) let midiStart = range.map { _ in UInt8.random(in: 70...90) } let midiStop = [0] + midiStart let times = range.map { _ in TimeInterval.random(in: 0...100) * 0.3 } for i in range {     DispatchQueue.main.asyncAfter(deadline: .now()+TimeInterval(times[i])){         unit.stopNote(midiStop[i], onChannel: 1)         unit.startNote(midiStart[i], withVelocity: 127, onChannel: 1)     } } But instead, I need to send midi events from a midi instrument, and tap to them for recording.
1
0
1.4k
Dec ’22
AirPods Pro inward facing microphone
I'm unclear on how to access the inward facing microphone in the AirPods Pro (not the outward facing one). If this is possible, can you point me in the right direction? More context is that there is a ticking noise coming a spasm inside someone's ears that I'd like to try canceling for them. The standard AirPods Pro noise cancellation modes don't have any effect on the sound. I know latency may be too high to do this on the phone with a custom app, but thought if I could reach the point of that being the problem, then I could experiment with predictive algorithms. Thank you in advance for ideas or recommendations.
1
0
1.5k
Nov ’22
AVAudioEngine setup doesn't work with iPhone 14 Pro + Airpods Pro combination
I have an AVAudioEngine setup with VoiceProcessingEnabled that takes the input from mic and plays it on speaker. This works great with Airpods on other iPhone models except iPhone 14 (specifically tested on iPhone 14 Pro). In case of iPhone 14 Pro, there is no audio on the speaker at all. I am linking to a minimal sample app below to reproduce the issue. Please run this sample on iPhone 11 using Airpods Pro you will hear yourself speaking. But when you run the app on iPhone 14 Pro with Airpods Pro connected, you can't hear yourself. Any help will be appreciated. Cheers Sample app: https://www.icloud.com/iclouddrive/07bC_sAZW8MAA2u5lHeHOoFPg#AudioEngineAirpodsTest
0
0
965
Nov ’22
Airpods actual audio latency is differ from AVAudioengine.session prediction and changes over time
Hi, I am building a realtime drum practise tool which listens to the players' practice and provides visual feedback on their accuracy. I use AVAudioSourceNode and AVAudioSinkNode for playing audio and for listening to player practise. Precious timing is the most important part of our app. To optimise audio latency I set PreferredIOBufferDuration to 64/48000sec (~1.33ms). My preferences work fine with builtin or wired audio devices. In these cases we can easily estimate the actual audio latency. However we would like to support Apple airPods (or other bluetooth earbuds) as well, but it seems to be impossible to predict the actual audio latency. let bufferSize: UInt32 = 64 let sampleRate: Double = 48000 let bufferDuration = TimeInterval(Double(bufferSize) / sampleRate) try? session.setCategory(AVAudioSession.Category.playAndRecord, options: [.defaultToSpeaker, .mixWithOthers, .allowBluetoothA2DP])     try? session.setPreferredSampleRate(Double(sampleRate))     try? session.setPreferredIOBufferDuration(bufferDuration)     try? session.setActive(true, options: .notifyOthersOnDeactivation) I use iPhone 12 mini and airPods 2 for testing. (Input always have to be the phone's builtin mic) let input = session.inputLatency // 2.438ms let output = session.outputLatency // 160.667ms let buffer = session.ioBufferDuration // 1.333ms let estimated = input + output + buffer * 2 // 165.771 session.outputLatency returns ca 160ms for my airPods. With the basic calculation above I can estimate a latency of 165.771ms, but when I measure the actual latency (time difference between heard and played sound ) I get significantly different values. If I connect my airPods and start playing immediately, the actual measured latency is ca 215-220ms at first, but it is continuously decreasing over time. After about 20-30mins of measuring the actual latency is around 155-160ms (just like the value that the session returns). However if I am using my airPods for a while before I start the measurement, the actual latency starts from ca 180ms (and decreasing over time the same way). On older iOS devices these differences are even larger. It feels like bluetooth connection needs to "warm up" or something. My questions would be: Is there any way to have a relatively constant audio latency with bluetooth devices? I thought maybe it depends on the actual bandwidth but I couldn't find anything on this topic. Can bandwidth change over time? Can I control it? I guess airPods support AAC codec. Is there any way to force them to use SBC? Does SBC codec work with lower latency? What is the best audioengine setting to support bluetooth devices with the lowest latency? Any other suggestion? Thank you
3
0
8.5k
Oct ’22
Sound decibel recognition
Hi Community Members, We tried to find the particular sound through the microphone. We used PKCCheck to detect the sound decibel. we detect the sound based on the number of dB values per second we receive and add some logic over it to get the result, but when we have continuous sound like an alarm we can't detect it as the gap between the sound is very less. Any suggestion on libraries to achieve this. Also whether we can achieve this thru Frequency & Amplitude method. Please advise.
0
0
1.1k
Oct ’22
How to play .caf file
I tried to change my code from let urlString = Bundle.main.path(forResource: "X", ofType: "mp3")! to let urlString = Bundle.main.path(forResource: "X", ofType: "caf")! after I already uploaded the file. But it throws a fatal error: Unexpectedly found nil while unwrapping an Optional value I double check the filename and it's correct. and the caf file does play.
1
0
2.9k
Sep ’22
iOS opus codec issue. Webrtc RTCAudioTrack always starts the audio with 2 seconds delay. [aurioc] AURemoteIO.cpp:1128 failed: -66635
I'm trying to send the audio track in the webrtc app. I create the audio track like this: private var factory: RTCPeerConnectionFactory = RTCPeerConnectionFactory(encoderFactory: RTCDefaultVideoEncoderFactory(), decoderFactory: RTCDefaultVideoDecoderFactory()) .... let audioTrack = factory.audioTrack(withTrackId: "ARDAMSa0") if mediaStream == nil { self.mediaStream = self.factory.mediaStream(withStreamId: "0") } self.mediaStream.addAudioTrack(audioTrack) Then I add it to peerConnection the usual way. The problem is my audio starts with some delay (2 seconds). I hear it on another peer in almost 2 seconds. Video starts immediately. The connection is perfect. I see an error log: [aurioc] AURemoteIO.cpp:1128 failed: -66635 (enable 3, outf< 1 ch, 48000 Hz, Int16> inf< 1 ch, 48000 Hz, Int16>) In the SDP offer I see that the audio codec is "opus", channels=2, clockRate=48000, which seems completely fine. Question: Is this opus codec is a problem for iOS? is there any extra RTCAudioSession steps I have to do to be able to start the audio immediately? I tried: RTCAudioSession.sharedInstance().setPreferredIOBufferDuration(0.005) Also I tried setting RTCAudioSession to various categories. Nothing helps. There's still a lag at the start. I'm not even sure what it's potentially connected with. I'm testing on iPhone 11, 12, iOS 15.6.1. Tried multiple webrtc branches. (m88, m90+), all the same. Any ideas appreciated. Thanks
0
1
2.2k
Sep ’22
Playing Audio
So I have successfully triggered a PTT notification, but when I try to play audio – any audio – it doesn't play. Seems to be an issue with initiating my AVAudioSession. If I do not initiate it, the sound plays (outside of the didActivateAudioSession; such as on view did load), so I know that it's not the audio playing code. For some reason, the AVAudioSession is not allowing me to play sound. Even when I put "PlayandRecord" and when I put "mix" in the options
2
0
1.6k
Sep ’22
AUAudioUnit – Impossible to handle frame count limitation in render?
Summary: I've created an AUAudioUnit to host some third party signal processing code and am running into a edge case limitation where I can only process and supply output audio data (from the internalRenderBlock) if it's an exact multiple of a specific number of frames. More Detail: This third party code ONLY works with exactly 10ms of data at time. For example, say with 48khz audio, it only accepts 480 frames on each processing function call. If the AUAudioUnit's internalRenderBlock is called with 1024 frames as the frame count, I can use the pullInputBlock to get 480 frames, process it, another 480 frames, and process that, but what should I then do with the remaining 64 frames? Possible Solutions Foiled: a) It seems there's no way to indicate to the host that I have only consumed 960 frames and will only be supplying 960 frames of output. I thought perhaps the host would observe that if the outputData ABL buffers have less than the frame count passed into the internalRenderBlock, that it might appropriately advance the timestamp only by that much the next time time around, but it does not. So it's required that all the audio be processed before the block returns, but I can only do that if the block is requested to handle exactly a multiple of 10ms of data. b) I can't buffer up the "remainder" input and process it on the next internalRenderBlock cycle because all of the output must be provided on return as discussed in A. c) As an alternative, I see no way to have the unit explicitly indicate to the host, how many frames the unit can process at a time. maximumFramesToRender is the host telling the unit (not the reverse), and either way it's a maximum only, not a minumum as well. What can I do?
1
0
2.2k
Aug ’22
App Crash during toggle between Speaker to bluetooth headphone.
We have developed iOS app using WebRTC and ARKit for the video communication. We have the option to toggle between headphone and speaker. We are facing an app crash when bluetooth headphone is connected and the user tries to toggle between speaker and headphone continuously. Also while toggle between speaker and headphone it throws log in console ARSessionDelegate is retaining 11 ARFrames. This can lead to future camera frames being dropped. Following is the crash : Fatal Exception: com.apple.coreaudio.avfaudio required condition is false: nil == owningEngine || GetEngine() == owningEngine Following are the code snippet : func headphoneOn() -> Bool {      audioSession.lockForConfiguration()      var bluetoothPort : AVAudioSessionPortDescription? = nil      var headphonePort : AVAudioSessionPortDescription? = nil      var inbuiltMicPort : AVAudioSessionPortDescription? = nil            if let availableInputs = AVAudioSession.sharedInstance().availableInputs {        for inputDevice in availableInputs {          if inputDevice.portType == .builtInMic {           inbuiltMicPort = inputDevice         } else if inputDevice.portType == .headsetMic || inputDevice.portType == .headphones {           headphonePort = inputDevice         } else if inputDevice.portType == .bluetoothHFP || inputDevice.portType == .bluetoothA2DP || inputDevice.portType == .bluetoothLE {           bluetoothPort = inputDevice         }       }     }            do {        try audioSession.overrideOutputAudioPort(AVAudioSession.PortOverride.none)        if let bluetoothPort = bluetoothPort {          try audioSession.setPreferredInput(bluetoothPort)          try audioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue)          audioSession.unlockForConfiguration()          return true       } else if let headphonePort = headphonePort {          try audioSession.setPreferredInput(headphonePort)          try audioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue)          audioSession.unlockForConfiguration()          return true       } else if let inbuiltMicPort = inbuiltMicPort {          try audioSession.setMode(AVAudioSession.Mode.default.rawValue)          try audioSession.setPreferredInput(inbuiltMicPort)          audioSession.unlockForConfiguration()          return true       } else {          audioSession.unlockForConfiguration()          return false       }             } catch let error as NSError {        debugPrint("#configureAudioSessionToSpeaker Error \(error.localizedDescription)")        audioSession.unlockForConfiguration()        return false     }         } func speakerOn() -> Bool {      audioSession.lockForConfiguration()      var inbuiltSpeakerPort : AVAudioSessionPortDescription? = nil            if let availableInputs = AVAudioSession.sharedInstance().availableInputs {        for inputDevice in availableInputs {          if inputDevice.portType == .builtInSpeaker {           inbuiltSpeakerPort = inputDevice         }       }     }      do { ///Audio Session: Set on Speaker        if let inbuiltSpeakerPort = inbuiltSpeakerPort {          try audioSession.setPreferredInput(inbuiltSpeakerPort)       }        try audioSession.setMode(AVAudioSession.Mode.videoChat.rawValue)        try audioSession.overrideOutputAudioPort(.speaker)        audioSession.unlockForConfiguration()        return true             } catch let error as NSError {        debugPrint("#configureAudioSessionToSpeaker Error \(error.localizedDescription)")        audioSession.unlockForConfiguration()        return false             }   } Any help will be appreciated to solve this crash issue.
2
0
2.0k
Aug ’22
AVAudioEngine exception - required condition is false format.sampleRate == hwFormat.sampleRate
I see in Crashlytics few users are getting this exception when connecting the inputNode to mainMixerNode in AVAudioEngine: Fatal Exception: com.apple.coreaudio.avfaudio required condition is false: format.sampleRate == hwFormat.sampleRate Here is my code: self.engine = AVAudioEngine() let format = engine.inputNode.inputFormat(forBus: 0) //main mixer node is connected to output node by default engine.connect(self.engine.inputNode, to: self.engine.mainMixerNode, format: format) Just want to understand how can this error occur and what is the right fix?
2
1
3.1k
Aug ’22
Am unable to add an AVAudioMixerNode to downsize my recording
Am at the beginning of a voice recording app. I store incoming voice data into a buffer array, and write 50 of them to a file. The code works fine, Sample One. However, I would like the recorded files to be smaller. So here I try to add an AVAudioMixer to downsize the sampling. But this code sample gives me two errors. Sample Two The first error I get is when I call audioEngine.attach(downMixer). The debugger gives me nine of these errors: throwing -10878 The second error is a crash when I try to write to audioFile. Of course they might all be related, so am looking to include the mixer successfully first. But I do need help as I am just trying to piece these all together from tutorials, and when it comes to audio, I know less than anything else. Sample One //these two lines are in the init of the class that contains this function... node = audioEngine.inputNode recordingFormat = node.inputFormat(forBus: 0) func startRecording() { audioBuffs = [] x = -1 node.installTap(onBus: 0, bufferSize: 8192, format: recordingFormat, block: { [self] (buffer, _) in x += 1 audioBuffs.append(buffer) if x >= 50 { audioFile = makeFile(format: recordingFormat, index: fileCount) mainView?.setLabelText(tag: 3, text: "fileIndex = \(fileCount)") fileCount += 1 for i in 0...49 { do { try audioFile!.write(from: audioBuffs[i]); } catch { mainView?.setLabelText(tag: 4, text: "write error") stopRecording() } } ...cleanup buffer code } }) audioEngine.prepare() do { try audioEngine.start() } catch let error { print ("oh catch \(error)") } } Sample Two //these two lines are in the init of the class that contains this function node = audioEngine.inputNode recordingFormat = node.inputFormat(forBus: 0) func startRecording() { audioBuffs = [] x = -1 // new code let format16KHzMono = AVAudioFormat.init(commonFormat: AVAudioCommonFormat.pcmFormatInt16, sampleRate: 11025.0, channels: 1, interleaved: true) let downMixer = AVAudioMixerNode() audioEngine.attach(downMixer) // installTap on the mixer rather than the node downMixer.installTap(onBus: 0, bufferSize: 8192, format: format16KHzMono, block: { [self] (buffer, _) in x += 1 audioBuffs.append(buffer) if x >= 50 { // use a different format in creating the audioFile audioFile = makeFile(format: format16KHzMono!, index: fileCount) mainView?.setLabelText(tag: 3, text: "fileIndex = \(fileCount)") fileCount += 1 for i in 0...49 { do { try audioFile!.write(from: audioBuffs[i]); } catch { stopRecording() } } ...cleanup buffers... } }) let format = node.inputFormat(forBus: 0) // new code audioEngine.connect(node, to: downMixer, format: format)//use default input format audioEngine.connect(downMixer, to: audioEngine.outputNode, format: format16KHzMono)//use new audio format downMixer.outputVolume = 0.0 audioEngine.prepare() do { try audioEngine.start() } catch let error { print ("oh catch \(error)") } }
0
0
1.3k
Aug ’22
How set CBR in AVAudioConverter?
I am using AVAudioConverter in Objective C. AVAudioConverter has bitRate and bitRateStrategy parameters defined. The default bitRateStrategy value is AVAudioBitRateStrategy_LongTermAverage. If I set bitRateStrategy to AVAudioBitRateStrategy_Constant there is no change. The bitRate variable works correctly. AVAudioConverter *audioConverter = [[AVAudioConverter alloc] initFromFormat:inputFormat toFormat:outputFormat]; audioConverter.bitRate = 128000; audioConverter.bitRateStrategy = AVAudioBitRateStrategy_Constant;
0
0
966
Aug ’22
Detecting background volume level in Swift
Am trying to distinguish the differences in volumes between background noise, and someone speaking in Swift. Previously, I had come across a tutorial which had me looking at the power levels in each channel. It come out as the code listed in Sample One which I called within the installTap closure. It was ok, but the variance between background and the intended voice to record, wasn't that great. Sure, it could have been the math used to calculate it, but since I have no experience in audio data, it was like reading another language. Then I came across another demo. It's code was much simpler, and the difference in values between background noise and speaking voice was much greater, therefore much more detectable. It's listed here in Sample Two, which I also call within the installTap closure. My issue here is wanting to understand what is happening in the code. In all my experiences with other languages, voice was something I never dealt with before, so this is way over my head. Not looking for someone to explain this to me line by line. But if someone could let me know where I can find decent documentation so I can better grasp what is going on, I would appreciate it. Thank you Sample One func audioMetering(buffer:AVAudioPCMBuffer) { // buffer.frameLength = 1024 let inNumberFrames:UInt = UInt(buffer.frameLength) if buffer.format.channelCount > 0 { let samples = (buffer.floatChannelData![0]) var avgValue:Float32 = 0 vDSP_meamgv(samples,1 , &avgValue, inNumberFrames) var v:Float = -100 if avgValue != 0 { v = 20.0 * log10f(avgValue) } self.averagePowerForChannel0 = (self.LEVEL_LOWPASS_TRIG*v) + ((1-self.LEVEL_LOWPASS_TRIG)*self.averagePowerForChannel0) self.averagePowerForChannel1 = self.averagePowerForChannel0 } if buffer.format.channelCount > 1 { let samples = buffer.floatChannelData![1] var avgValue:Float32 = 0 vDSP_meamgv(samples, 1, &avgValue, inNumberFrames) var v:Float = -100 if avgValue != 0 { v = 20.0 * log10f(avgValue) } self.averagePowerForChannel1 = (self.LEVEL_LOWPASS_TRIG*v) + ((1-self.LEVEL_LOWPASS_TRIG)*self.averagePowerForChannel1) } } Sample Two private func getVolume(from buffer: AVAudioPCMBuffer, bufferSize: Int) -> Float { guard let channelData = buffer.floatChannelData?[0] else { return 0 } let channelDataArray = Array(UnsafeBufferPointer(start:channelData, count: bufferSize)) var outEnvelope = [Float]() var envelopeState:Float = 0 let envConstantAtk:Float = 0.16 let envConstantDec:Float = 0.003 for sample in channelDataArray { let rectified = abs(sample) if envelopeState < rectified { envelopeState += envConstantAtk * (rectified - envelopeState) } else { envelopeState += envConstantDec * (rectified - envelopeState) } outEnvelope.append(envelopeState) } // 0.007 is the low pass filter to prevent // getting the noise entering from the microphone if let maxVolume = outEnvelope.max(), maxVolume > Float(0.015) { return maxVolume } else { return 0.0 } }
1
0
2.8k
Jul ’22
Audio crashes when connected to AirPods
Hi There, Whenever I want to use the microphone for my ShazamKit app while connected to AirPods my app crashes with a "Invalid input sample rate." message. I've tried multiple formats but keep getting this crash. Any pointers would be really helpful. func configureAudioEngine() { do { try audioSession.setCategory(.playAndRecord, options: [.mixWithOthers, .defaultToSpeaker, .allowAirPlay, .allowBluetoothA2DP ,.allowBluetooth]) try audioSession.setActive(false, options: .notifyOthersOnDeactivation) } catch { print(error.localizedDescription) } guard let engine = audioEngine else { return } let inputNode = engine.inputNode let inputNodeFormat = inputNode.inputFormat(forBus: 0) let audioFormat = AVAudioFormat( standardFormatWithSampleRate: inputNodeFormat.sampleRate, channels: 1 ) // Install a "tap" in the audio engine's input so that we can send buffers from the microphone to the signature generator. engine.inputNode.installTap(onBus: 0, bufferSize: 1024, format: audioFormat) { buffer, audioTime in self.addAudio(buffer: buffer, audioTime: audioTime) } } ```
2
1
2.4k
Jul ’22
Bug when using multiple AVAudioUnitSampler instances
Hi there, I'm building an audio app for iOS and ran into a very weird bug when using multiple AVAudioUnitSampler instances to play different instruments at the same time. I narrowed down the repro to: let sampler = AVAudioUnitSampler() self.audioEngine.attach(sampler) self.audioEngine.connect(sampler, to: self.audioEngine.mainMixerNode, format: nil) try! sampler.loadInstrument(at: Bundle.main.url(forResource: "SteinwayPiano-v1", withExtension: "aupreset")!) let sampler2 = AVAudioUnitSampler() self.audioEngine.attach(sampler2) self.audioEngine.connect(sampler2, to: self.audioEngine.mainMixerNode, format: nil) try! sampler2.loadInstrument(at: Bundle.main.url(forResource: "Rhodes-v1", withExtension: "aupreset")!) I get the following error on the console (real device and simulator): 2022-07-02 21:27:28.329147+0200 soundboard[23592:612358] [default]     ExtAudioFile.cpp:193  about to throw -42: open audio file 2022-07-02 21:27:28.329394+0200 soundboard[23592:612358] [default]      FileSample.cpp:52  about to throw -42: FileSample::LoadFromURL: ExtAudioFileOpenURL 2022-07-02 21:27:28.330206+0200 soundboard[23592:612358]     SampleManager.cpp:434  Failed to load sample 'Sounds/Rhodes/A_050__D3_4-ST.wav -- file:///Users/deermichel/Library/Developer/CoreSimulator/Devices/79ACB2AD-5155-4798-8E96-649964CB274E/data/Containers/Bundle/Application/A10C7802-3F4B-445D-A390-B6A84D8071EE/soundboard.app/': error -42 2022-07-02 21:27:28.330414+0200 soundboard[23592:612358] [default]     SampleManager.cpp:435  about to throw -42: Failed to load sample Sometimes the app crashes after that, but most importantly, sampler2 won't work. Now, if I only create one of the samplers, it works as expected. Also, if both samplers reference to the same aupreset, it works. Only if I try to load different samples, I end up in undefined behavior. Adding a audioEngine.detach(sampler) before creating sampler2 doesn't solve the issue either - it will fail loading the samples with the same error. However, when deferring removal of sampler and creation of sampler2 a little bit, it magically starts working (though that's not what I want because I need both samplers simultaneously): let sampler = AVAudioUnitSampler() self.audioEngine.attach(sampler) self.audioEngine.connect(sampler, to: self.audioEngine.mainMixerNode, format: nil) try! sampler.loadInstrument(at: Bundle.main.url(forResource: "SteinwayPiano-v1", withExtension: "aupreset")!) DispatchQueue.main.async { self.audioEngine.detach(sampler)   let sampler2 = AVAudioUnitSampler()   self.audioEngine.attach(sampler2)   self.audioEngine.connect(sampler2, to: self.audioEngine.mainMixerNode, format: nil)   try! sampler2.loadInstrument(at: Bundle.main.url(forResource: "Rhodes-v1", withExtension: "aupreset")!) } My samples are linked to the bundle as a folder alias - and I have a feeling that there is some exclusive lock... however I don't have the source code to debug the errors on the console further. Any help is appreciated, have a good one :)
2
0
2k
Jul ’22
testing multichannel AudioUnit output with AVAudioEngine
I'm extending an AudioUnit to generate multi-channel output, and trying to write a unit test using AVAudioEngine. My test installs a tap on the AVAudioNode's output bus and ensures the output is not silence. This works for stereo. I've currently got: auto avEngine = [[AVAudioEngine alloc] init]; [avEngine attachNode:avAudioUnit]; auto format = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:44100. channels:channelCount]; [avEngine connect:avAudioUnit to:avEngine.mainMixerNode format:format]; where avAudioUnit is my AU. So it seems I need to do more than simply setting the channel count for the format when connecting, because after this code, [avAudioUnit outputFormatForBus:0].channelCount is still 2. Printing the graph yields: AVAudioEngineGraph 0x600001e0a200: initialized = 1, running = 1, number of nodes = 3 ******** output chain ******** node 0x600000c09a80 {'auou' 'ahal' 'appl'}, 'I' inputs = 1 (bus0, en1) <- (bus0) 0x600000c09e00, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved] node 0x600000c09e00 {'aumx' 'mcmx' 'appl'}, 'I' inputs = 1 (bus0, en1) <- (bus0) 0x600000c14300, {'augn' 'brnz' 'brnz'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved] outputs = 1 (bus0, en1) -> (bus0) 0x600000c09a80, {'auou' 'ahal' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved] node 0x600000c14300 {'augn' 'brnz' 'brnz'}, 'I' outputs = 1 (bus0, en1) -> (bus0) 0x600000c09e00, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved] So AVAudioEngine just silently ignores whatever channel counts I pass to it. If I do: auto numHardwareOutputChannels = [avEngine.outputNode outputFormatForBus:0].channelCount; NSLog(@"hardware output channels %d\n", numHardwareOutputChannels); I get 30, because I have an audio interface connected. So I would think AVAudioEngine would support this. I've also tried setting the format explicitly on the connection between the mainMixerNode and the outputNode to no avail.
0
2
1.6k
Jun ’22
How does toggling AVAudioSession active state affect the AVAudioPlayerNode
Every time the AVAudioSession category is re-activated ( after being inactivated) and the audioengine is restarted (calling stop() and play()), the output from audioplayer node seems to ignore the audio session category, until explicitly connecting the audio player node again using audioEngine.connect(playerNode, to: audioEngine.outputNode, format: audioFile.processingFormat) The documentation regarding this behavior is not clear and would like to clarify the following. Should audioEngine.connect be called everytime the AVAudioSession is activated? Should audioEngine.connect be called after the audio player engine is stopped (audioEngine.stop())?
0
0
836
Jun ’22
If not AVMIDIRecorder, then what?
For AVAudioPlayer, there is corresponding AVAudioRecorder. For AVMIDIPLayer, I found nothing for recording from the system's active MIDI input device. Can I record midi events from the system’s active input midi device, without resolving to low level CoreMidi? After configuring AVAudioUnitSampler with just a few lines of code, import AVFoundation var engine = AVAudioEngine() let unit = AVAudioUnitSampler() engine.attach(unit) engine.connect(unit, to: engine.outputNode, format: engine.outputNode.outputFormat (forBus:0)) try! unit.loadInstrument(at:sndurl) //url to .sf2 file try! engine.start() I could send midi events programmatically. // feeding AVAudioUnitMIDIInstrument with midi data let range = (0..<100) let midiStart = range.map { _ in UInt8.random(in: 70...90) } let midiStop = [0] + midiStart let times = range.map { _ in TimeInterval.random(in: 0...100) * 0.3 } for i in range {     DispatchQueue.main.asyncAfter(deadline: .now()+TimeInterval(times[i])){         unit.stopNote(midiStop[i], onChannel: 1)         unit.startNote(midiStart[i], withVelocity: 127, onChannel: 1)     } } But instead, I need to send midi events from a midi instrument, and tap to them for recording.
Replies
1
Boosts
0
Views
1.4k
Activity
Dec ’22
AirPods Pro inward facing microphone
I'm unclear on how to access the inward facing microphone in the AirPods Pro (not the outward facing one). If this is possible, can you point me in the right direction? More context is that there is a ticking noise coming a spasm inside someone's ears that I'd like to try canceling for them. The standard AirPods Pro noise cancellation modes don't have any effect on the sound. I know latency may be too high to do this on the phone with a custom app, but thought if I could reach the point of that being the problem, then I could experiment with predictive algorithms. Thank you in advance for ideas or recommendations.
Replies
1
Boosts
0
Views
1.5k
Activity
Nov ’22
AVAudioEngine setup doesn't work with iPhone 14 Pro + Airpods Pro combination
I have an AVAudioEngine setup with VoiceProcessingEnabled that takes the input from mic and plays it on speaker. This works great with Airpods on other iPhone models except iPhone 14 (specifically tested on iPhone 14 Pro). In case of iPhone 14 Pro, there is no audio on the speaker at all. I am linking to a minimal sample app below to reproduce the issue. Please run this sample on iPhone 11 using Airpods Pro you will hear yourself speaking. But when you run the app on iPhone 14 Pro with Airpods Pro connected, you can't hear yourself. Any help will be appreciated. Cheers Sample app: https://www.icloud.com/iclouddrive/07bC_sAZW8MAA2u5lHeHOoFPg#AudioEngineAirpodsTest
Replies
0
Boosts
0
Views
965
Activity
Nov ’22
AVSpeechSynthesisVoice broken in iOS 16 beta
Hello, It seems like AVSpeechSynthesisVoice.speechVoices() now returns [] instead of a list of voices, and which means that no speechVoices are available. This leads to the impossibility to do any speech synthesis using iOS 16. Is anyone else experiencing this? Have you found a way to address it? Thanks
Replies
2
Boosts
2
Views
1.8k
Activity
Nov ’22
Airpods actual audio latency is differ from AVAudioengine.session prediction and changes over time
Hi, I am building a realtime drum practise tool which listens to the players' practice and provides visual feedback on their accuracy. I use AVAudioSourceNode and AVAudioSinkNode for playing audio and for listening to player practise. Precious timing is the most important part of our app. To optimise audio latency I set PreferredIOBufferDuration to 64/48000sec (~1.33ms). My preferences work fine with builtin or wired audio devices. In these cases we can easily estimate the actual audio latency. However we would like to support Apple airPods (or other bluetooth earbuds) as well, but it seems to be impossible to predict the actual audio latency. let bufferSize: UInt32 = 64 let sampleRate: Double = 48000 let bufferDuration = TimeInterval(Double(bufferSize) / sampleRate) try? session.setCategory(AVAudioSession.Category.playAndRecord, options: [.defaultToSpeaker, .mixWithOthers, .allowBluetoothA2DP])     try? session.setPreferredSampleRate(Double(sampleRate))     try? session.setPreferredIOBufferDuration(bufferDuration)     try? session.setActive(true, options: .notifyOthersOnDeactivation) I use iPhone 12 mini and airPods 2 for testing. (Input always have to be the phone's builtin mic) let input = session.inputLatency // 2.438ms let output = session.outputLatency // 160.667ms let buffer = session.ioBufferDuration // 1.333ms let estimated = input + output + buffer * 2 // 165.771 session.outputLatency returns ca 160ms for my airPods. With the basic calculation above I can estimate a latency of 165.771ms, but when I measure the actual latency (time difference between heard and played sound ) I get significantly different values. If I connect my airPods and start playing immediately, the actual measured latency is ca 215-220ms at first, but it is continuously decreasing over time. After about 20-30mins of measuring the actual latency is around 155-160ms (just like the value that the session returns). However if I am using my airPods for a while before I start the measurement, the actual latency starts from ca 180ms (and decreasing over time the same way). On older iOS devices these differences are even larger. It feels like bluetooth connection needs to "warm up" or something. My questions would be: Is there any way to have a relatively constant audio latency with bluetooth devices? I thought maybe it depends on the actual bandwidth but I couldn't find anything on this topic. Can bandwidth change over time? Can I control it? I guess airPods support AAC codec. Is there any way to force them to use SBC? Does SBC codec work with lower latency? What is the best audioengine setting to support bluetooth devices with the lowest latency? Any other suggestion? Thank you
Replies
3
Boosts
0
Views
8.5k
Activity
Oct ’22
Sound decibel recognition
Hi Community Members, We tried to find the particular sound through the microphone. We used PKCCheck to detect the sound decibel. we detect the sound based on the number of dB values per second we receive and add some logic over it to get the result, but when we have continuous sound like an alarm we can't detect it as the gap between the sound is very less. Any suggestion on libraries to achieve this. Also whether we can achieve this thru Frequency & Amplitude method. Please advise.
Replies
0
Boosts
0
Views
1.1k
Activity
Oct ’22
How to play .caf file
I tried to change my code from let urlString = Bundle.main.path(forResource: "X", ofType: "mp3")! to let urlString = Bundle.main.path(forResource: "X", ofType: "caf")! after I already uploaded the file. But it throws a fatal error: Unexpectedly found nil while unwrapping an Optional value I double check the filename and it's correct. and the caf file does play.
Replies
1
Boosts
0
Views
2.9k
Activity
Sep ’22
iOS opus codec issue. Webrtc RTCAudioTrack always starts the audio with 2 seconds delay. [aurioc] AURemoteIO.cpp:1128 failed: -66635
I'm trying to send the audio track in the webrtc app. I create the audio track like this: private var factory: RTCPeerConnectionFactory = RTCPeerConnectionFactory(encoderFactory: RTCDefaultVideoEncoderFactory(), decoderFactory: RTCDefaultVideoDecoderFactory()) .... let audioTrack = factory.audioTrack(withTrackId: "ARDAMSa0") if mediaStream == nil { self.mediaStream = self.factory.mediaStream(withStreamId: "0") } self.mediaStream.addAudioTrack(audioTrack) Then I add it to peerConnection the usual way. The problem is my audio starts with some delay (2 seconds). I hear it on another peer in almost 2 seconds. Video starts immediately. The connection is perfect. I see an error log: [aurioc] AURemoteIO.cpp:1128 failed: -66635 (enable 3, outf< 1 ch, 48000 Hz, Int16> inf< 1 ch, 48000 Hz, Int16>) In the SDP offer I see that the audio codec is "opus", channels=2, clockRate=48000, which seems completely fine. Question: Is this opus codec is a problem for iOS? is there any extra RTCAudioSession steps I have to do to be able to start the audio immediately? I tried: RTCAudioSession.sharedInstance().setPreferredIOBufferDuration(0.005) Also I tried setting RTCAudioSession to various categories. Nothing helps. There's still a lag at the start. I'm not even sure what it's potentially connected with. I'm testing on iPhone 11, 12, iOS 15.6.1. Tried multiple webrtc branches. (m88, m90+), all the same. Any ideas appreciated. Thanks
Replies
0
Boosts
1
Views
2.2k
Activity
Sep ’22
Playing Audio
So I have successfully triggered a PTT notification, but when I try to play audio – any audio – it doesn't play. Seems to be an issue with initiating my AVAudioSession. If I do not initiate it, the sound plays (outside of the didActivateAudioSession; such as on view did load), so I know that it's not the audio playing code. For some reason, the AVAudioSession is not allowing me to play sound. Even when I put "PlayandRecord" and when I put "mix" in the options
Replies
2
Boosts
0
Views
1.6k
Activity
Sep ’22
AVAudioEngine and c++?
Im guessing i already know the answer to this but is AVAudioEngine class accessible in c++? No matter what i try i can't seem to get a pointer to it.
Replies
1
Boosts
0
Views
1.1k
Activity
Sep ’22
AUAudioUnit – Impossible to handle frame count limitation in render?
Summary: I've created an AUAudioUnit to host some third party signal processing code and am running into a edge case limitation where I can only process and supply output audio data (from the internalRenderBlock) if it's an exact multiple of a specific number of frames. More Detail: This third party code ONLY works with exactly 10ms of data at time. For example, say with 48khz audio, it only accepts 480 frames on each processing function call. If the AUAudioUnit's internalRenderBlock is called with 1024 frames as the frame count, I can use the pullInputBlock to get 480 frames, process it, another 480 frames, and process that, but what should I then do with the remaining 64 frames? Possible Solutions Foiled: a) It seems there's no way to indicate to the host that I have only consumed 960 frames and will only be supplying 960 frames of output. I thought perhaps the host would observe that if the outputData ABL buffers have less than the frame count passed into the internalRenderBlock, that it might appropriately advance the timestamp only by that much the next time time around, but it does not. So it's required that all the audio be processed before the block returns, but I can only do that if the block is requested to handle exactly a multiple of 10ms of data. b) I can't buffer up the "remainder" input and process it on the next internalRenderBlock cycle because all of the output must be provided on return as discussed in A. c) As an alternative, I see no way to have the unit explicitly indicate to the host, how many frames the unit can process at a time. maximumFramesToRender is the host telling the unit (not the reverse), and either way it's a maximum only, not a minumum as well. What can I do?
Replies
1
Boosts
0
Views
2.2k
Activity
Aug ’22
App Crash during toggle between Speaker to bluetooth headphone.
We have developed iOS app using WebRTC and ARKit for the video communication. We have the option to toggle between headphone and speaker. We are facing an app crash when bluetooth headphone is connected and the user tries to toggle between speaker and headphone continuously. Also while toggle between speaker and headphone it throws log in console ARSessionDelegate is retaining 11 ARFrames. This can lead to future camera frames being dropped. Following is the crash : Fatal Exception: com.apple.coreaudio.avfaudio required condition is false: nil == owningEngine || GetEngine() == owningEngine Following are the code snippet : func headphoneOn() -> Bool {      audioSession.lockForConfiguration()      var bluetoothPort : AVAudioSessionPortDescription? = nil      var headphonePort : AVAudioSessionPortDescription? = nil      var inbuiltMicPort : AVAudioSessionPortDescription? = nil            if let availableInputs = AVAudioSession.sharedInstance().availableInputs {        for inputDevice in availableInputs {          if inputDevice.portType == .builtInMic {           inbuiltMicPort = inputDevice         } else if inputDevice.portType == .headsetMic || inputDevice.portType == .headphones {           headphonePort = inputDevice         } else if inputDevice.portType == .bluetoothHFP || inputDevice.portType == .bluetoothA2DP || inputDevice.portType == .bluetoothLE {           bluetoothPort = inputDevice         }       }     }            do {        try audioSession.overrideOutputAudioPort(AVAudioSession.PortOverride.none)        if let bluetoothPort = bluetoothPort {          try audioSession.setPreferredInput(bluetoothPort)          try audioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue)          audioSession.unlockForConfiguration()          return true       } else if let headphonePort = headphonePort {          try audioSession.setPreferredInput(headphonePort)          try audioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue)          audioSession.unlockForConfiguration()          return true       } else if let inbuiltMicPort = inbuiltMicPort {          try audioSession.setMode(AVAudioSession.Mode.default.rawValue)          try audioSession.setPreferredInput(inbuiltMicPort)          audioSession.unlockForConfiguration()          return true       } else {          audioSession.unlockForConfiguration()          return false       }             } catch let error as NSError {        debugPrint("#configureAudioSessionToSpeaker Error \(error.localizedDescription)")        audioSession.unlockForConfiguration()        return false     }         } func speakerOn() -> Bool {      audioSession.lockForConfiguration()      var inbuiltSpeakerPort : AVAudioSessionPortDescription? = nil            if let availableInputs = AVAudioSession.sharedInstance().availableInputs {        for inputDevice in availableInputs {          if inputDevice.portType == .builtInSpeaker {           inbuiltSpeakerPort = inputDevice         }       }     }      do { ///Audio Session: Set on Speaker        if let inbuiltSpeakerPort = inbuiltSpeakerPort {          try audioSession.setPreferredInput(inbuiltSpeakerPort)       }        try audioSession.setMode(AVAudioSession.Mode.videoChat.rawValue)        try audioSession.overrideOutputAudioPort(.speaker)        audioSession.unlockForConfiguration()        return true             } catch let error as NSError {        debugPrint("#configureAudioSessionToSpeaker Error \(error.localizedDescription)")        audioSession.unlockForConfiguration()        return false             }   } Any help will be appreciated to solve this crash issue.
Replies
2
Boosts
0
Views
2.0k
Activity
Aug ’22
AVAudioEngine exception - required condition is false format.sampleRate == hwFormat.sampleRate
I see in Crashlytics few users are getting this exception when connecting the inputNode to mainMixerNode in AVAudioEngine: Fatal Exception: com.apple.coreaudio.avfaudio required condition is false: format.sampleRate == hwFormat.sampleRate Here is my code: self.engine = AVAudioEngine() let format = engine.inputNode.inputFormat(forBus: 0) //main mixer node is connected to output node by default engine.connect(self.engine.inputNode, to: self.engine.mainMixerNode, format: format) Just want to understand how can this error occur and what is the right fix?
Replies
2
Boosts
1
Views
3.1k
Activity
Aug ’22
Am unable to add an AVAudioMixerNode to downsize my recording
Am at the beginning of a voice recording app. I store incoming voice data into a buffer array, and write 50 of them to a file. The code works fine, Sample One. However, I would like the recorded files to be smaller. So here I try to add an AVAudioMixer to downsize the sampling. But this code sample gives me two errors. Sample Two The first error I get is when I call audioEngine.attach(downMixer). The debugger gives me nine of these errors: throwing -10878 The second error is a crash when I try to write to audioFile. Of course they might all be related, so am looking to include the mixer successfully first. But I do need help as I am just trying to piece these all together from tutorials, and when it comes to audio, I know less than anything else. Sample One //these two lines are in the init of the class that contains this function... node = audioEngine.inputNode recordingFormat = node.inputFormat(forBus: 0) func startRecording() { audioBuffs = [] x = -1 node.installTap(onBus: 0, bufferSize: 8192, format: recordingFormat, block: { [self] (buffer, _) in x += 1 audioBuffs.append(buffer) if x >= 50 { audioFile = makeFile(format: recordingFormat, index: fileCount) mainView?.setLabelText(tag: 3, text: "fileIndex = \(fileCount)") fileCount += 1 for i in 0...49 { do { try audioFile!.write(from: audioBuffs[i]); } catch { mainView?.setLabelText(tag: 4, text: "write error") stopRecording() } } ...cleanup buffer code } }) audioEngine.prepare() do { try audioEngine.start() } catch let error { print ("oh catch \(error)") } } Sample Two //these two lines are in the init of the class that contains this function node = audioEngine.inputNode recordingFormat = node.inputFormat(forBus: 0) func startRecording() { audioBuffs = [] x = -1 // new code let format16KHzMono = AVAudioFormat.init(commonFormat: AVAudioCommonFormat.pcmFormatInt16, sampleRate: 11025.0, channels: 1, interleaved: true) let downMixer = AVAudioMixerNode() audioEngine.attach(downMixer) // installTap on the mixer rather than the node downMixer.installTap(onBus: 0, bufferSize: 8192, format: format16KHzMono, block: { [self] (buffer, _) in x += 1 audioBuffs.append(buffer) if x >= 50 { // use a different format in creating the audioFile audioFile = makeFile(format: format16KHzMono!, index: fileCount) mainView?.setLabelText(tag: 3, text: "fileIndex = \(fileCount)") fileCount += 1 for i in 0...49 { do { try audioFile!.write(from: audioBuffs[i]); } catch { stopRecording() } } ...cleanup buffers... } }) let format = node.inputFormat(forBus: 0) // new code audioEngine.connect(node, to: downMixer, format: format)//use default input format audioEngine.connect(downMixer, to: audioEngine.outputNode, format: format16KHzMono)//use new audio format downMixer.outputVolume = 0.0 audioEngine.prepare() do { try audioEngine.start() } catch let error { print ("oh catch \(error)") } }
Replies
0
Boosts
0
Views
1.3k
Activity
Aug ’22
How set CBR in AVAudioConverter?
I am using AVAudioConverter in Objective C. AVAudioConverter has bitRate and bitRateStrategy parameters defined. The default bitRateStrategy value is AVAudioBitRateStrategy_LongTermAverage. If I set bitRateStrategy to AVAudioBitRateStrategy_Constant there is no change. The bitRate variable works correctly. AVAudioConverter *audioConverter = [[AVAudioConverter alloc] initFromFormat:inputFormat toFormat:outputFormat]; audioConverter.bitRate = 128000; audioConverter.bitRateStrategy = AVAudioBitRateStrategy_Constant;
Replies
0
Boosts
0
Views
966
Activity
Aug ’22
Detecting background volume level in Swift
Am trying to distinguish the differences in volumes between background noise, and someone speaking in Swift. Previously, I had come across a tutorial which had me looking at the power levels in each channel. It come out as the code listed in Sample One which I called within the installTap closure. It was ok, but the variance between background and the intended voice to record, wasn't that great. Sure, it could have been the math used to calculate it, but since I have no experience in audio data, it was like reading another language. Then I came across another demo. It's code was much simpler, and the difference in values between background noise and speaking voice was much greater, therefore much more detectable. It's listed here in Sample Two, which I also call within the installTap closure. My issue here is wanting to understand what is happening in the code. In all my experiences with other languages, voice was something I never dealt with before, so this is way over my head. Not looking for someone to explain this to me line by line. But if someone could let me know where I can find decent documentation so I can better grasp what is going on, I would appreciate it. Thank you Sample One func audioMetering(buffer:AVAudioPCMBuffer) { // buffer.frameLength = 1024 let inNumberFrames:UInt = UInt(buffer.frameLength) if buffer.format.channelCount > 0 { let samples = (buffer.floatChannelData![0]) var avgValue:Float32 = 0 vDSP_meamgv(samples,1 , &avgValue, inNumberFrames) var v:Float = -100 if avgValue != 0 { v = 20.0 * log10f(avgValue) } self.averagePowerForChannel0 = (self.LEVEL_LOWPASS_TRIG*v) + ((1-self.LEVEL_LOWPASS_TRIG)*self.averagePowerForChannel0) self.averagePowerForChannel1 = self.averagePowerForChannel0 } if buffer.format.channelCount > 1 { let samples = buffer.floatChannelData![1] var avgValue:Float32 = 0 vDSP_meamgv(samples, 1, &avgValue, inNumberFrames) var v:Float = -100 if avgValue != 0 { v = 20.0 * log10f(avgValue) } self.averagePowerForChannel1 = (self.LEVEL_LOWPASS_TRIG*v) + ((1-self.LEVEL_LOWPASS_TRIG)*self.averagePowerForChannel1) } } Sample Two private func getVolume(from buffer: AVAudioPCMBuffer, bufferSize: Int) -> Float { guard let channelData = buffer.floatChannelData?[0] else { return 0 } let channelDataArray = Array(UnsafeBufferPointer(start:channelData, count: bufferSize)) var outEnvelope = [Float]() var envelopeState:Float = 0 let envConstantAtk:Float = 0.16 let envConstantDec:Float = 0.003 for sample in channelDataArray { let rectified = abs(sample) if envelopeState < rectified { envelopeState += envConstantAtk * (rectified - envelopeState) } else { envelopeState += envConstantDec * (rectified - envelopeState) } outEnvelope.append(envelopeState) } // 0.007 is the low pass filter to prevent // getting the noise entering from the microphone if let maxVolume = outEnvelope.max(), maxVolume > Float(0.015) { return maxVolume } else { return 0.0 } }
Replies
1
Boosts
0
Views
2.8k
Activity
Jul ’22
Audio crashes when connected to AirPods
Hi There, Whenever I want to use the microphone for my ShazamKit app while connected to AirPods my app crashes with a "Invalid input sample rate." message. I've tried multiple formats but keep getting this crash. Any pointers would be really helpful. func configureAudioEngine() { do { try audioSession.setCategory(.playAndRecord, options: [.mixWithOthers, .defaultToSpeaker, .allowAirPlay, .allowBluetoothA2DP ,.allowBluetooth]) try audioSession.setActive(false, options: .notifyOthersOnDeactivation) } catch { print(error.localizedDescription) } guard let engine = audioEngine else { return } let inputNode = engine.inputNode let inputNodeFormat = inputNode.inputFormat(forBus: 0) let audioFormat = AVAudioFormat( standardFormatWithSampleRate: inputNodeFormat.sampleRate, channels: 1 ) // Install a "tap" in the audio engine's input so that we can send buffers from the microphone to the signature generator. engine.inputNode.installTap(onBus: 0, bufferSize: 1024, format: audioFormat) { buffer, audioTime in self.addAudio(buffer: buffer, audioTime: audioTime) } } ```
Replies
2
Boosts
1
Views
2.4k
Activity
Jul ’22
Bug when using multiple AVAudioUnitSampler instances
Hi there, I'm building an audio app for iOS and ran into a very weird bug when using multiple AVAudioUnitSampler instances to play different instruments at the same time. I narrowed down the repro to: let sampler = AVAudioUnitSampler() self.audioEngine.attach(sampler) self.audioEngine.connect(sampler, to: self.audioEngine.mainMixerNode, format: nil) try! sampler.loadInstrument(at: Bundle.main.url(forResource: "SteinwayPiano-v1", withExtension: "aupreset")!) let sampler2 = AVAudioUnitSampler() self.audioEngine.attach(sampler2) self.audioEngine.connect(sampler2, to: self.audioEngine.mainMixerNode, format: nil) try! sampler2.loadInstrument(at: Bundle.main.url(forResource: "Rhodes-v1", withExtension: "aupreset")!) I get the following error on the console (real device and simulator): 2022-07-02 21:27:28.329147+0200 soundboard[23592:612358] [default]     ExtAudioFile.cpp:193  about to throw -42: open audio file 2022-07-02 21:27:28.329394+0200 soundboard[23592:612358] [default]      FileSample.cpp:52  about to throw -42: FileSample::LoadFromURL: ExtAudioFileOpenURL 2022-07-02 21:27:28.330206+0200 soundboard[23592:612358]     SampleManager.cpp:434  Failed to load sample 'Sounds/Rhodes/A_050__D3_4-ST.wav -- file:///Users/deermichel/Library/Developer/CoreSimulator/Devices/79ACB2AD-5155-4798-8E96-649964CB274E/data/Containers/Bundle/Application/A10C7802-3F4B-445D-A390-B6A84D8071EE/soundboard.app/': error -42 2022-07-02 21:27:28.330414+0200 soundboard[23592:612358] [default]     SampleManager.cpp:435  about to throw -42: Failed to load sample Sometimes the app crashes after that, but most importantly, sampler2 won't work. Now, if I only create one of the samplers, it works as expected. Also, if both samplers reference to the same aupreset, it works. Only if I try to load different samples, I end up in undefined behavior. Adding a audioEngine.detach(sampler) before creating sampler2 doesn't solve the issue either - it will fail loading the samples with the same error. However, when deferring removal of sampler and creation of sampler2 a little bit, it magically starts working (though that's not what I want because I need both samplers simultaneously): let sampler = AVAudioUnitSampler() self.audioEngine.attach(sampler) self.audioEngine.connect(sampler, to: self.audioEngine.mainMixerNode, format: nil) try! sampler.loadInstrument(at: Bundle.main.url(forResource: "SteinwayPiano-v1", withExtension: "aupreset")!) DispatchQueue.main.async { self.audioEngine.detach(sampler)   let sampler2 = AVAudioUnitSampler()   self.audioEngine.attach(sampler2)   self.audioEngine.connect(sampler2, to: self.audioEngine.mainMixerNode, format: nil)   try! sampler2.loadInstrument(at: Bundle.main.url(forResource: "Rhodes-v1", withExtension: "aupreset")!) } My samples are linked to the bundle as a folder alias - and I have a feeling that there is some exclusive lock... however I don't have the source code to debug the errors on the console further. Any help is appreciated, have a good one :)
Replies
2
Boosts
0
Views
2k
Activity
Jul ’22
testing multichannel AudioUnit output with AVAudioEngine
I'm extending an AudioUnit to generate multi-channel output, and trying to write a unit test using AVAudioEngine. My test installs a tap on the AVAudioNode's output bus and ensures the output is not silence. This works for stereo. I've currently got: auto avEngine = [[AVAudioEngine alloc] init]; [avEngine attachNode:avAudioUnit]; auto format = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:44100. channels:channelCount]; [avEngine connect:avAudioUnit to:avEngine.mainMixerNode format:format]; where avAudioUnit is my AU. So it seems I need to do more than simply setting the channel count for the format when connecting, because after this code, [avAudioUnit outputFormatForBus:0].channelCount is still 2. Printing the graph yields: AVAudioEngineGraph 0x600001e0a200: initialized = 1, running = 1, number of nodes = 3 ******** output chain ******** node 0x600000c09a80 {'auou' 'ahal' 'appl'}, 'I' inputs = 1 (bus0, en1) <- (bus0) 0x600000c09e00, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved] node 0x600000c09e00 {'aumx' 'mcmx' 'appl'}, 'I' inputs = 1 (bus0, en1) <- (bus0) 0x600000c14300, {'augn' 'brnz' 'brnz'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved] outputs = 1 (bus0, en1) -> (bus0) 0x600000c09a80, {'auou' 'ahal' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved] node 0x600000c14300 {'augn' 'brnz' 'brnz'}, 'I' outputs = 1 (bus0, en1) -> (bus0) 0x600000c09e00, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved] So AVAudioEngine just silently ignores whatever channel counts I pass to it. If I do: auto numHardwareOutputChannels = [avEngine.outputNode outputFormatForBus:0].channelCount; NSLog(@"hardware output channels %d\n", numHardwareOutputChannels); I get 30, because I have an audio interface connected. So I would think AVAudioEngine would support this. I've also tried setting the format explicitly on the connection between the mainMixerNode and the outputNode to no avail.
Replies
0
Boosts
2
Views
1.6k
Activity
Jun ’22
How does toggling AVAudioSession active state affect the AVAudioPlayerNode
Every time the AVAudioSession category is re-activated ( after being inactivated) and the audioengine is restarted (calling stop() and play()), the output from audioplayer node seems to ignore the audio session category, until explicitly connecting the audio player node again using audioEngine.connect(playerNode, to: audioEngine.outputNode, format: audioFile.processingFormat) The documentation regarding this behavior is not clear and would like to clarify the following. Should audioEngine.connect be called everytime the AVAudioSession is activated? Should audioEngine.connect be called after the audio player engine is stopped (audioEngine.stop())?
Replies
0
Boosts
0
Views
836
Activity
Jun ’22