import Foundation /// Writes audio samples to a 16-bit PCM WAV file. func writeWAV(_ samples: [Float], to url: URL, sampleRate: Int = 24_000) throws { let numSamples = samples.count let dataSize = numSamples * 2 // 16-bit PCM var data = Data() // RIFF header data.append(contentsOf: "RIFF".utf8) var chunkSize = UInt32(36 + dataSize).littleEndian data.append(Data(bytes: &chunkSize, count: 4)) data.append(contentsOf: "WAVE".utf8) // fmt chunk data.append(contentsOf: "fmt ".utf8) var fmtSize = UInt32(16).littleEndian; data.append(Data(bytes: &fmtSize, count: 4)) var audioFormat = UInt16(1).littleEndian; data.append(Data(bytes: &audioFormat, count: 2)) var channels = UInt16(1).littleEndian; data.append(Data(bytes: &channels, count: 2)) var sr = UInt32(sampleRate).littleEndian; data.append(Data(bytes: &sr, count: 4)) var byteRate = UInt32(sampleRate * 2).littleEndian; data.append(Data(bytes: &byteRate, count: 4)) var blockAlign = UInt16(2).littleEndian; data.append(Data(bytes: &blockAlign, count: 2)) var bitsPerSample = UInt16(16).littleEndian; data.append(Data(bytes: &bitsPerSample, count: 2)) // data chunk data.append(contentsOf: "data".utf8) var dataChunkSize = UInt32(dataSize).littleEndian; data.append(Data(bytes: &dataChunkSize, count: 4)) for sample in samples { let clamped = max(-1.0, min(1.0, sample)) var pcm = Int16(clamped * 32767.0).littleEndian data.append(Data(bytes: &pcm, count: 2)) } try data.write(to: url) }