Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions Sources/AudioSnapshotTesting/Internal/AudioDataComparator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,25 @@ enum AudioDataComparator {
/// This matches the quantization that ALAC applies during encoding.
private static func quantize(_ buffer: AVAudioPCMBuffer, bitDepth: AudioBitDepth) throws -> AVAudioPCMBuffer {
let intFormat: AVAudioFormat?
switch bitDepth {
case .bits16:
let commonFormat: AVAudioCommonFormat = bitDepth == .bits16 ? .pcmFormatInt16 : .pcmFormatInt32

// For multi-channel audio (>2 channels), we need to preserve the channel layout
if let channelLayout = buffer.format.channelLayout {
intFormat = AVAudioFormat(
commonFormat: .pcmFormatInt16,
commonFormat: commonFormat,
sampleRate: buffer.format.sampleRate,
channels: buffer.format.channelCount,
interleaved: false
interleaved: false,
channelLayout: channelLayout
)
case .bits32:
} else {
intFormat = AVAudioFormat(
commonFormat: .pcmFormatInt32,
commonFormat: commonFormat,
sampleRate: buffer.format.sampleRate,
channels: buffer.format.channelCount,
interleaved: false
)
}

guard let intFormat else {
throw AudioComparisonError.formatCreationFailed
}
Expand Down
45 changes: 38 additions & 7 deletions Tests/AudioSnapshotTestingTests/AudioSnapshotTestingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,45 @@ func audioSnapshotSynthesized() async throws {
)
}

private func createBuffer(from samples: [Float]) -> AVAudioPCMBuffer {
let format = AVAudioFormat(standardFormatWithSampleRate: 32768, channels: 1)!
let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(samples.count))!
let channelData = buffer.floatChannelData![0]
samples.enumerated().forEach { index, sample in
channelData[index] = sample
@available(iOS 16, macOS 13, *)
@Test(
"Multi-channel (4ch) audio comparison",
.audioSnapshot(record: false, strategy: .spectrogram(hopSize: 4096, frequencyCount: 2048))
)
func multiChannelComparison() async throws {
let frameCount = 44100
let frequencies: [Float] = [440, 880, 1320, 1760]
let channels = frequencies.map { frequency in
synthesizeSignal(frequencyAmplitudePairs: [(frequency, 0.5)], count: frameCount)
}
let buffer = createBuffer(channels: channels, sampleRate: 44100)
await assertAudioSnapshot(of: buffer, named: "multiChannelComparison.4ch")
}

private func createBuffer(from samples: [Float], sampleRate: Double = 32768) -> AVAudioPCMBuffer {
createBuffer(channels: [samples], sampleRate: sampleRate)
}

private func createBuffer(channels: [[Float]], sampleRate: Double = 32768) -> AVAudioPCMBuffer {
let channelCount = channels.count
let frameCount = channels.first?.count ?? 0

let format: AVAudioFormat
if channelCount <= 2 {
format = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: AVAudioChannelCount(channelCount))!
} else {
let layout = AVAudioChannelLayout(layoutTag: kAudioChannelLayoutTag_DiscreteInOrder | UInt32(channelCount))!
format = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channelLayout: layout)
}

let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(frameCount))!
for (channelIndex, samples) in channels.enumerated() {
let channelData = buffer.floatChannelData![channelIndex]
for (frameIndex, sample) in samples.enumerated() {
channelData[frameIndex] = sample
}
}
buffer.frameLength = AVAudioFrameCount(samples.count)
buffer.frameLength = AVAudioFrameCount(frameCount)
return buffer
}

Expand Down
Binary file not shown.