我正在读取输入文件并使用离线手动渲染模式,我想执行幅度调制并将结果写入输出文件。
为了测试,我产生纯正弦波——这适用于低于 6.000 Hz 的频率。对于更高的频率(我的目标是使用大约 20.000 Hz),信号(因此监听输出文件)会失真,并且频谱在 8.000 Hz 处结束 - 不再有纯频谱,在 0 到 8.000 Hz 之间有多个峰值。
这是我的代码片段:
let outputFile: AVAudioFile
do {
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let outputURL = documentsURL.appendingPathComponent("output.caf")
outputFile = try AVAudioFile(forWriting: outputURL, settings: sourceFile.fileFormat.settings)
} catch {
fatalError("Unable to open output audio file: \(error).")
}
var sampleTime: Float32 = 0
while engine.manualRenderingSampleTime < sourceFile.length {
do {
let frameCount = sourceFile.length - engine.manualRenderingSampleTime
let framesToRender = min(AVAudioFrameCount(frameCount), buffer.frameCapacity)
let status = try engine.renderOffline(framesToRender, to: buffer)
switch status {
case .success:
// The data rendered successfully. Write it to the output file.
let sampleRate:Float = Float((mixer.outputFormat(forBus: 0).sampleRate))
let modulationFrequency: Float = 20000.0
for i in stride(from:0, to: Int(buffer.frameLength), by: 1) {
let val = sinf(2.0 * .pi * modulationFrequency * Float(sampleTime) / Float(sampleRate))
// TODO: perform modulation later
buffer.floatChannelData?.pointee[Int(i)] = val
sampleTime = sampleTime + 1.0
}
try outputFile.write(from: buffer)
case .insufficientDataFromInputNode:
// Applicable only when using the input node as one of the sources.
break
case .cannotDoInCurrentContext:
// The engine couldn't render in the current render call.
// Retry in the next iteration.
break
case .error:
// An error occurred while rendering the audio.
fatalError("The manual rendering failed.")
@unknown default:
fatalError("unknown error")
}
} catch {
fatalError("The manual rendering failed: \(error).")
}
}
我的问题:有s.th。我的代码错了吗?或者有谁知道如何生成具有更高频率正弦波的输出文件?
我想手动渲染模式不够快,无法处理更高的频率。
更新:与此同时,我确实用 Audacity 分析了输出文件。上图为 1.000 Hz 的波形,下图为 20.000 Hz 的波形:
奇怪的是,随着频率的升高,幅度趋近于零。此外,我在第二个频谱中看到更多频率。
与结果相关的一个新问题是以下算法的正确性:
// Process the audio in `renderBuffer` here
for i in 0..<Int(renderBuffer.frameLength) {
let val = sinf(1000.0*Float(index) *2 * .pi / Float(sampleRate))
renderBuffer.floatChannelData?.pointee[i] = val
index += 1
}
我确实检查了采样率,即 48000 - 我知道当采样频率大于被采样信号的最大频率的两倍时,可以忠实地重建原始信号。
更新 2:
我更改了如下设置:
settings[AVFormatIDKey] = kAudioFormatAppleLossless
settings[AVAudioFileTypeKey] = kAudioFileCAFType
settings[AVSampleRateKey] = readBuffer.format.sampleRate
settings[AVNumberOfChannelsKey] = 1
settings[AVLinearPCMIsFloatKey] = (readBuffer.format.commonFormat == .pcmFormatInt32)
settings[AVSampleRateConverterAudioQualityKey] = AVAudioQuality.max
settings[AVLinearPCMBitDepthKey] = 32
settings[AVEncoderAudioQualityKey] = AVAudioQuality.max
现在输出信号的质量更好,但并不完美。我得到更高的幅度,但在频谱分析仪中总是不止一个频率。也许解决方法可以包括应用高通滤波器?
与此同时,我确实使用了一种 SignalGenerator,将经过处理的缓冲区(使用正弦波)直接传输到扬声器——在这种情况下,输出是完美的。我认为将信号路由到文件会导致此类问题。