Skip to content

Instantly share code, notes, and snippets.

@moutend
Created March 26, 2021 00:58
Show Gist options
  • Save moutend/ac500588c52c9c94ca9dae2fee719891 to your computer and use it in GitHub Desktop.
Save moutend/ac500588c52c9c94ca9dae2fee719891 to your computer and use it in GitHub Desktop.
[Swift] read and write WAV audio file with AVAudioFile

This script reads /tmp/input.wav and writes the copy of input as /tmp/output.wav.

$ swift main.swift
import AVFoundation
func readPCMBuffer(url: URL) -> AVAudioPCMBuffer? {
guard let input = try? AVAudioFile(forReading: url, commonFormat: .pcmFormatInt16, interleaved: false) else {
return nil
}
guard let buffer = AVAudioPCMBuffer(pcmFormat: input.processingFormat, frameCapacity: AVAudioFrameCount(input.length)) else {
return nil
}
do {
try input.read(into: buffer)
} catch {
return nil
}
return buffer
}
func writePCMBuffer(url: URL, buffer: AVAudioPCMBuffer) throws {
let settings: [String: Any] = [
AVFormatIDKey: buffer.format.settings[AVFormatIDKey] ?? kAudioFormatLinearPCM,
AVNumberOfChannelsKey: buffer.format.settings[AVNumberOfChannelsKey] ?? 2,
AVSampleRateKey: buffer.format.settings[AVSampleRateKey] ?? 44100,
AVLinearPCMBitDepthKey: buffer.format.settings[AVLinearPCMBitDepthKey] ?? 16
]
do {
let output = try AVAudioFile(forWriting: url, settings: settings, commonFormat: .pcmFormatInt16, interleaved: false)
try output.write(from: buffer)
} catch {
throw error
}
}
func copyPCMBuffer(from inputPath: String, to outputPath: String) {
guard let inputBuffer = readPCMBuffer(url: URL(string: inputPath)!) else {
fatalError("failed to read \(inputPath)")
}
guard let outputBuffer = AVAudioPCMBuffer(pcmFormat: inputBuffer.format, frameCapacity: inputBuffer.frameLength) else {
fatalError("failed to create a buffer for writing")
}
guard let inputInt16ChannelData = inputBuffer.int16ChannelData else {
fatalError("failed to obtain underlying input buffer")
}
guard let outputInt16ChannelData = outputBuffer.int16ChannelData else {
fatalError("failed to obtain underlying output buffer")
}
for channel in 0 ..< Int(inputBuffer.format.channelCount) {
let p1: UnsafeMutablePointer<Int16> = inputInt16ChannelData[channel]
let p2: UnsafeMutablePointer<Int16> = outputInt16ChannelData[channel]
for i in 0 ..< Int(inputBuffer.frameLength) {
p2[i] = p1[i]
}
}
outputBuffer.frameLength = inputBuffer.frameLength
do {
try writePCMBuffer(url: URL(string: outputPath)!, buffer: outputBuffer)
} catch {
fatalError("failed to write \(outputPath)")
}
}
copyPCMBuffer(from: "file:///tmp/input.wav", to: "file:///tmp/output.wav")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment