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.
Musubi/Packages/MusubiKit/Sources/AudioMatrix/AudioFeed.swift

55 lines
2.1 KiB

import CAudioRing
import Foundation
/// Producer side of one route: takes audio from any thread (NDI, input device) into a stereo ring buffer.
///
/// One feed has exactly one producer and one consumer (the route on the render thread).
public final class AudioFeed: @unchecked Sendable {
let ring: OpaquePointer
/// Sample rate of the audio in the ring. Written by the producer, read by the render thread.
private(set) var sampleRate: Double = 0
// Producer-only scratch for interleaving.
private var scratch: UnsafeMutablePointer<Float>
private var scratchFrames = 0
public init(capacitySeconds: Double = 1, maxSampleRate: Double = 96_000) {
ring = musubi_ring_create(UInt32(capacitySeconds * maxSampleRate), 2)!
scratchFrames = 4096
scratch = .allocate(capacity: scratchFrames * 2)
}
deinit {
musubi_ring_destroy(ring)
scratch.deallocate()
}
/// Pushes planar audio. Mono is duplicated to both channels; channels beyond two are ignored.
public func push(planar data: UnsafePointer<Float>, channelStride: Int, channels: Int, frames: Int, sampleRate: Double) {
guard channels > 0, frames > 0 else { return }
self.sampleRate = sampleRate
ensureScratch(frames)
let left = data
let right = channels > 1 ? data + channelStride : data
for i in 0..<frames {
scratch[i * 2] = left[i]
scratch[i * 2 + 1] = right[i]
}
musubi_ring_write(ring, scratch, UInt32(frames))
}
/// Consumer side for taps: reads up to `frames` interleaved stereo frames; returns the number read.
public func read(into interleaved: UnsafeMutablePointer<Float>, frames: Int) -> Int {
Int(musubi_ring_read(ring, interleaved, UInt32(frames)))
}
/// Sample rate of the most recent push (0 before the first).
public var currentSampleRate: Double { sampleRate }
private func ensureScratch(_ frames: Int) {
guard frames > scratchFrames else { return }
scratch.deallocate()
scratchFrames = frames
scratch = .allocate(capacity: frames * 2)
}
}

Powered by TurnKey Linux.