2022-02-13 04:11:04 +03:00

87 lines
3.2 KiB
Swift

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)
}
public final class AudioWaveform: Equatable {
public let samples: Data
public let peak: Int32
public init(samples: Data, peak: Int32) {
self.samples = samples
self.peak = peak
}
public 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 -> Void in
result.withUnsafeMutableBytes { samples -> Void in
let norm = Int64((1 << bitsPerSample) - 1)
for i in 0 ..< numSamples {
samples.baseAddress!.assumingMemoryBound(to: Int16.self)[i] = Int16(Int64(getBits(data: bytes.baseAddress!.assumingMemoryBound(to: Int8.self), length: bitstream.count, bitOffset: i * 5, numBits: 5)) * norm / norm)
}
}
}
self.init(samples: result, peak: 31)
}
public 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 { rawSamples -> Void in
let samples = rawSamples.baseAddress!.assumingMemoryBound(to: Int16.self)
result.withUnsafeMutableBytes { rawBytes -> Void in
let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int16.self)
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
}
public static func ==(lhs: AudioWaveform, rhs: AudioWaveform) -> Bool {
return lhs.peak == rhs.peak && lhs.samples == rhs.samples
}
}