import Foundation private func getBits(data: UnsafeRawPointer, length: Int, bitOffset: Int, numBits: Int) -> Int32 { let normalizedNumBits = Int(pow(2.0, Double(numBits))) - 1 let byteOffset = bitOffset / 8 let normalizedData = data.advanced(by: byteOffset) let normalizedBitOffset = bitOffset % 8 var value: Int32 = 0 if byteOffset + 4 > length { let remaining = length - byteOffset withUnsafeMutableBytes(of: &value, { (bytes: UnsafeMutableRawBufferPointer) -> Void in memcpy(bytes.baseAddress!, normalizedData, remaining) }) } else { value = normalizedData.assumingMemoryBound(to: Int32.self).pointee } return (value >> Int32(normalizedBitOffset)) & Int32(normalizedNumBits) } private func setBits(data: UnsafeMutableRawPointer, bitOffset: Int, numBits: Int, value: Int32) { let normalizedData = data.advanced(by: bitOffset / 8) let normalizedBitOffset = bitOffset % 8 normalizedData.assumingMemoryBound(to: Int32.self).pointee |= value << Int32(normalizedBitOffset) } final class AudioWaveform: Equatable { let samples: Data let peak: Int32 init(samples: Data, peak: Int32) { self.samples = samples self.peak = peak } convenience init(bitstream: Data, bitsPerSample: Int) { let numSamples = Int(Float(bitstream.count * 8) / Float(bitsPerSample)) var result = Data() result.count = numSamples * 2 bitstream.withUnsafeBytes { (bytes: UnsafePointer) -> Void in result.withUnsafeMutableBytes { (samples: UnsafeMutablePointer) -> Void in let norm = Int64((1 << bitsPerSample) - 1) for i in 0 ..< numSamples { samples[i] = Int16(Int64(getBits(data: bytes, length: bitstream.count, bitOffset: i * 5, numBits: 5)) * norm / norm) } } } self.init(samples: result, peak: 31) } func makeBitstream() -> Data { let numSamples = self.samples.count / 2 let bitstreamLength = (numSamples * 5) / 8 + (((numSamples * 5) % 8) == 0 ? 0 : 1) var result = Data() result.count = bitstreamLength + 4 let maxSample: Int32 = self.peak self.samples.withUnsafeBytes { (samples: UnsafePointer) -> Void in result.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in for i in 0 ..< numSamples { let value: Int32 = min(Int32(31), abs(Int32(samples[i])) * 31 / maxSample) if i == 99 { assert(true) } setBits(data: bytes, bitOffset: i * 5, numBits: 5, value: value & Int32(31)) } } } result.count = bitstreamLength return result } static func ==(lhs: AudioWaveform, rhs: AudioWaveform) -> Bool { return lhs.peak == rhs.peak && lhs.samples == rhs.samples } }