【发布时间】:2019-04-21 16:46:50
【问题描述】:
我正在使用 Core Audio(带有 swift 包装器)播放一些音频样本(用于记录冲动的短刺激)。我坚持使用核心音频而不是较新的 AVFoundation,因为我需要一些严格的时间安排以及新框架尚未涵盖的多设备输入(我通过苹果代码请求让他们告诉我我必须使用核心音频)。
我现在使用以下方法创建了一个非常简单的正弦波:
func createSine()->[Float]{
var timeArray = makeArray(from: ((1.0/Float(sampleRate))*((-0.5)*Float(kernelLength))), to: ((1.0/Float(sampleRate))*((0.5)*Float(kernelLength))), increment: 1/sampleRate)
var sineArray = Array(repeating:0, count: timeArray.count)
for i in 0..<timeArray.count {
let x = 2 * Float.pi * 1000 * testTimeArray[i]
sineArray[i] = cos(x)
}
}
当以 sampleRate(在我的情况下为 44,100Hz)播放时,这将为 1000Hz 的正弦波创建一个浮点(我认为是 32 位)数组
如果我将其写入 wav 文件并播放,则会按预期创建音调。
但是,我实际上想在应用程序中触发这种声音。我已经设置了我的 AUGraph 并用音频单元填充了它。我创建了一个 AURenderCallback,它在混音器的输入时被调用。每次,此输入都需要调用此回调函数的信号。
let genCallback: AURenderCallback = { (
inRefCon,
ioActionFlags,
inTimeStamp,
inBusNumber,
frameCount,
ioData) -> OSStatus in
let audioObject = unsafeBitCast(inRefCon, to: AudioEngine.self)
for buffer in UnsafeMutableAudioBufferListPointer(ioData!) {
var frames = buffer.mData!.assumingMemoryBound(to: Float.self)
var j = 0
for i in stride(from: 0, to: Int(frameCount), by: 2) {
frames[i] = Float((audioObject.Stimulus[j + audioObject.stimulusReadIndex]))
j += 1
}
audioObject.stimulusReadIndex += Int(frameCount/2)
}
}
return noErr;
}
其中 audioObject.Stimulus 是我的 SineArray,而 audioObject.stimulusReadIndex 只是一个计数器,用于记住已在数组中读取的内容。
现在,这就是我遇到麻烦的地方。如果我启动 AUGraph,我会听到我的正弦波,但我也会听到很多谐波(噪声)。看来这不是正确的格式。
如果我将每组帧复制到另一个数组中以测试写入的内容是否正确,则输出与输入刺激相匹配,因此不会丢失样本。
如果我去查看混音器单元的 AudioStreamBasicDescription(因为这是调用渲染回调,我有以下内容:
var audioFormat = AudioStreamBasicDescription()
audioFormat.mSampleRate = 44100.00;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 2;
audioFormat.mBitsPerChannel = 16;
audioFormat.mBytesPerPacket = 4;
audioFormat.mBytesPerFrame = 4;
audioFormat.mReserved = 0;
status = AudioUnitSetProperty(mixerUnit!,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
1,
&stimFormat,
UInt32(MemoryLayout<AudioStreamBasicDescription>.size));
checkStatus(status: status!);
所以这告诉了我一些事情。它需要两个通道,并且是交错的(因为不存在非交错标志)。在我的回调函数中,我将帧跨步 2 以仅在第一个通道中填充样本。如果我从 1 开始,并播放音频,则写入并播放回右侧。
采样率是正确的,但是比特率是 16(Float 不是),我可以看到有一个“isSignedInteger”标志,所以这是一种不同的格式。
所以现在,我尝试使用以下方法将我的浮点数组转换为 Int16:
for i in 0..<sineArray.count{
sineArray[i] = Int16.init((32767 * sweepSamples[i]))
}
然而,这仍然会产生不同的噪音,尽管不同。如果我检查数组,我可以确认结果是有符号的 int16 落在数据范围内。
我看不到如何以核心音频期望看到的格式表示这些数据。我尝试将格式标志更改为 kAudioFormatFlagIsFloat 但仍然没有运气。
【问题讨论】:
标签: swift audio buffer core-audio