mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
87 lines
3.2 KiB
Swift
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
|
|
}
|
|
}
|