So, following the previous posts my last little test to ensure that my generation code itself was not just the problem was to try a loop-back and see how this worked. To do this I created a simple test case which has the default input going into a mixer with it's volume set to zero and then a player also going into the other mixer that is connecting to the output. I have then installed a tap on the input and used that buffer to pump straight into ScheduleBuffer of the player.
Here's the example code:
import Cocoa
import AVFoundation
// Setup engine and node instances
var engine = AVAudioEngine()
var mixer = engine.mainMixerNode
var inputstub = AVAudioMixerNode()
var player = AVAudioPlayerNode()
var input = engine.inputNode
var output = engine.outputNode
var format = input.inputFormatForBus(0)
var error:NSError?
engine.attachNode(inputstub)
engine.attachNode(player)
// Connect nodes
engine.connect(player,to:mixer, format:format)
// Start engine
engine.startAndReturnError(&error)
player.play()
engine.connect(input, to: inputstub, format: format)
engine.connect(inputstub, to: mixer, format: format)
engine.connect(mixer, to: output, format: format)
inputstub.outputVolume = 1.0
mixer.outputVolume = 1.0
let length = 24256
var audioBuffer = AVAudioPCMBuffer(PCMFormat: player.outputFormatForBus(0),
frameCapacity: UInt32(length))
audioBuffer.frameLength = UInt32(length)
input.installTapOnBus(0, bufferSize:UInt32(length), format: input.outputFormatForBus(0))
{
(buffer, time) in
var sum:Float = 0
// fill up the buffer with some samples
for (var i=0; i<length; i++)
{
audioBuffer.floatChannelData.memory[i] = 1.0 * buffer.floatChannelData.memory[i]
}
player.scheduleBuffer(audioBuffer,atTime:nil,options:.InterruptsAtLoop,
completionHandler:nil)
}
while (true)
{
NSThread.sleepForTimeInterval(1)
}
Testing this, there is a sense that the loop must be working ok to fill the buffer without too much trouble and the CPU is barely hitting 3% but the audio playback is glitching which becomes more pronounced as the buffer size is reduced (try playing around with length) until values below 1000 or so become too choppy for anything sensible.
I tried scheduleBuffer with various different options, nil and InterruptsAtLoop, neither made much difference. This is a shame as it means that the scheduleBuffer function is just a bit too simplistic in implementation and is not implementing some fairly basic double buffering to transition between two buffers. Hmmm.... will have to look at another way of doing this then and get back to basics.
For information, I'm using two separate buffers as if the buffer in the tap closure is used the memory is not freed and just increases.
Is there a sample code to select sound card for output node?
ReplyDeleteThis comment has been removed by the author.
ReplyDeletehey had the same issue as you. The docs says that .loops should fire the completion handler but it doesnt. They still haven't fixed it but I found a workaround.
ReplyDelete