| import Foundation |
|
|
| |
| func writeWAV(_ samples: [Float], to url: URL, sampleRate: Int = 24_000) throws { |
| let numSamples = samples.count |
| let dataSize = numSamples * 2 |
| var data = Data() |
|
|
| |
| data.append(contentsOf: "RIFF".utf8) |
| var chunkSize = UInt32(36 + dataSize).littleEndian |
| data.append(Data(bytes: &chunkSize, count: 4)) |
| data.append(contentsOf: "WAVE".utf8) |
|
|
| |
| 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.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) |
| } |
|
|