You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
61 lines
2.2 KiB
61 lines
2.2 KiB
/// Stereo 4-point Hermite resampler for small rate corrections and 44.1 ↔ 48 kHz.
|
|
///
|
|
/// `step` is input frames per output frame (1.0 = no change). Allocation-free; safe on the render thread.
|
|
public struct Resampler: Sendable {
|
|
// History per channel: x[-1], x[0], x[1], x[2]. Output is interpolated between x[0] and x[1].
|
|
private var left: (Float, Float, Float, Float) = (0, 0, 0, 0)
|
|
private var right: (Float, Float, Float, Float) = (0, 0, 0, 0)
|
|
private var fraction: Double = 0
|
|
|
|
public init() {}
|
|
|
|
/// Number of input frames `process` will consume for `outputFrames` at `step`.
|
|
public func inputFramesNeeded(outputFrames: Int, step: Double) -> Int {
|
|
var position = fraction
|
|
var consumed = 0
|
|
for _ in 0..<outputFrames {
|
|
position += step
|
|
while position >= 1 {
|
|
position -= 1
|
|
consumed += 1
|
|
}
|
|
}
|
|
return consumed
|
|
}
|
|
|
|
/// Consumes exactly `inputFramesNeeded(outputFrames:step:)` interleaved stereo frames from `input`
|
|
/// and writes `outputFrames` interleaved stereo frames to `output`.
|
|
public mutating func process(
|
|
input: UnsafePointer<Float>, output: UnsafeMutablePointer<Float>, outputFrames: Int, step: Double
|
|
) {
|
|
var read = 0
|
|
for frame in 0..<outputFrames {
|
|
let t = Float(fraction)
|
|
output[frame * 2] = Self.hermite(left, t)
|
|
output[frame * 2 + 1] = Self.hermite(right, t)
|
|
fraction += step
|
|
while fraction >= 1 {
|
|
fraction -= 1
|
|
left = (left.1, left.2, left.3, input[read * 2])
|
|
right = (right.1, right.2, right.3, input[read * 2 + 1])
|
|
read += 1
|
|
}
|
|
}
|
|
}
|
|
|
|
public mutating func reset() {
|
|
left = (0, 0, 0, 0)
|
|
right = (0, 0, 0, 0)
|
|
fraction = 0
|
|
}
|
|
|
|
@inline(__always)
|
|
private static func hermite(_ x: (Float, Float, Float, Float), _ t: Float) -> Float {
|
|
let c0 = x.1
|
|
let c1 = 0.5 * (x.2 - x.0)
|
|
let c2 = x.0 - 2.5 * x.1 + 2 * x.2 - 0.5 * x.3
|
|
let c3 = 0.5 * (x.3 - x.0) + 1.5 * (x.1 - x.2)
|
|
return ((c3 * t + c2) * t + c1) * t + c0
|
|
}
|
|
}
|