Я пытаюсь воспроизвести простой сигнал, используя синусоидальную волну заданной частоты.Я использую Swift 4.2 и AudioQueues для этой цели и создаю для iPhone на iOS 12. Однако у меня возникают большие трудности с настройкой.
Проблема, с которой я сейчас сталкиваюсь, заключается в том, что когдаЯ ставлю в очередь начальные буферы, я получаю небольшой щелчок, когда они воспроизводятся.Однако когда буферы используются повторно, ничего не происходит.Я доказал это, используя неоправданно большое количество буферов (50 000 с лишним), которые производят звуковой сигнал за одну секунду примерно на том уровне, который я ожидаю.Это правильно для данной частоты дискретизации.Как только все начальные буферы будут воспроизведены один раз, сэмпл останавливается.
Я попытался использовать циклы выполнения, отличные от внутреннего.Я проверил, что мой обратный вызов вызван, он получает правильные объекты и, кажется, устанавливает правильные значения для содержимого буфера, но он просто перестает работать.Ни одна из функций AudioQueue не возвращает никаких ненормальных кодов OSStatus.Я пробовал различные варианты в базовом описании для учета формата данных и порядка байтов.Я просто не могу понять, что еще может быть не так, поскольку то, что у меня есть, похоже на большинство примеров, которые я нашел.
(NB. Я для краткости опущу команды, которые запускают и останавливают аудио-очередьДостаточно сказать, что createAudioQueue()
называется.)
Вот мой код:
func synthesizerCallback(userData: UnsafeMutableRawPointer?, audioQueue: AudioQueueRef, buffer: AudioQueueBufferRef) {
guard let rawSynth = userData else { return }
let synth = Unmanaged<Synthesizer>.fromOpaque(rawSynth).takeUnretainedValue()
synth.write(withAudioQueue: audioQueue, toBuffer: buffer)
}
class Synthesizer {
enum Errors: Error {
case coreAudioError(OSStatus)
case couldNotInitialiseAudioQueue
}
private var format: AudioStreamBasicDescription
private var outputQueue: AudioQueueRef?
private var outputBuffers: [AudioQueueBufferRef?]
private var offset: Double = 0
let sampleRate: Double
let channels: Int
init(sampleRate: Double = 44100, channels: Int = 2, bufferCount: Int = 3) {
assert(bufferCount > 2, "Need at least three buffers!")
self.sampleRate = sampleRate
self.channels = channels
self.outputBuffers = Array<AudioQueueBufferRef?>(repeating: nil, count: bufferCount)
let uChannels = UInt32(channels)
let channelBytes = UInt32(MemoryLayout<Int16>.size)
let bytesPerFrame = uChannels * channelBytes
self.format = AudioStreamBasicDescription(
mSampleRate: Float64(sampleRate),
mFormatID: kAudioFormatLinearPCM,
mFormatFlags: kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked,
mBytesPerPacket: bytesPerFrame,
mFramesPerPacket: 1,
mBytesPerFrame: bytesPerFrame,
mChannelsPerFrame: uChannels,
mBitsPerChannel: channelBytes * 8,
mReserved: 0
)
}
private func createAudioQueue() throws {
let selfPointer = unsafeBitCast(self, to: UnsafeMutableRawPointer.self)
let createOutputResult = AudioQueueNewOutput(&format, synthesizerCallback, selfPointer, nil, nil, 0, &outputQueue)
if createOutputResult != 0 { throw Errors.coreAudioError(createOutputResult) }
guard let outputQueue = outputQueue else { throw Errors.couldNotInitialiseAudioQueue }
for i in 0 ..< outputBuffers.count {
let createBufferResult = AudioQueueAllocateBuffer(outputQueue, format.mBytesPerFrame, &outputBuffers[i])
if createBufferResult != 0 { throw Errors.coreAudioError(createBufferResult) }
guard let outputBuffer = outputBuffers[i] else { throw Errors.couldNotInitialiseAudioQueue }
synthesizerCallback(userData: selfPointer, audioQueue: outputQueue, buffer: outputBuffer)
}
let primeQueueResult = AudioQueuePrime(outputQueue, 0, nil)
if primeQueueResult != 0 { throw Errors.coreAudioError(primeQueueResult) }
let startQueueResult = AudioQueueStart(outputQueue, nil)
if startQueueResult != 0 { throw Errors.coreAudioError(startQueueResult) }
}
func write(withAudioQueue audioQueue: AudioQueueRef, toBuffer buffer: AudioQueueBufferRef) {
let dataSize = MemoryLayout<Int16>.stride * channels
let phase = offset / sampleRate * 10000 * Double.pi * 2
let value = Int16(sin(phase) * Double(Int16.max))
var allChannels = Array<Int16>(repeatElement(value, count: channels))
buffer.pointee.mAudioData.copyMemory(from: &allChannels, byteCount: dataSize)
buffer.pointee.mAudioDataByteSize = UInt32(dataSize)
let enqueueResult = AudioQueueEnqueueBuffer(audioQueue, buffer, 0, nil)
if enqueueResult != 0 { print(enqueueResult) }
offset += 1
}
}
ОБНОВЛЕНИЕ Как ни странно, звук кажется непрерывным, если я поставлюоколо 550 - 12000 буферов.Гораздо выше или ниже, и оно либо обрывается, либо сильно глюкает, или и то, и другое.Я предполагаю, что есть некоторые обстоятельства, при которых буфер может быть не готов к пополнению, и мне нужно что-то сделать, чтобы обойти эту проблему, но я не знаю, что это может быть.