Seed Swift package for demucs-rs SDK

Package.swift (binary target placeholder + Demucs wrapper target), README, and UniFFI-generated demucs.swift. The release workflow in ondeinference/demucs-rs rewrites the binary target URL/checksum and regenerates demucs.swift on every swift-X.Y.Z tag. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PMgTdQhdPV6h4XXpNKRKn7

Claude committed Jul 9, 2026 at 10:19 UTC 6f1f785a9350c0892ee85a624262a08d4e2bf654
4 files changed +2292
.gitignore new
+2
@@ -0,0 +1,2 @@
1 +.DS_Store
2 +.build/
Package.swift new
+41
@@ -0,0 +1,41 @@
1 +// swift-tools-version:5.9
2 +import PackageDescription
3 +
4 +// These two constants are rewritten automatically by the demucs-rs
5 +// "Release SDK Swift" workflow on every release. Do not reformat them —
6 +// the rewrite regex depends on this exact layout.
7 +//
8 +// For local development against a locally built framework, comment out the
9 +// url/checksum binaryTarget below and use the path form instead:
10 +// .binaryTarget(name: "DemucsFramework", path: "../demucs-rs/dist/swift/DemucsFramework.xcframework"),
11 +// (run .github/scripts/build-swift-xcframework.sh in demucs-rs first).
12 +// Never commit the path form — CI overwrites this file on every release.
13 +let releaseFrameworkURL =
14 + "https://github.com/ondeinference/demucs-rs/releases/download/swift-0.1.0/DemucsFramework.xcframework.zip"
15 +let releaseFrameworkChecksum =
16 + "0000000000000000000000000000000000000000000000000000000000000000"
17 +
18 +let package = Package(
19 + name: "Demucs",
20 + platforms: [
21 + .iOS(.v16),
22 + .macOS(.v14),
23 + .tvOS(.v16),
24 + .visionOS(.v1),
25 + ],
26 + products: [
27 + .library(name: "Demucs", targets: ["Demucs"])
28 + ],
29 + targets: [
30 + .binaryTarget(
31 + name: "DemucsFramework",
32 + url: releaseFrameworkURL,
33 + checksum: releaseFrameworkChecksum
34 + ),
35 + .target(
36 + name: "Demucs",
37 + dependencies: ["DemucsFramework"],
38 + path: "Sources/Demucs"
39 + ),
40 + ]
41 +)
README.md new
+80
@@ -0,0 +1,80 @@
1 +# demucs-swift
2 +
3 +Swift SDK for [demucs-rs](https://github.com/ondeinference/demucs-rs) — on-device
4 +music source separation (HTDemucs v4) for iOS, macOS, tvOS, and visionOS,
5 +GPU-accelerated via Metal.
6 +
7 +> **This repository is machine-published.** Every release of
8 +> [demucs-rs](https://github.com/ondeinference/demucs-rs) rewrites
9 +> `Package.swift` and `Sources/Demucs/demucs.swift` via CI. Do not edit them
10 +> by hand — changes belong in the `demucs-ffi` crate in demucs-rs.
11 +
12 +## Installation
13 +
14 +```swift
15 +dependencies: [
16 + .package(url: "https://github.com/ondeinference/demucs-swift", from: "0.1.0")
17 +]
18 +```
19 +
20 +## Usage
21 +
22 +```swift
23 +import Demucs
24 +
25 +// 1. Sandboxed platforms (iOS/tvOS/visionOS): point the weight cache inside
26 +// the app container once at launch.
27 +let caches = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
28 +configureCacheDir(path: caches.appendingPathComponent("demucs").path)
29 +
30 +// 2. Download weights (84–333 MB, from HuggingFace, cached on disk).
31 +final class DownloadHandler: DownloadProgressListener {
32 + func onProgress(progress: DownloadProgress) -> Bool {
33 + print("download \(Int(progress.fraction * 100))%")
34 + return true // return false to cancel
35 + }
36 +}
37 +try await downloadModel(model: .fourStem, listener: DownloadHandler())
38 +
39 +// 3. Load the model and pre-compile GPU shaders.
40 +let engine = DemucsEngine()
41 +let seconds = try await engine.loadModel(model: .fourStem)
42 +try await engine.warmup()
43 +
44 +// 4. Separate. Input is per-channel PCM at any sample rate (use AVFoundation
45 +// to decode files); output stems are stereo PCM at 44100 Hz.
46 +final class ProgressHandler: SeparationProgressListener {
47 + func onProgress(progress: SeparationProgress) -> Bool {
48 + print("separating \(Int(progress.fraction * 100))%")
49 + return true // return false to cancel
50 + }
51 +}
52 +let stems = try await separateWithProgress(
53 + engine: engine,
54 + left: leftSamples, right: rightSamples,
55 + sampleRate: 44100,
56 + listener: ProgressHandler()
57 +)
58 +for stem in stems {
59 + print(stem.kind, stem.left.count)
60 +}
61 +
62 +// Or without progress reporting:
63 +let stems2 = try await engine.separate(left: leftSamples, right: rightSamples, sampleRate: 44100)
64 +```
65 +
66 +## Models
67 +
68 +| Model | Case | Stems | Size |
69 +|-------|------|-------|------|
70 +| htdemucs | `.fourStem` | drums, bass, other, vocals | ~84 MB |
71 +| htdemucs_6s | `.sixStem` | + guitar, piano | ~84 MB |
72 +| htdemucs_ft | `.fineTuned(stems:)` | up to 4, best quality | ~333 MB |
73 +
74 +Weights download from HuggingFace on demand and are cached locally
75 +(`allModels()`, `isModelCached(model:)`, `deleteCachedModel(model:)` manage
76 +the cache).
77 +
78 +## License
79 +
80 +Apache-2.0, same as demucs-rs.
Sources/Demucs/demucs.swift new
+2169
@@ -0,0 +1,2169 @@
1 +// This file was autogenerated by some hot garbage in the `uniffi` crate.
2 +// Trust me, you don't want to mess with it!
3 +
4 +// swiftlint:disable all
5 +import Foundation
6 +
7 +// Depending on the consumer's build setup, the low-level FFI code
8 +// might be in a separate module, or it might be compiled inline into
9 +// this module. This is a bit of light hackery to work with both.
10 +#if canImport(demucsFFI)
11 +import demucsFFI
12 +#endif
13 +
14 +fileprivate extension RustBuffer {
15 + // Allocate a new buffer, copying the contents of a `UInt8` array.
16 + init(bytes: [UInt8]) {
17 + let rbuf = bytes.withUnsafeBufferPointer { ptr in
18 + RustBuffer.from(ptr)
19 + }
20 + self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data)
21 + }
22 +
23 + static func empty() -> RustBuffer {
24 + RustBuffer(capacity: 0, len:0, data: nil)
25 + }
26 +
27 + static func from(_ ptr: UnsafeBufferPointer<UInt8>) -> RustBuffer {
28 + try! rustCall { ffi_demucs_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) }
29 + }
30 +
31 + // Frees the buffer in place.
32 + // The buffer must not be used after this is called.
33 + func deallocate() {
34 + try! rustCall { ffi_demucs_rustbuffer_free(self, $0) }
35 + }
36 +}
37 +
38 +fileprivate extension ForeignBytes {
39 + init(bufferPointer: UnsafeBufferPointer<UInt8>) {
40 + self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress)
41 + }
42 +}
43 +
44 +// For every type used in the interface, we provide helper methods for conveniently
45 +// lifting and lowering that type from C-compatible data, and for reading and writing
46 +// values of that type in a buffer.
47 +
48 +// Helper classes/extensions that don't change.
49 +// Someday, this will be in a library of its own.
50 +
51 +fileprivate extension Data {
52 + init(rustBuffer: RustBuffer) {
53 + self.init(
54 + bytesNoCopy: rustBuffer.data!,
55 + count: Int(rustBuffer.len),
56 + deallocator: .none
57 + )
58 + }
59 +}
60 +
61 +// Define reader functionality. Normally this would be defined in a class or
62 +// struct, but we use standalone functions instead in order to make external
63 +// types work.
64 +//
65 +// With external types, one swift source file needs to be able to call the read
66 +// method on another source file's FfiConverter, but then what visibility
67 +// should Reader have?
68 +// - If Reader is fileprivate, then this means the read() must also
69 +// be fileprivate, which doesn't work with external types.
70 +// - If Reader is internal/public, we'll get compile errors since both source
71 +// files will try define the same type.
72 +//
73 +// Instead, the read() method and these helper functions input a tuple of data
74 +
75 +fileprivate func createReader(data: Data) -> (data: Data, offset: Data.Index) {
76 + (data: data, offset: 0)
77 +}
78 +
79 +// Reads an integer at the current offset, in big-endian order, and advances
80 +// the offset on success. Throws if reading the integer would move the
81 +// offset past the end of the buffer.
82 +fileprivate func readInt<T: FixedWidthInteger>(_ reader: inout (data: Data, offset: Data.Index)) throws -> T {
83 + let range = reader.offset..<reader.offset + MemoryLayout<T>.size
84 + guard reader.data.count >= range.upperBound else {
85 + throw UniffiInternalError.bufferOverflow
86 + }
87 + if T.self == UInt8.self {
88 + let value = reader.data[reader.offset]
89 + reader.offset += 1
90 + return value as! T
91 + }
92 + var value: T = 0
93 + let _ = withUnsafeMutableBytes(of: &value, { reader.data.copyBytes(to: $0, from: range)})
94 + reader.offset = range.upperBound
95 + return value.bigEndian
96 +}
97 +
98 +// Reads an arbitrary number of bytes, to be used to read
99 +// raw bytes, this is useful when lifting strings
100 +fileprivate func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> Array<UInt8> {
101 + let range = reader.offset..<(reader.offset+count)
102 + guard reader.data.count >= range.upperBound else {
103 + throw UniffiInternalError.bufferOverflow
104 + }
105 + var value = [UInt8](repeating: 0, count: count)
106 + value.withUnsafeMutableBufferPointer({ buffer in
107 + reader.data.copyBytes(to: buffer, from: range)
108 + })
109 + reader.offset = range.upperBound
110 + return value
111 +}
112 +
113 +// Reads a float at the current offset.
114 +fileprivate func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float {
115 + return Float(bitPattern: try readInt(&reader))
116 +}
117 +
118 +// Reads a float at the current offset.
119 +fileprivate func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double {
120 + return Double(bitPattern: try readInt(&reader))
121 +}
122 +
123 +// Indicates if the offset has reached the end of the buffer.
124 +fileprivate func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool {
125 + return reader.offset < reader.data.count
126 +}
127 +
128 +// Define writer functionality. Normally this would be defined in a class or
129 +// struct, but we use standalone functions instead in order to make external
130 +// types work. See the above discussion on Readers for details.
131 +
132 +fileprivate func createWriter() -> [UInt8] {
133 + return []
134 +}
135 +
136 +fileprivate func writeBytes<S>(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 {
137 + writer.append(contentsOf: byteArr)
138 +}
139 +
140 +// Writes an integer in big-endian order.
141 +//
142 +// Warning: make sure what you are trying to write
143 +// is in the correct type!
144 +fileprivate func writeInt<T: FixedWidthInteger>(_ writer: inout [UInt8], _ value: T) {
145 + var value = value.bigEndian
146 + withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) }
147 +}
148 +
149 +fileprivate func writeFloat(_ writer: inout [UInt8], _ value: Float) {
150 + writeInt(&writer, value.bitPattern)
151 +}
152 +
153 +fileprivate func writeDouble(_ writer: inout [UInt8], _ value: Double) {
154 + writeInt(&writer, value.bitPattern)
155 +}
156 +
157 +// Protocol for types that transfer other types across the FFI. This is
158 +// analogous to the Rust trait of the same name.
159 +fileprivate protocol FfiConverter {
160 + associatedtype FfiType
161 + associatedtype SwiftType
162 +
163 + static func lift(_ value: FfiType) throws -> SwiftType
164 + static func lower(_ value: SwiftType) -> FfiType
165 + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType
166 + static func write(_ value: SwiftType, into buf: inout [UInt8])
167 +}
168 +
169 +// Types conforming to `Primitive` pass themselves directly over the FFI.
170 +fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { }
171 +
172 +extension FfiConverterPrimitive {
173 +#if swift(>=5.8)
174 + @_documentation(visibility: private)
175 +#endif
176 + public static func lift(_ value: FfiType) throws -> SwiftType {
177 + return value
178 + }
179 +
180 +#if swift(>=5.8)
181 + @_documentation(visibility: private)
182 +#endif
183 + public static func lower(_ value: SwiftType) -> FfiType {
184 + return value
185 + }
186 +}
187 +
188 +// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`.
189 +// Used for complex types where it's hard to write a custom lift/lower.
190 +fileprivate protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {}
191 +
192 +extension FfiConverterRustBuffer {
193 +#if swift(>=5.8)
194 + @_documentation(visibility: private)
195 +#endif
196 + public static func lift(_ buf: RustBuffer) throws -> SwiftType {
197 + var reader = createReader(data: Data(rustBuffer: buf))
198 + let value = try read(from: &reader)
199 + if hasRemaining(reader) {
200 + throw UniffiInternalError.incompleteData
201 + }
202 + buf.deallocate()
203 + return value
204 + }
205 +
206 +#if swift(>=5.8)
207 + @_documentation(visibility: private)
208 +#endif
209 + public static func lower(_ value: SwiftType) -> RustBuffer {
210 + var writer = createWriter()
211 + write(value, into: &writer)
212 + return RustBuffer(bytes: writer)
213 + }
214 +}
215 +// An error type for FFI errors. These errors occur at the UniFFI level, not
216 +// the library level.
217 +fileprivate enum UniffiInternalError: LocalizedError {
218 + case bufferOverflow
219 + case incompleteData
220 + case unexpectedOptionalTag
221 + case unexpectedEnumCase
222 + case unexpectedNullPointer
223 + case unexpectedRustCallStatusCode
224 + case unexpectedRustCallError
225 + case unexpectedStaleHandle
226 + case rustPanic(_ message: String)
227 +
228 + public var errorDescription: String? {
229 + switch self {
230 + case .bufferOverflow: return "Reading the requested value would read past the end of the buffer"
231 + case .incompleteData: return "The buffer still has data after lifting its containing value"
232 + case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1"
233 + case .unexpectedEnumCase: return "Raw enum value doesn't match any cases"
234 + case .unexpectedNullPointer: return "Raw pointer value was null"
235 + case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code"
236 + case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified"
237 + case .unexpectedStaleHandle: return "The object in the handle map has been dropped already"
238 + case let .rustPanic(message): return message
239 + }
240 + }
241 +}
242 +
243 +fileprivate extension NSLock {
244 + func withLock<T>(f: () throws -> T) rethrows -> T {
245 + self.lock()
246 + defer { self.unlock() }
247 + return try f()
248 + }
249 +}
250 +
251 +fileprivate let CALL_SUCCESS: Int8 = 0
252 +fileprivate let CALL_ERROR: Int8 = 1
253 +fileprivate let CALL_UNEXPECTED_ERROR: Int8 = 2
254 +fileprivate let CALL_CANCELLED: Int8 = 3
255 +
256 +fileprivate extension RustCallStatus {
257 + init() {
258 + self.init(
259 + code: CALL_SUCCESS,
260 + errorBuf: RustBuffer.init(
261 + capacity: 0,
262 + len: 0,
263 + data: nil
264 + )
265 + )
266 + }
267 +}
268 +
269 +private func rustCall<T>(_ callback: (UnsafeMutablePointer<RustCallStatus>) -> T) throws -> T {
270 + let neverThrow: ((RustBuffer) throws -> Never)? = nil
271 + return try makeRustCall(callback, errorHandler: neverThrow)
272 +}
273 +
274 +private func rustCallWithError<T, E: Swift.Error>(
275 + _ errorHandler: @escaping (RustBuffer) throws -> E,
276 + _ callback: (UnsafeMutablePointer<RustCallStatus>) -> T) throws -> T {
277 + try makeRustCall(callback, errorHandler: errorHandler)
278 +}
279 +
280 +private func makeRustCall<T, E: Swift.Error>(
281 + _ callback: (UnsafeMutablePointer<RustCallStatus>) -> T,
282 + errorHandler: ((RustBuffer) throws -> E)?
283 +) throws -> T {
284 + uniffiEnsureDemucsInitialized()
285 + var callStatus = RustCallStatus.init()
286 + let returnedVal = callback(&callStatus)
287 + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler)
288 + return returnedVal
289 +}
290 +
291 +private func uniffiCheckCallStatus<E: Swift.Error>(
292 + callStatus: RustCallStatus,
293 + errorHandler: ((RustBuffer) throws -> E)?
294 +) throws {
295 + switch callStatus.code {
296 + case CALL_SUCCESS:
297 + return
298 +
299 + case CALL_ERROR:
300 + if let errorHandler = errorHandler {
301 + throw try errorHandler(callStatus.errorBuf)
302 + } else {
303 + callStatus.errorBuf.deallocate()
304 + throw UniffiInternalError.unexpectedRustCallError
305 + }
306 +
307 + case CALL_UNEXPECTED_ERROR:
308 + // When the rust code sees a panic, it tries to construct a RustBuffer
309 + // with the message. But if that code panics, then it just sends back
310 + // an empty buffer.
311 + if callStatus.errorBuf.len > 0 {
312 + throw UniffiInternalError.rustPanic(try FfiConverterString.lift(callStatus.errorBuf))
313 + } else {
314 + callStatus.errorBuf.deallocate()
315 + throw UniffiInternalError.rustPanic("Rust panic")
316 + }
317 +
318 + case CALL_CANCELLED:
319 + fatalError("Cancellation not supported yet")
320 +
321 + default:
322 + throw UniffiInternalError.unexpectedRustCallStatusCode
323 + }
324 +}
325 +
326 +private func uniffiTraitInterfaceCall<T>(
327 + callStatus: UnsafeMutablePointer<RustCallStatus>,
328 + makeCall: () throws -> T,
329 + writeReturn: (T) -> ()
330 +) {
331 + do {
332 + try writeReturn(makeCall())
333 + } catch let error {
334 + callStatus.pointee.code = CALL_UNEXPECTED_ERROR
335 + callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error))
336 + }
337 +}
338 +
339 +private func uniffiTraitInterfaceCallWithError<T, E>(
340 + callStatus: UnsafeMutablePointer<RustCallStatus>,
341 + makeCall: () throws -> T,
342 + writeReturn: (T) -> (),
343 + lowerError: (E) -> RustBuffer
344 +) {
345 + do {
346 + try writeReturn(makeCall())
347 + } catch let error as E {
348 + callStatus.pointee.code = CALL_ERROR
349 + callStatus.pointee.errorBuf = lowerError(error)
350 + } catch {
351 + callStatus.pointee.code = CALL_UNEXPECTED_ERROR
352 + callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error))
353 + }
354 +}
355 +// Initial value and increment amount for handles.
356 +// These ensure that SWIFT handles always have the lowest bit set
357 +fileprivate let UNIFFI_HANDLEMAP_INITIAL: UInt64 = 1
358 +fileprivate let UNIFFI_HANDLEMAP_DELTA: UInt64 = 2
359 +
360 +fileprivate final class UniffiHandleMap<T>: @unchecked Sendable {
361 + // All mutation happens with this lock held, which is why we implement @unchecked Sendable.
362 + private let lock = NSLock()
363 + private var map: [UInt64: T] = [:]
364 + private var currentHandle: UInt64 = UNIFFI_HANDLEMAP_INITIAL
365 +
366 + func insert(obj: T) -> UInt64 {
367 + lock.withLock {
368 + return doInsert(obj)
369 + }
370 + }
371 +
372 + // Low-level insert function, this assumes `lock` is held.
373 + private func doInsert(_ obj: T) -> UInt64 {
374 + let handle = currentHandle
375 + currentHandle += UNIFFI_HANDLEMAP_DELTA
376 + map[handle] = obj
377 + return handle
378 + }
379 +
380 + func get(handle: UInt64) throws -> T {
381 + try lock.withLock {
382 + guard let obj = map[handle] else {
383 + throw UniffiInternalError.unexpectedStaleHandle
384 + }
385 + return obj
386 + }
387 + }
388 +
389 + func clone(handle: UInt64) throws -> UInt64 {
390 + try lock.withLock {
391 + guard let obj = map[handle] else {
392 + throw UniffiInternalError.unexpectedStaleHandle
393 + }
394 + return doInsert(obj)
395 + }
396 + }
397 +
398 + @discardableResult
399 + func remove(handle: UInt64) throws -> T {
400 + try lock.withLock {
401 + guard let obj = map.removeValue(forKey: handle) else {
402 + throw UniffiInternalError.unexpectedStaleHandle
403 + }
404 + return obj
405 + }
406 + }
407 +
408 + var count: Int {
409 + get {
410 + map.count
411 + }
412 + }
413 +}
414 +
415 +
416 +// Public interface members begin here.
417 +// Magic number for the Rust proxy to call using the same mechanism as every other method,
418 +// to free the callback once it's dropped by Rust.
419 +private let IDX_CALLBACK_FREE: Int32 = 0
420 +// Callback return codes
421 +private let UNIFFI_CALLBACK_SUCCESS: Int32 = 0
422 +private let UNIFFI_CALLBACK_ERROR: Int32 = 1
423 +private let UNIFFI_CALLBACK_UNEXPECTED_ERROR: Int32 = 2
424 +
425 +#if swift(>=5.8)
426 +@_documentation(visibility: private)
427 +#endif
428 +fileprivate struct FfiConverterUInt32: FfiConverterPrimitive {
429 + typealias FfiType = UInt32
430 + typealias SwiftType = UInt32
431 +
432 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt32 {
433 + return try lift(readInt(&buf))
434 + }
435 +
436 + public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
437 + writeInt(&buf, lower(value))
438 + }
439 +}
440 +
441 +#if swift(>=5.8)
442 +@_documentation(visibility: private)
443 +#endif
444 +fileprivate struct FfiConverterUInt64: FfiConverterPrimitive {
445 + typealias FfiType = UInt64
446 + typealias SwiftType = UInt64
447 +
448 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt64 {
449 + return try lift(readInt(&buf))
450 + }
451 +
452 + public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
453 + writeInt(&buf, lower(value))
454 + }
455 +}
456 +
457 +#if swift(>=5.8)
458 +@_documentation(visibility: private)
459 +#endif
460 +fileprivate struct FfiConverterFloat: FfiConverterPrimitive {
461 + typealias FfiType = Float
462 + typealias SwiftType = Float
463 +
464 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Float {
465 + return try lift(readFloat(&buf))
466 + }
467 +
468 + public static func write(_ value: Float, into buf: inout [UInt8]) {
469 + writeFloat(&buf, lower(value))
470 + }
471 +}
472 +
473 +#if swift(>=5.8)
474 +@_documentation(visibility: private)
475 +#endif
476 +fileprivate struct FfiConverterDouble: FfiConverterPrimitive {
477 + typealias FfiType = Double
478 + typealias SwiftType = Double
479 +
480 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Double {
481 + return try lift(readDouble(&buf))
482 + }
483 +
484 + public static func write(_ value: Double, into buf: inout [UInt8]) {
485 + writeDouble(&buf, lower(value))
486 + }
487 +}
488 +
489 +#if swift(>=5.8)
490 +@_documentation(visibility: private)
491 +#endif
492 +fileprivate struct FfiConverterBool : FfiConverter {
493 + typealias FfiType = Int8
494 + typealias SwiftType = Bool
495 +
496 + public static func lift(_ value: Int8) throws -> Bool {
497 + return value != 0
498 + }
499 +
500 + public static func lower(_ value: Bool) -> Int8 {
501 + return value ? 1 : 0
502 + }
503 +
504 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bool {
505 + return try lift(readInt(&buf))
506 + }
507 +
508 + public static func write(_ value: Bool, into buf: inout [UInt8]) {
509 + writeInt(&buf, lower(value))
510 + }
511 +}
512 +
513 +#if swift(>=5.8)
514 +@_documentation(visibility: private)
515 +#endif
516 +fileprivate struct FfiConverterString: FfiConverter {
517 + typealias SwiftType = String
518 + typealias FfiType = RustBuffer
519 +
520 + public static func lift(_ value: RustBuffer) throws -> String {
521 + defer {
522 + value.deallocate()
523 + }
524 + if value.data == nil {
525 + return String()
526 + }
527 + let bytes = UnsafeBufferPointer<UInt8>(start: value.data!, count: Int(value.len))
528 + return String(bytes: bytes, encoding: String.Encoding.utf8)!
529 + }
530 +
531 + public static func lower(_ value: String) -> RustBuffer {
532 + return value.utf8CString.withUnsafeBufferPointer { ptr in
533 + // The swift string gives us int8_t, we want uint8_t.
534 + ptr.withMemoryRebound(to: UInt8.self) { ptr in
535 + // The swift string gives us a trailing null byte, we don't want it.
536 + let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1))
537 + return RustBuffer.from(buf)
538 + }
539 + }
540 + }
541 +
542 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String {
543 + let len: Int32 = try readInt(&buf)
544 + return String(bytes: try readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)!
545 + }
546 +
547 + public static func write(_ value: String, into buf: inout [UInt8]) {
548 + let len = Int32(value.utf8.count)
549 + writeInt(&buf, len)
550 + writeBytes(&buf, value.utf8)
551 + }
552 +}
553 +
554 +
555 +
556 +
557 +/**
558 + * Thread-safe HTDemucs source-separation engine.
559 + *
560 + * Typical lifecycle from Swift:
561 + * ```swift
562 + * configureCacheDir(path: appSupportDir) // sandboxed platforms
563 + * try await downloadModel(model: .fourStem, listener: dl)
564 + * let engine = DemucsEngine()
565 + * let secs = try await engine.loadModel(model: .fourStem)
566 + * try await engine.warmup()
567 + * let stems = try await engine.separate(left: l, right: r, sampleRate: 44100)
568 + * ```
569 + */
570 +public protocol DemucsEngineProtocol: AnyObject, Sendable {
571 +
572 + func isLoaded() async -> Bool
573 +
574 + /**
575 + * Load a model's weights from the local cache into memory (and onto the
576 + * GPU device). Errors with `NotCached` if `downloadModel` has not been
577 + * run for this model. Returns the wall-clock load time in seconds.
578 + */
579 + func loadModel(model: DemucsModel) async throws -> Double
580 +
581 + /**
582 + * The model currently loaded, if any.
583 + */
584 + func loadedModel() async -> DemucsModel?
585 +
586 + /**
587 + * Separate a stereo track into stems.
588 + *
589 + * `left` and `right` are per-channel PCM samples (any sample rate;
590 + * resampled to 44100 Hz internally). Mono input: pass the same samples
591 + * for both channels. Output stems are stereo PCM at 44100 Hz.
592 + *
593 + * Holds the engine lock for the whole separation, so concurrent calls
594 + * on one engine serialize.
595 + */
596 + func separate(left: [Float], right: [Float], sampleRate: UInt32) async throws -> [StemResult]
597 +
598 + /**
599 + * Drop the loaded model, freeing CPU and GPU memory. Returns true if a
600 + * model was loaded.
601 + */
602 + func unloadModel() async -> Bool
603 +
604 + /**
605 + * Run the full pipeline once on synthetic audio to pre-compile GPU
606 + * shaders and resolve autotune. Optional but recommended before the
607 + * first `separate` call; takes a few seconds on first run.
608 + */
609 + func warmup() async throws
610 +
611 +}
612 +/**
613 + * Thread-safe HTDemucs source-separation engine.
614 + *
615 + * Typical lifecycle from Swift:
616 + * ```swift
617 + * configureCacheDir(path: appSupportDir) // sandboxed platforms
618 + * try await downloadModel(model: .fourStem, listener: dl)
619 + * let engine = DemucsEngine()
620 + * let secs = try await engine.loadModel(model: .fourStem)
621 + * try await engine.warmup()
622 + * let stems = try await engine.separate(left: l, right: r, sampleRate: 44100)
623 + * ```
624 + */
625 +open class DemucsEngine: DemucsEngineProtocol, @unchecked Sendable {
626 + fileprivate let handle: UInt64
627 +
628 + /// Used to instantiate a [FFIObject] without an actual handle, for fakes in tests, mostly.
629 +#if swift(>=5.8)
630 + @_documentation(visibility: private)
631 +#endif
632 + public struct NoHandle {
633 + public init() {}
634 + }
635 +
636 + // TODO: We'd like this to be `private` but for Swifty reasons,
637 + // we can't implement `FfiConverter` without making this `required` and we can't
638 + // make it `required` without making it `public`.
639 +#if swift(>=5.8)
640 + @_documentation(visibility: private)
641 +#endif
642 + required public init(unsafeFromHandle handle: UInt64) {
643 + self.handle = handle
644 + }
645 +
646 + // This constructor can be used to instantiate a fake object.
647 + // - Parameter noHandle: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject].
648 + //
649 + // - Warning:
650 + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing handle the FFI lower functions will crash.
651 +#if swift(>=5.8)
652 + @_documentation(visibility: private)
653 +#endif
654 + public init(noHandle: NoHandle) {
655 + self.handle = 0
656 + }
657 +
658 +#if swift(>=5.8)
659 + @_documentation(visibility: private)
660 +#endif
661 + public func uniffiCloneHandle() -> UInt64 {
662 + return try! rustCall { uniffi_demucs_fn_clone_demucsengine(self.handle, $0) }
663 + }
664 +public convenience init() {
665 + let handle =
666 + try! rustCall() {
667 + uniffi_demucs_fn_constructor_demucsengine_new($0
668 + )
669 +}
670 + self.init(unsafeFromHandle: handle)
671 +}
672 +
673 + deinit {
674 + if handle == 0 {
675 + // Mock objects have handle=0 don't try to free them
676 + return
677 + }
678 +
679 + try! rustCall { uniffi_demucs_fn_free_demucsengine(handle, $0) }
680 + }
681 +
682 +
683 +
684 +
685 +open func isLoaded()async -> Bool {
686 + return
687 + try! await uniffiRustCallAsync(
688 + rustFutureFunc: {
689 + uniffi_demucs_fn_method_demucsengine_is_loaded(
690 + self.uniffiCloneHandle()
691 +
692 + )
693 + },
694 + pollFunc: ffi_demucs_rust_future_poll_i8,
695 + completeFunc: ffi_demucs_rust_future_complete_i8,
696 + freeFunc: ffi_demucs_rust_future_free_i8,
697 + liftFunc: FfiConverterBool.lift,
698 + errorHandler: nil
699 +
700 + )
701 +}
702 +
703 + /**
704 + * Load a model's weights from the local cache into memory (and onto the
705 + * GPU device). Errors with `NotCached` if `downloadModel` has not been
706 + * run for this model. Returns the wall-clock load time in seconds.
707 + */
708 +open func loadModel(model: DemucsModel)async throws -> Double {
709 + return
710 + try await uniffiRustCallAsync(
711 + rustFutureFunc: {
712 + uniffi_demucs_fn_method_demucsengine_load_model(
713 + self.uniffiCloneHandle(),
714 + FfiConverterTypeDemucsModel_lower(model)
715 + )
716 + },
717 + pollFunc: ffi_demucs_rust_future_poll_f64,
718 + completeFunc: ffi_demucs_rust_future_complete_f64,
719 + freeFunc: ffi_demucs_rust_future_free_f64,
720 + liftFunc: FfiConverterDouble.lift,
721 + errorHandler: FfiConverterTypeDemucsFfiError_lift
722 + )
723 +}
724 +
725 + /**
726 + * The model currently loaded, if any.
727 + */
728 +open func loadedModel()async -> DemucsModel? {
729 + return
730 + try! await uniffiRustCallAsync(
731 + rustFutureFunc: {
732 + uniffi_demucs_fn_method_demucsengine_loaded_model(
733 + self.uniffiCloneHandle()
734 +
735 + )
736 + },
737 + pollFunc: ffi_demucs_rust_future_poll_rust_buffer,
738 + completeFunc: ffi_demucs_rust_future_complete_rust_buffer,
739 + freeFunc: ffi_demucs_rust_future_free_rust_buffer,
740 + liftFunc: FfiConverterOptionTypeDemucsModel.lift,
741 + errorHandler: nil
742 +
743 + )
744 +}
745 +
746 + /**
747 + * Separate a stereo track into stems.
748 + *
749 + * `left` and `right` are per-channel PCM samples (any sample rate;
750 + * resampled to 44100 Hz internally). Mono input: pass the same samples
751 + * for both channels. Output stems are stereo PCM at 44100 Hz.
752 + *
753 + * Holds the engine lock for the whole separation, so concurrent calls
754 + * on one engine serialize.
755 + */
756 +open func separate(left: [Float], right: [Float], sampleRate: UInt32)async throws -> [StemResult] {
757 + return
758 + try await uniffiRustCallAsync(
759 + rustFutureFunc: {
760 + uniffi_demucs_fn_method_demucsengine_separate(
761 + self.uniffiCloneHandle(),
762 + FfiConverterSequenceFloat.lower(left),FfiConverterSequenceFloat.lower(right),FfiConverterUInt32.lower(sampleRate)
763 + )
764 + },
765 + pollFunc: ffi_demucs_rust_future_poll_rust_buffer,
766 + completeFunc: ffi_demucs_rust_future_complete_rust_buffer,
767 + freeFunc: ffi_demucs_rust_future_free_rust_buffer,
768 + liftFunc: FfiConverterSequenceTypeStemResult.lift,
769 + errorHandler: FfiConverterTypeDemucsFfiError_lift
770 + )
771 +}
772 +
773 + /**
774 + * Drop the loaded model, freeing CPU and GPU memory. Returns true if a
775 + * model was loaded.
776 + */
777 +open func unloadModel()async -> Bool {
778 + return
779 + try! await uniffiRustCallAsync(
780 + rustFutureFunc: {
781 + uniffi_demucs_fn_method_demucsengine_unload_model(
782 + self.uniffiCloneHandle()
783 +
784 + )
785 + },
786 + pollFunc: ffi_demucs_rust_future_poll_i8,
787 + completeFunc: ffi_demucs_rust_future_complete_i8,
788 + freeFunc: ffi_demucs_rust_future_free_i8,
789 + liftFunc: FfiConverterBool.lift,
790 + errorHandler: nil
791 +
792 + )
793 +}
794 +
795 + /**
796 + * Run the full pipeline once on synthetic audio to pre-compile GPU
797 + * shaders and resolve autotune. Optional but recommended before the
798 + * first `separate` call; takes a few seconds on first run.
799 + */
800 +open func warmup()async throws {
801 + return
802 + try await uniffiRustCallAsync(
803 + rustFutureFunc: {
804 + uniffi_demucs_fn_method_demucsengine_warmup(
805 + self.uniffiCloneHandle()
806 +
807 + )
808 + },
809 + pollFunc: ffi_demucs_rust_future_poll_void,
810 + completeFunc: ffi_demucs_rust_future_complete_void,
811 + freeFunc: ffi_demucs_rust_future_free_void,
812 + liftFunc: { $0 },
813 + errorHandler: FfiConverterTypeDemucsFfiError_lift
814 + )
815 +}
816 +
817 +
818 +
819 +}
820 +
821 +
822 +#if swift(>=5.8)
823 +@_documentation(visibility: private)
824 +#endif
825 +public struct FfiConverterTypeDemucsEngine: FfiConverter {
826 + typealias FfiType = UInt64
827 + typealias SwiftType = DemucsEngine
828 +
829 + public static func lift(_ handle: UInt64) throws -> DemucsEngine {
830 + return DemucsEngine(unsafeFromHandle: handle)
831 + }
832 +
833 + public static func lower(_ value: DemucsEngine) -> UInt64 {
834 + return value.uniffiCloneHandle()
835 + }
836 +
837 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> DemucsEngine {
838 + let handle: UInt64 = try readInt(&buf)
839 + return try lift(handle)
840 + }
841 +
842 + public static func write(_ value: DemucsEngine, into buf: inout [UInt8]) {
843 + writeInt(&buf, lower(value))
844 + }
845 +}
846 +
847 +
848 +#if swift(>=5.8)
849 +@_documentation(visibility: private)
850 +#endif
851 +public func FfiConverterTypeDemucsEngine_lift(_ handle: UInt64) throws -> DemucsEngine {
852 + return try FfiConverterTypeDemucsEngine.lift(handle)
853 +}
854 +
855 +#if swift(>=5.8)
856 +@_documentation(visibility: private)
857 +#endif
858 +public func FfiConverterTypeDemucsEngine_lower(_ value: DemucsEngine) -> UInt64 {
859 + return FfiConverterTypeDemucsEngine.lower(value)
860 +}
861 +
862 +
863 +
864 +
865 +/**
866 + * Progress payload for weight downloads.
867 + */
868 +public struct DownloadProgress: Equatable, Hashable {
869 + public var downloadedBytes: UInt64
870 + /**
871 + * 0 when the server did not report a Content-Length.
872 + */
873 + public var totalBytes: UInt64
874 + /**
875 + * 0.0–1.0, or 0.0 when the total is unknown.
876 + */
877 + public var fraction: Double
878 + public var done: Bool
879 +
880 + // Default memberwise initializers are never public by default, so we
881 + // declare one manually.
882 + public init(downloadedBytes: UInt64,
883 + /**
884 + * 0 when the server did not report a Content-Length.
885 + */totalBytes: UInt64,
886 + /**
887 + * 0.0–1.0, or 0.0 when the total is unknown.
888 + */fraction: Double, done: Bool) {
889 + self.downloadedBytes = downloadedBytes
890 + self.totalBytes = totalBytes
891 + self.fraction = fraction
892 + self.done = done
893 + }
894 +
895 +
896 +
897 +
898 +}
899 +
900 +#if compiler(>=6)
901 +extension DownloadProgress: Sendable {}
902 +#endif
903 +
904 +#if swift(>=5.8)
905 +@_documentation(visibility: private)
906 +#endif
907 +public struct FfiConverterTypeDownloadProgress: FfiConverterRustBuffer {
908 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> DownloadProgress {
909 + return
910 + try DownloadProgress(
911 + downloadedBytes: FfiConverterUInt64.read(from: &buf),
912 + totalBytes: FfiConverterUInt64.read(from: &buf),
913 + fraction: FfiConverterDouble.read(from: &buf),
914 + done: FfiConverterBool.read(from: &buf)
915 + )
916 + }
917 +
918 + public static func write(_ value: DownloadProgress, into buf: inout [UInt8]) {
919 + FfiConverterUInt64.write(value.downloadedBytes, into: &buf)
920 + FfiConverterUInt64.write(value.totalBytes, into: &buf)
921 + FfiConverterDouble.write(value.fraction, into: &buf)
922 + FfiConverterBool.write(value.done, into: &buf)
923 + }
924 +}
925 +
926 +
927 +#if swift(>=5.8)
928 +@_documentation(visibility: private)
929 +#endif
930 +public func FfiConverterTypeDownloadProgress_lift(_ buf: RustBuffer) throws -> DownloadProgress {
931 + return try FfiConverterTypeDownloadProgress.lift(buf)
932 +}
933 +
934 +#if swift(>=5.8)
935 +@_documentation(visibility: private)
936 +#endif
937 +public func FfiConverterTypeDownloadProgress_lower(_ value: DownloadProgress) -> RustBuffer {
938 + return FfiConverterTypeDownloadProgress.lower(value)
939 +}
940 +
941 +
942 +/**
943 + * Descriptive metadata for a model variant.
944 + */
945 +public struct ModelMetadata: Equatable, Hashable {
946 + public var id: String
947 + public var label: String
948 + public var description: String
949 + /**
950 + * Safetensors weight file name, e.g. "htdemucs.safetensors".
951 + */
952 + public var filename: String
953 + public var sizeMb: UInt32
954 + public var stems: [StemKind]
955 + public var downloadUrl: String
956 +
957 + // Default memberwise initializers are never public by default, so we
958 + // declare one manually.
959 + public init(id: String, label: String, description: String,
960 + /**
961 + * Safetensors weight file name, e.g. "htdemucs.safetensors".
962 + */filename: String, sizeMb: UInt32, stems: [StemKind], downloadUrl: String) {
963 + self.id = id
964 + self.label = label
965 + self.description = description
966 + self.filename = filename
967 + self.sizeMb = sizeMb
968 + self.stems = stems
969 + self.downloadUrl = downloadUrl
970 + }
971 +
972 +
973 +
974 +
975 +}
976 +
977 +#if compiler(>=6)
978 +extension ModelMetadata: Sendable {}
979 +#endif
980 +
981 +#if swift(>=5.8)
982 +@_documentation(visibility: private)
983 +#endif
984 +public struct FfiConverterTypeModelMetadata: FfiConverterRustBuffer {
985 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ModelMetadata {
986 + return
987 + try ModelMetadata(
988 + id: FfiConverterString.read(from: &buf),
989 + label: FfiConverterString.read(from: &buf),
990 + description: FfiConverterString.read(from: &buf),
991 + filename: FfiConverterString.read(from: &buf),
992 + sizeMb: FfiConverterUInt32.read(from: &buf),
993 + stems: FfiConverterSequenceTypeStemKind.read(from: &buf),
994 + downloadUrl: FfiConverterString.read(from: &buf)
995 + )
996 + }
997 +
998 + public static func write(_ value: ModelMetadata, into buf: inout [UInt8]) {
999 + FfiConverterString.write(value.id, into: &buf)
1000 + FfiConverterString.write(value.label, into: &buf)
1001 + FfiConverterString.write(value.description, into: &buf)
1002 + FfiConverterString.write(value.filename, into: &buf)
1003 + FfiConverterUInt32.write(value.sizeMb, into: &buf)
1004 + FfiConverterSequenceTypeStemKind.write(value.stems, into: &buf)
1005 + FfiConverterString.write(value.downloadUrl, into: &buf)
1006 + }
1007 +}
1008 +
1009 +
1010 +#if swift(>=5.8)
1011 +@_documentation(visibility: private)
1012 +#endif
1013 +public func FfiConverterTypeModelMetadata_lift(_ buf: RustBuffer) throws -> ModelMetadata {
1014 + return try FfiConverterTypeModelMetadata.lift(buf)
1015 +}
1016 +
1017 +#if swift(>=5.8)
1018 +@_documentation(visibility: private)
1019 +#endif
1020 +public func FfiConverterTypeModelMetadata_lower(_ value: ModelMetadata) -> RustBuffer {
1021 + return FfiConverterTypeModelMetadata.lower(value)
1022 +}
1023 +
1024 +
1025 +/**
1026 + * Coarse separation progress derived from chunk/stem counters.
1027 + */
1028 +public struct SeparationProgress: Equatable, Hashable {
1029 + /**
1030 + * 0.0–1.0 overall fraction.
1031 + */
1032 + public var fraction: Double
1033 + /**
1034 + * 0-based index of the chunk currently in flight.
1035 + */
1036 + public var currentChunk: UInt64
1037 + public var totalChunks: UInt64
1038 +
1039 + // Default memberwise initializers are never public by default, so we
1040 + // declare one manually.
1041 + public init(
1042 + /**
1043 + * 0.0–1.0 overall fraction.
1044 + */fraction: Double,
1045 + /**
1046 + * 0-based index of the chunk currently in flight.
1047 + */currentChunk: UInt64, totalChunks: UInt64) {
1048 + self.fraction = fraction
1049 + self.currentChunk = currentChunk
1050 + self.totalChunks = totalChunks
1051 + }
1052 +
1053 +
1054 +
1055 +
1056 +}
1057 +
1058 +#if compiler(>=6)
1059 +extension SeparationProgress: Sendable {}
1060 +#endif
1061 +
1062 +#if swift(>=5.8)
1063 +@_documentation(visibility: private)
1064 +#endif
1065 +public struct FfiConverterTypeSeparationProgress: FfiConverterRustBuffer {
1066 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SeparationProgress {
1067 + return
1068 + try SeparationProgress(
1069 + fraction: FfiConverterDouble.read(from: &buf),
1070 + currentChunk: FfiConverterUInt64.read(from: &buf),
1071 + totalChunks: FfiConverterUInt64.read(from: &buf)
1072 + )
1073 + }
1074 +
1075 + public static func write(_ value: SeparationProgress, into buf: inout [UInt8]) {
1076 + FfiConverterDouble.write(value.fraction, into: &buf)
1077 + FfiConverterUInt64.write(value.currentChunk, into: &buf)
1078 + FfiConverterUInt64.write(value.totalChunks, into: &buf)
1079 + }
1080 +}
1081 +
1082 +
1083 +#if swift(>=5.8)
1084 +@_documentation(visibility: private)
1085 +#endif
1086 +public func FfiConverterTypeSeparationProgress_lift(_ buf: RustBuffer) throws -> SeparationProgress {
1087 + return try FfiConverterTypeSeparationProgress.lift(buf)
1088 +}
1089 +
1090 +#if swift(>=5.8)
1091 +@_documentation(visibility: private)
1092 +#endif
1093 +public func FfiConverterTypeSeparationProgress_lower(_ value: SeparationProgress) -> RustBuffer {
1094 + return FfiConverterTypeSeparationProgress.lower(value)
1095 +}
1096 +
1097 +
1098 +/**
1099 + * One separated stem: interleaved-free stereo PCM at 44100 Hz.
1100 + */
1101 +public struct StemResult: Equatable, Hashable {
1102 + public var kind: StemKind
1103 + public var left: [Float]
1104 + public var right: [Float]
1105 +
1106 + // Default memberwise initializers are never public by default, so we
1107 + // declare one manually.
1108 + public init(kind: StemKind, left: [Float], right: [Float]) {
1109 + self.kind = kind
1110 + self.left = left
1111 + self.right = right
1112 + }
1113 +
1114 +
1115 +
1116 +
1117 +}
1118 +
1119 +#if compiler(>=6)
1120 +extension StemResult: Sendable {}
1121 +#endif
1122 +
1123 +#if swift(>=5.8)
1124 +@_documentation(visibility: private)
1125 +#endif
1126 +public struct FfiConverterTypeStemResult: FfiConverterRustBuffer {
1127 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> StemResult {
1128 + return
1129 + try StemResult(
1130 + kind: FfiConverterTypeStemKind.read(from: &buf),
1131 + left: FfiConverterSequenceFloat.read(from: &buf),
1132 + right: FfiConverterSequenceFloat.read(from: &buf)
1133 + )
1134 + }
1135 +
1136 + public static func write(_ value: StemResult, into buf: inout [UInt8]) {
1137 + FfiConverterTypeStemKind.write(value.kind, into: &buf)
1138 + FfiConverterSequenceFloat.write(value.left, into: &buf)
1139 + FfiConverterSequenceFloat.write(value.right, into: &buf)
1140 + }
1141 +}
1142 +
1143 +
1144 +#if swift(>=5.8)
1145 +@_documentation(visibility: private)
1146 +#endif
1147 +public func FfiConverterTypeStemResult_lift(_ buf: RustBuffer) throws -> StemResult {
1148 + return try FfiConverterTypeStemResult.lift(buf)
1149 +}
1150 +
1151 +#if swift(>=5.8)
1152 +@_documentation(visibility: private)
1153 +#endif
1154 +public func FfiConverterTypeStemResult_lower(_ value: StemResult) -> RustBuffer {
1155 + return FfiConverterTypeStemResult.lower(value)
1156 +}
1157 +
1158 +
1159 +/**
1160 + * Errors surfaced across the FFI boundary.
1161 + */
1162 +public enum DemucsFfiError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError {
1163 +
1164 +
1165 +
1166 + case NoModelLoaded
1167 + case AlreadyLoaded(modelId: String
1168 + )
1169 + case Weights(reason: String
1170 + )
1171 + case Dsp(reason: String
1172 + )
1173 + case Tensor(reason: String
1174 + )
1175 + case Internal(reason: String
1176 + )
1177 + case Cancelled
1178 + case NotCached(reason: String
1179 + )
1180 + case Io(reason: String
1181 + )
1182 + case NoCacheDir
1183 + case Download(reason: String
1184 + )
1185 +
1186 +
1187 +
1188 +
1189 +
1190 +
1191 + public var errorDescription: String? {
1192 + String(reflecting: self)
1193 + }
1194 +
1195 +}
1196 +
1197 +#if compiler(>=6)
1198 +extension DemucsFfiError: Sendable {}
1199 +#endif
1200 +
1201 +#if swift(>=5.8)
1202 +@_documentation(visibility: private)
1203 +#endif
1204 +public struct FfiConverterTypeDemucsFfiError: FfiConverterRustBuffer {
1205 + typealias SwiftType = DemucsFfiError
1206 +
1207 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> DemucsFfiError {
1208 + let variant: Int32 = try readInt(&buf)
1209 + switch variant {
1210 +
1211 +
1212 +
1213 +
1214 + case 1: return .NoModelLoaded
1215 + case 2: return .AlreadyLoaded(
1216 + modelId: try FfiConverterString.read(from: &buf)
1217 + )
1218 + case 3: return .Weights(
1219 + reason: try FfiConverterString.read(from: &buf)
1220 + )
1221 + case 4: return .Dsp(
1222 + reason: try FfiConverterString.read(from: &buf)
1223 + )
1224 + case 5: return .Tensor(
1225 + reason: try FfiConverterString.read(from: &buf)
1226 + )
1227 + case 6: return .Internal(
1228 + reason: try FfiConverterString.read(from: &buf)
1229 + )
1230 + case 7: return .Cancelled
1231 + case 8: return .NotCached(
1232 + reason: try FfiConverterString.read(from: &buf)
1233 + )
1234 + case 9: return .Io(
1235 + reason: try FfiConverterString.read(from: &buf)
1236 + )
1237 + case 10: return .NoCacheDir
1238 + case 11: return .Download(
1239 + reason: try FfiConverterString.read(from: &buf)
1240 + )
1241 +
1242 + default: throw UniffiInternalError.unexpectedEnumCase
1243 + }
1244 + }
1245 +
1246 + public static func write(_ value: DemucsFfiError, into buf: inout [UInt8]) {
1247 + switch value {
1248 +
1249 +
1250 +
1251 +
1252 +
1253 + case .NoModelLoaded:
1254 + writeInt(&buf, Int32(1))
1255 +
1256 +
1257 + case let .AlreadyLoaded(modelId):
1258 + writeInt(&buf, Int32(2))
1259 + FfiConverterString.write(modelId, into: &buf)
1260 +
1261 +
1262 + case let .Weights(reason):
1263 + writeInt(&buf, Int32(3))
1264 + FfiConverterString.write(reason, into: &buf)
1265 +
1266 +
1267 + case let .Dsp(reason):
1268 + writeInt(&buf, Int32(4))
1269 + FfiConverterString.write(reason, into: &buf)
1270 +
1271 +
1272 + case let .Tensor(reason):
1273 + writeInt(&buf, Int32(5))
1274 + FfiConverterString.write(reason, into: &buf)
1275 +
1276 +
1277 + case let .Internal(reason):
1278 + writeInt(&buf, Int32(6))
1279 + FfiConverterString.write(reason, into: &buf)
1280 +
1281 +
1282 + case .Cancelled:
1283 + writeInt(&buf, Int32(7))
1284 +
1285 +
1286 + case let .NotCached(reason):
1287 + writeInt(&buf, Int32(8))
1288 + FfiConverterString.write(reason, into: &buf)
1289 +
1290 +
1291 + case let .Io(reason):
1292 + writeInt(&buf, Int32(9))
1293 + FfiConverterString.write(reason, into: &buf)
1294 +
1295 +
1296 + case .NoCacheDir:
1297 + writeInt(&buf, Int32(10))
1298 +
1299 +
1300 + case let .Download(reason):
1301 + writeInt(&buf, Int32(11))
1302 + FfiConverterString.write(reason, into: &buf)
1303 +
1304 + }
1305 + }
1306 +}
1307 +
1308 +
1309 +#if swift(>=5.8)
1310 +@_documentation(visibility: private)
1311 +#endif
1312 +public func FfiConverterTypeDemucsFfiError_lift(_ buf: RustBuffer) throws -> DemucsFfiError {
1313 + return try FfiConverterTypeDemucsFfiError.lift(buf)
1314 +}
1315 +
1316 +#if swift(>=5.8)
1317 +@_documentation(visibility: private)
1318 +#endif
1319 +public func FfiConverterTypeDemucsFfiError_lower(_ value: DemucsFfiError) -> RustBuffer {
1320 + return FfiConverterTypeDemucsFfiError.lower(value)
1321 +}
1322 +
1323 +// Note that we don't yet support `indirect` for enums.
1324 +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
1325 +/**
1326 + * Which HTDemucs variant to load.
1327 + */
1328 +
1329 +public enum DemucsModel: Equatable, Hashable {
1330 +
1331 + /**
1332 + * htdemucs — 4 stems, balanced speed and quality (~84 MB).
1333 + */
1334 + case fourStem
1335 + /**
1336 + * htdemucs_6s — 6 stems, adds guitar and piano (~84 MB).
1337 + */
1338 + case sixStem
1339 + /**
1340 + * htdemucs_ft — fine-tuned, best quality, one sub-model per requested
1341 + * stem so inference time scales with `stems.len()` (~333 MB).
1342 + */
1343 + case fineTuned(stems: [StemKind]
1344 + )
1345 +
1346 +
1347 +
1348 +
1349 +
1350 +}
1351 +
1352 +#if compiler(>=6)
1353 +extension DemucsModel: Sendable {}
1354 +#endif
1355 +
1356 +#if swift(>=5.8)
1357 +@_documentation(visibility: private)
1358 +#endif
1359 +public struct FfiConverterTypeDemucsModel: FfiConverterRustBuffer {
1360 + typealias SwiftType = DemucsModel
1361 +
1362 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> DemucsModel {
1363 + let variant: Int32 = try readInt(&buf)
1364 + switch variant {
1365 +
1366 + case 1: return .fourStem
1367 +
1368 + case 2: return .sixStem
1369 +
1370 + case 3: return .fineTuned(stems: try FfiConverterSequenceTypeStemKind.read(from: &buf)
1371 + )
1372 +
1373 + default: throw UniffiInternalError.unexpectedEnumCase
1374 + }
1375 + }
1376 +
1377 + public static func write(_ value: DemucsModel, into buf: inout [UInt8]) {
1378 + switch value {
1379 +
1380 +
1381 + case .fourStem:
1382 + writeInt(&buf, Int32(1))
1383 +
1384 +
1385 + case .sixStem:
1386 + writeInt(&buf, Int32(2))
1387 +
1388 +
1389 + case let .fineTuned(stems):
1390 + writeInt(&buf, Int32(3))
1391 + FfiConverterSequenceTypeStemKind.write(stems, into: &buf)
1392 +
1393 + }
1394 + }
1395 +}
1396 +
1397 +
1398 +#if swift(>=5.8)
1399 +@_documentation(visibility: private)
1400 +#endif
1401 +public func FfiConverterTypeDemucsModel_lift(_ buf: RustBuffer) throws -> DemucsModel {
1402 + return try FfiConverterTypeDemucsModel.lift(buf)
1403 +}
1404 +
1405 +#if swift(>=5.8)
1406 +@_documentation(visibility: private)
1407 +#endif
1408 +public func FfiConverterTypeDemucsModel_lower(_ value: DemucsModel) -> RustBuffer {
1409 + return FfiConverterTypeDemucsModel.lower(value)
1410 +}
1411 +
1412 +
1413 +// Note that we don't yet support `indirect` for enums.
1414 +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
1415 +/**
1416 + * A single separable audio source.
1417 + */
1418 +
1419 +public enum StemKind: Equatable, Hashable {
1420 +
1421 + case drums
1422 + case bass
1423 + case other
1424 + case vocals
1425 + case guitar
1426 + case piano
1427 +
1428 +
1429 +
1430 +
1431 +
1432 +}
1433 +
1434 +#if compiler(>=6)
1435 +extension StemKind: Sendable {}
1436 +#endif
1437 +
1438 +#if swift(>=5.8)
1439 +@_documentation(visibility: private)
1440 +#endif
1441 +public struct FfiConverterTypeStemKind: FfiConverterRustBuffer {
1442 + typealias SwiftType = StemKind
1443 +
1444 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> StemKind {
1445 + let variant: Int32 = try readInt(&buf)
1446 + switch variant {
1447 +
1448 + case 1: return .drums
1449 +
1450 + case 2: return .bass
1451 +
1452 + case 3: return .other
1453 +
1454 + case 4: return .vocals
1455 +
1456 + case 5: return .guitar
1457 +
1458 + case 6: return .piano
1459 +
1460 + default: throw UniffiInternalError.unexpectedEnumCase
1461 + }
1462 + }
1463 +
1464 + public static func write(_ value: StemKind, into buf: inout [UInt8]) {
1465 + switch value {
1466 +
1467 +
1468 + case .drums:
1469 + writeInt(&buf, Int32(1))
1470 +
1471 +
1472 + case .bass:
1473 + writeInt(&buf, Int32(2))
1474 +
1475 +
1476 + case .other:
1477 + writeInt(&buf, Int32(3))
1478 +
1479 +
1480 + case .vocals:
1481 + writeInt(&buf, Int32(4))
1482 +
1483 +
1484 + case .guitar:
1485 + writeInt(&buf, Int32(5))
1486 +
1487 +
1488 + case .piano:
1489 + writeInt(&buf, Int32(6))
1490 +
1491 + }
1492 + }
1493 +}
1494 +
1495 +
1496 +#if swift(>=5.8)
1497 +@_documentation(visibility: private)
1498 +#endif
1499 +public func FfiConverterTypeStemKind_lift(_ buf: RustBuffer) throws -> StemKind {
1500 + return try FfiConverterTypeStemKind.lift(buf)
1501 +}
1502 +
1503 +#if swift(>=5.8)
1504 +@_documentation(visibility: private)
1505 +#endif
1506 +public func FfiConverterTypeStemKind_lower(_ value: StemKind) -> RustBuffer {
1507 + return FfiConverterTypeStemKind.lower(value)
1508 +}
1509 +
1510 +
1511 +
1512 +
1513 +
1514 +/**
1515 + * Receives download progress. Return true to continue, false to cancel —
1516 + * the partial file is deleted and `download_model` returns `Cancelled`.
1517 + */
1518 +public protocol DownloadProgressListener: AnyObject, Sendable {
1519 +
1520 + func onProgress(progress: DownloadProgress) -> Bool
1521 +
1522 +}
1523 +
1524 +
1525 +// Put the implementation in a struct so we don't pollute the top-level namespace
1526 +fileprivate struct UniffiCallbackInterfaceDownloadProgressListener {
1527 +
1528 + // Create the VTable using a series of closures.
1529 + // Swift automatically converts these into C callback functions.
1530 + //
1531 + // This creates 1-element array, since this seems to be the only way to construct a const
1532 + // pointer that we can pass to the Rust code.
1533 + static let vtable: [UniffiVTableCallbackInterfaceDownloadProgressListener] = [UniffiVTableCallbackInterfaceDownloadProgressListener(
1534 + uniffiFree: { (uniffiHandle: UInt64) -> () in
1535 + do {
1536 + try FfiConverterCallbackInterfaceDownloadProgressListener.handleMap.remove(handle: uniffiHandle)
1537 + } catch {
1538 + print("Uniffi callback interface DownloadProgressListener: handle missing in uniffiFree")
1539 + }
1540 + },
1541 + uniffiClone: { (uniffiHandle: UInt64) -> UInt64 in
1542 + do {
1543 + return try FfiConverterCallbackInterfaceDownloadProgressListener.handleMap.clone(handle: uniffiHandle)
1544 + } catch {
1545 + fatalError("Uniffi callback interface DownloadProgressListener: handle missing in uniffiClone")
1546 + }
1547 + },
1548 + onProgress: { (
1549 + uniffiHandle: UInt64,
1550 + progress: RustBuffer,
1551 + uniffiOutReturn: UnsafeMutablePointer<Int8>,
1552 + uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
1553 + ) in
1554 + let makeCall = {
1555 + () throws -> Bool in
1556 + guard let uniffiObj = try? FfiConverterCallbackInterfaceDownloadProgressListener.handleMap.get(handle: uniffiHandle) else {
1557 + throw UniffiInternalError.unexpectedStaleHandle
1558 + }
1559 + return uniffiObj.onProgress(
1560 + progress: try FfiConverterTypeDownloadProgress_lift(progress)
1561 + )
1562 + }
1563 +
1564 +
1565 + let writeReturn = { uniffiOutReturn.pointee = FfiConverterBool.lower($0) }
1566 + uniffiTraitInterfaceCall(
1567 + callStatus: uniffiCallStatus,
1568 + makeCall: makeCall,
1569 + writeReturn: writeReturn
1570 + )
1571 + }
1572 + )]
1573 +}
1574 +
1575 +private func uniffiCallbackInitDownloadProgressListener() {
1576 + uniffi_demucs_fn_init_callback_vtable_downloadprogresslistener(UniffiCallbackInterfaceDownloadProgressListener.vtable)
1577 +}
1578 +
1579 +// FfiConverter protocol for callback interfaces
1580 +#if swift(>=5.8)
1581 +@_documentation(visibility: private)
1582 +#endif
1583 +fileprivate struct FfiConverterCallbackInterfaceDownloadProgressListener {
1584 + fileprivate static let handleMap = UniffiHandleMap<DownloadProgressListener>()
1585 +}
1586 +
1587 +#if swift(>=5.8)
1588 +@_documentation(visibility: private)
1589 +#endif
1590 +extension FfiConverterCallbackInterfaceDownloadProgressListener : FfiConverter {
1591 + typealias SwiftType = DownloadProgressListener
1592 + typealias FfiType = UInt64
1593 +
1594 +#if swift(>=5.8)
1595 + @_documentation(visibility: private)
1596 +#endif
1597 + public static func lift(_ handle: UInt64) throws -> SwiftType {
1598 + try handleMap.get(handle: handle)
1599 + }
1600 +
1601 +#if swift(>=5.8)
1602 + @_documentation(visibility: private)
1603 +#endif
1604 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
1605 + let handle: UInt64 = try readInt(&buf)
1606 + return try lift(handle)
1607 + }
1608 +
1609 +#if swift(>=5.8)
1610 + @_documentation(visibility: private)
1611 +#endif
1612 + public static func lower(_ v: SwiftType) -> UInt64 {
1613 + return handleMap.insert(obj: v)
1614 + }
1615 +
1616 +#if swift(>=5.8)
1617 + @_documentation(visibility: private)
1618 +#endif
1619 + public static func write(_ v: SwiftType, into buf: inout [UInt8]) {
1620 + writeInt(&buf, lower(v))
1621 + }
1622 +}
1623 +
1624 +
1625 +#if swift(>=5.8)
1626 +@_documentation(visibility: private)
1627 +#endif
1628 +public func FfiConverterCallbackInterfaceDownloadProgressListener_lift(_ handle: UInt64) throws -> DownloadProgressListener {
1629 + return try FfiConverterCallbackInterfaceDownloadProgressListener.lift(handle)
1630 +}
1631 +
1632 +#if swift(>=5.8)
1633 +@_documentation(visibility: private)
1634 +#endif
1635 +public func FfiConverterCallbackInterfaceDownloadProgressListener_lower(_ v: DownloadProgressListener) -> UInt64 {
1636 + return FfiConverterCallbackInterfaceDownloadProgressListener.lower(v)
1637 +}
1638 +
1639 +
1640 +
1641 +
1642 +/**
1643 + * Receives coarse progress during separation.
1644 + *
1645 + * Called from the inference task; keep the callback fast. Return true to
1646 + * continue, false to cancel — the engine then returns `Cancelled`.
1647 + */
1648 +public protocol SeparationProgressListener: AnyObject, Sendable {
1649 +
1650 + func onProgress(progress: SeparationProgress) -> Bool
1651 +
1652 +}
1653 +
1654 +
1655 +// Put the implementation in a struct so we don't pollute the top-level namespace
1656 +fileprivate struct UniffiCallbackInterfaceSeparationProgressListener {
1657 +
1658 + // Create the VTable using a series of closures.
1659 + // Swift automatically converts these into C callback functions.
1660 + //
1661 + // This creates 1-element array, since this seems to be the only way to construct a const
1662 + // pointer that we can pass to the Rust code.
1663 + static let vtable: [UniffiVTableCallbackInterfaceSeparationProgressListener] = [UniffiVTableCallbackInterfaceSeparationProgressListener(
1664 + uniffiFree: { (uniffiHandle: UInt64) -> () in
1665 + do {
1666 + try FfiConverterCallbackInterfaceSeparationProgressListener.handleMap.remove(handle: uniffiHandle)
1667 + } catch {
1668 + print("Uniffi callback interface SeparationProgressListener: handle missing in uniffiFree")
1669 + }
1670 + },
1671 + uniffiClone: { (uniffiHandle: UInt64) -> UInt64 in
1672 + do {
1673 + return try FfiConverterCallbackInterfaceSeparationProgressListener.handleMap.clone(handle: uniffiHandle)
1674 + } catch {
1675 + fatalError("Uniffi callback interface SeparationProgressListener: handle missing in uniffiClone")
1676 + }
1677 + },
1678 + onProgress: { (
1679 + uniffiHandle: UInt64,
1680 + progress: RustBuffer,
1681 + uniffiOutReturn: UnsafeMutablePointer<Int8>,
1682 + uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
1683 + ) in
1684 + let makeCall = {
1685 + () throws -> Bool in
1686 + guard let uniffiObj = try? FfiConverterCallbackInterfaceSeparationProgressListener.handleMap.get(handle: uniffiHandle) else {
1687 + throw UniffiInternalError.unexpectedStaleHandle
1688 + }
1689 + return uniffiObj.onProgress(
1690 + progress: try FfiConverterTypeSeparationProgress_lift(progress)
1691 + )
1692 + }
1693 +
1694 +
1695 + let writeReturn = { uniffiOutReturn.pointee = FfiConverterBool.lower($0) }
1696 + uniffiTraitInterfaceCall(
1697 + callStatus: uniffiCallStatus,
1698 + makeCall: makeCall,
1699 + writeReturn: writeReturn
1700 + )
1701 + }
1702 + )]
1703 +}
1704 +
1705 +private func uniffiCallbackInitSeparationProgressListener() {
1706 + uniffi_demucs_fn_init_callback_vtable_separationprogresslistener(UniffiCallbackInterfaceSeparationProgressListener.vtable)
1707 +}
1708 +
1709 +// FfiConverter protocol for callback interfaces
1710 +#if swift(>=5.8)
1711 +@_documentation(visibility: private)
1712 +#endif
1713 +fileprivate struct FfiConverterCallbackInterfaceSeparationProgressListener {
1714 + fileprivate static let handleMap = UniffiHandleMap<SeparationProgressListener>()
1715 +}
1716 +
1717 +#if swift(>=5.8)
1718 +@_documentation(visibility: private)
1719 +#endif
1720 +extension FfiConverterCallbackInterfaceSeparationProgressListener : FfiConverter {
1721 + typealias SwiftType = SeparationProgressListener
1722 + typealias FfiType = UInt64
1723 +
1724 +#if swift(>=5.8)
1725 + @_documentation(visibility: private)
1726 +#endif
1727 + public static func lift(_ handle: UInt64) throws -> SwiftType {
1728 + try handleMap.get(handle: handle)
1729 + }
1730 +
1731 +#if swift(>=5.8)
1732 + @_documentation(visibility: private)
1733 +#endif
1734 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
1735 + let handle: UInt64 = try readInt(&buf)
1736 + return try lift(handle)
1737 + }
1738 +
1739 +#if swift(>=5.8)
1740 + @_documentation(visibility: private)
1741 +#endif
1742 + public static func lower(_ v: SwiftType) -> UInt64 {
1743 + return handleMap.insert(obj: v)
1744 + }
1745 +
1746 +#if swift(>=5.8)
1747 + @_documentation(visibility: private)
1748 +#endif
1749 + public static func write(_ v: SwiftType, into buf: inout [UInt8]) {
1750 + writeInt(&buf, lower(v))
1751 + }
1752 +}
1753 +
1754 +
1755 +#if swift(>=5.8)
1756 +@_documentation(visibility: private)
1757 +#endif
1758 +public func FfiConverterCallbackInterfaceSeparationProgressListener_lift(_ handle: UInt64) throws -> SeparationProgressListener {
1759 + return try FfiConverterCallbackInterfaceSeparationProgressListener.lift(handle)
1760 +}
1761 +
1762 +#if swift(>=5.8)
1763 +@_documentation(visibility: private)
1764 +#endif
1765 +public func FfiConverterCallbackInterfaceSeparationProgressListener_lower(_ v: SeparationProgressListener) -> UInt64 {
1766 + return FfiConverterCallbackInterfaceSeparationProgressListener.lower(v)
1767 +}
1768 +
1769 +#if swift(>=5.8)
1770 +@_documentation(visibility: private)
1771 +#endif
1772 +fileprivate struct FfiConverterOptionString: FfiConverterRustBuffer {
1773 + typealias SwiftType = String?
1774 +
1775 + public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
1776 + guard let value = value else {
1777 + writeInt(&buf, Int8(0))
1778 + return
1779 + }
1780 + writeInt(&buf, Int8(1))
1781 + FfiConverterString.write(value, into: &buf)
1782 + }
1783 +
1784 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
1785 + switch try readInt(&buf) as Int8 {
1786 + case 0: return nil
1787 + case 1: return try FfiConverterString.read(from: &buf)
1788 + default: throw UniffiInternalError.unexpectedOptionalTag
1789 + }
1790 + }
1791 +}
1792 +
1793 +#if swift(>=5.8)
1794 +@_documentation(visibility: private)
1795 +#endif
1796 +fileprivate struct FfiConverterOptionTypeDemucsModel: FfiConverterRustBuffer {
1797 + typealias SwiftType = DemucsModel?
1798 +
1799 + public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
1800 + guard let value = value else {
1801 + writeInt(&buf, Int8(0))
1802 + return
1803 + }
1804 + writeInt(&buf, Int8(1))
1805 + FfiConverterTypeDemucsModel.write(value, into: &buf)
1806 + }
1807 +
1808 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
1809 + switch try readInt(&buf) as Int8 {
1810 + case 0: return nil
1811 + case 1: return try FfiConverterTypeDemucsModel.read(from: &buf)
1812 + default: throw UniffiInternalError.unexpectedOptionalTag
1813 + }
1814 + }
1815 +}
1816 +
1817 +#if swift(>=5.8)
1818 +@_documentation(visibility: private)
1819 +#endif
1820 +fileprivate struct FfiConverterSequenceFloat: FfiConverterRustBuffer {
1821 + typealias SwiftType = [Float]
1822 +
1823 + public static func write(_ value: [Float], into buf: inout [UInt8]) {
1824 + let len = Int32(value.count)
1825 + writeInt(&buf, len)
1826 + for item in value {
1827 + FfiConverterFloat.write(item, into: &buf)
1828 + }
1829 + }
1830 +
1831 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [Float] {
1832 + let len: Int32 = try readInt(&buf)
1833 + var seq = [Float]()
1834 + seq.reserveCapacity(Int(len))
1835 + for _ in 0 ..< len {
1836 + seq.append(try FfiConverterFloat.read(from: &buf))
1837 + }
1838 + return seq
1839 + }
1840 +}
1841 +
1842 +#if swift(>=5.8)
1843 +@_documentation(visibility: private)
1844 +#endif
1845 +fileprivate struct FfiConverterSequenceTypeModelMetadata: FfiConverterRustBuffer {
1846 + typealias SwiftType = [ModelMetadata]
1847 +
1848 + public static func write(_ value: [ModelMetadata], into buf: inout [UInt8]) {
1849 + let len = Int32(value.count)
1850 + writeInt(&buf, len)
1851 + for item in value {
1852 + FfiConverterTypeModelMetadata.write(item, into: &buf)
1853 + }
1854 + }
1855 +
1856 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [ModelMetadata] {
1857 + let len: Int32 = try readInt(&buf)
1858 + var seq = [ModelMetadata]()
1859 + seq.reserveCapacity(Int(len))
1860 + for _ in 0 ..< len {
1861 + seq.append(try FfiConverterTypeModelMetadata.read(from: &buf))
1862 + }
1863 + return seq
1864 + }
1865 +}
1866 +
1867 +#if swift(>=5.8)
1868 +@_documentation(visibility: private)
1869 +#endif
1870 +fileprivate struct FfiConverterSequenceTypeStemResult: FfiConverterRustBuffer {
1871 + typealias SwiftType = [StemResult]
1872 +
1873 + public static func write(_ value: [StemResult], into buf: inout [UInt8]) {
1874 + let len = Int32(value.count)
1875 + writeInt(&buf, len)
1876 + for item in value {
1877 + FfiConverterTypeStemResult.write(item, into: &buf)
1878 + }
1879 + }
1880 +
1881 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [StemResult] {
1882 + let len: Int32 = try readInt(&buf)
1883 + var seq = [StemResult]()
1884 + seq.reserveCapacity(Int(len))
1885 + for _ in 0 ..< len {
1886 + seq.append(try FfiConverterTypeStemResult.read(from: &buf))
1887 + }
1888 + return seq
1889 + }
1890 +}
1891 +
1892 +#if swift(>=5.8)
1893 +@_documentation(visibility: private)
1894 +#endif
1895 +fileprivate struct FfiConverterSequenceTypeStemKind: FfiConverterRustBuffer {
1896 + typealias SwiftType = [StemKind]
1897 +
1898 + public static func write(_ value: [StemKind], into buf: inout [UInt8]) {
1899 + let len = Int32(value.count)
1900 + writeInt(&buf, len)
1901 + for item in value {
1902 + FfiConverterTypeStemKind.write(item, into: &buf)
1903 + }
1904 + }
1905 +
1906 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [StemKind] {
1907 + let len: Int32 = try readInt(&buf)
1908 + var seq = [StemKind]()
1909 + seq.reserveCapacity(Int(len))
1910 + for _ in 0 ..< len {
1911 + seq.append(try FfiConverterTypeStemKind.read(from: &buf))
1912 + }
1913 + return seq
1914 + }
1915 +}
1916 +private let UNIFFI_RUST_FUTURE_POLL_READY: Int8 = 0
1917 +private let UNIFFI_RUST_FUTURE_POLL_WAKE: Int8 = 1
1918 +
1919 +fileprivate let uniffiContinuationHandleMap = UniffiHandleMap<UnsafeContinuation<Int8, Never>>()
1920 +
1921 +fileprivate func uniffiRustCallAsync<F, T>(
1922 + rustFutureFunc: () -> UInt64,
1923 + pollFunc: (UInt64, @escaping UniffiRustFutureContinuationCallback, UInt64) -> (),
1924 + completeFunc: (UInt64, UnsafeMutablePointer<RustCallStatus>) -> F,
1925 + freeFunc: (UInt64) -> (),
1926 + liftFunc: (F) throws -> T,
1927 + errorHandler: ((RustBuffer) throws -> Swift.Error)?
1928 +) async throws -> T {
1929 + // Make sure to call the ensure init function since future creation doesn't have a
1930 + // RustCallStatus param, so doesn't use makeRustCall()
1931 + uniffiEnsureDemucsInitialized()
1932 + let rustFuture = rustFutureFunc()
1933 + defer {
1934 + freeFunc(rustFuture)
1935 + }
1936 + var pollResult: Int8;
1937 + repeat {
1938 + pollResult = await withUnsafeContinuation {
1939 + pollFunc(
1940 + rustFuture,
1941 + { handle, pollResult in
1942 + uniffiFutureContinuationCallback(handle: handle, pollResult: pollResult)
1943 + },
1944 + uniffiContinuationHandleMap.insert(obj: $0)
1945 + )
1946 + }
1947 + } while pollResult != UNIFFI_RUST_FUTURE_POLL_READY
1948 +
1949 + return try liftFunc(makeRustCall(
1950 + { completeFunc(rustFuture, $0) },
1951 + errorHandler: errorHandler
1952 + ))
1953 +}
1954 +
1955 +// Callback handlers for an async calls. These are invoked by Rust when the future is ready. They
1956 +// lift the return value or error and resume the suspended function.
1957 +fileprivate func uniffiFutureContinuationCallback(handle: UInt64, pollResult: Int8) {
1958 + if let continuation = try? uniffiContinuationHandleMap.remove(handle: handle) {
1959 + continuation.resume(returning: pollResult)
1960 + } else {
1961 + print("uniffiFutureContinuationCallback invalid handle")
1962 + }
1963 +}
1964 +/**
1965 + * Metadata for every supported model variant.
1966 + */
1967 +public func allModels() -> [ModelMetadata] {
1968 + return try! FfiConverterSequenceTypeModelMetadata.lift(try! rustCall() {
1969 + uniffi_demucs_fn_func_all_models($0
1970 + )
1971 +})
1972 +}
1973 +/**
1974 + * Filesystem path the model's weights live at once downloaded, or None if
1975 + * not cached yet.
1976 + */
1977 +public func cachedModelPath(model: DemucsModel) -> String? {
1978 + return try! FfiConverterOptionString.lift(try! rustCall() {
1979 + uniffi_demucs_fn_func_cached_model_path(
1980 + FfiConverterTypeDemucsModel_lower(model),$0
1981 + )
1982 +})
1983 +}
1984 +/**
1985 + * Override the model cache directory.
1986 + *
1987 + * On iOS/tvOS/visionOS call this once at app launch — before
1988 + * `downloadModel` or `DemucsEngine.loadModel` — with a directory inside the
1989 + * app sandbox, e.g. the app's Application Support or Caches directory.
1990 + * The directory is created if missing.
1991 + */
1992 +public func configureCacheDir(path: String) {try! rustCall() {
1993 + uniffi_demucs_fn_func_configure_cache_dir(
1994 + FfiConverterString.lower(path),$0
1995 + )
1996 +}
1997 +}
1998 +/**
1999 + * Delete a model's weights from the local cache. Returns true if a file was
2000 + * removed.
2001 + */
2002 +public func deleteCachedModel(model: DemucsModel) -> Bool {
2003 + return try! FfiConverterBool.lift(try! rustCall() {
2004 + uniffi_demucs_fn_func_delete_cached_model(
2005 + FfiConverterTypeDemucsModel_lower(model),$0
2006 + )
2007 +})
2008 +}
2009 +/**
2010 + * Whether the model's weights are already in the local cache.
2011 + */
2012 +public func isModelCached(model: DemucsModel) -> Bool {
2013 + return try! FfiConverterBool.lift(try! rustCall() {
2014 + uniffi_demucs_fn_func_is_model_cached(
2015 + FfiConverterTypeDemucsModel_lower(model),$0
2016 + )
2017 +})
2018 +}
2019 +/**
2020 + * Metadata (name, size, stems, download URL) for a model variant.
2021 + */
2022 +public func modelMetadata(model: DemucsModel) -> ModelMetadata {
2023 + return try! FfiConverterTypeModelMetadata_lift(try! rustCall() {
2024 + uniffi_demucs_fn_func_model_metadata(
2025 + FfiConverterTypeDemucsModel_lower(model),$0
2026 + )
2027 +})
2028 +}
2029 +/**
2030 + * Number of inference chunks a track of `n_samples` (per channel, at
2031 + * 44100 Hz) is split into. Useful for sizing progress UIs.
2032 + */
2033 +public func numChunks(nSamples: UInt64) -> UInt64 {
2034 + return try! FfiConverterUInt64.lift(try! rustCall() {
2035 + uniffi_demucs_fn_func_num_chunks(
2036 + FfiConverterUInt64.lower(nSamples),$0
2037 + )
2038 +})
2039 +}
2040 +/**
2041 + * Download a model's weights into the local cache.
2042 + *
2043 + * No-op (immediately reports `done`) if the model is already cached. Call
2044 + * `configureCacheDir` first on sandboxed platforms.
2045 + */
2046 +public func downloadModel(model: DemucsModel, listener: DownloadProgressListener)async throws {
2047 + return
2048 + try await uniffiRustCallAsync(
2049 + rustFutureFunc: {
2050 + uniffi_demucs_fn_func_download_model(FfiConverterTypeDemucsModel_lower(model),FfiConverterCallbackInterfaceDownloadProgressListener_lower(listener)
2051 + )
2052 + },
2053 + pollFunc: ffi_demucs_rust_future_poll_void,
2054 + completeFunc: ffi_demucs_rust_future_complete_void,
2055 + freeFunc: ffi_demucs_rust_future_free_void,
2056 + liftFunc: { $0 },
2057 + errorHandler: FfiConverterTypeDemucsFfiError_lift
2058 + )
2059 +}
2060 +/**
2061 + * `DemucsEngine.separate` with progress reporting and cancellation.
2062 + *
2063 + * A free function because UniFFI 0.31 only supports callback interfaces as
2064 + * free-function parameters.
2065 + */
2066 +public func separateWithProgress(engine: DemucsEngine, left: [Float], right: [Float], sampleRate: UInt32, listener: SeparationProgressListener)async throws -> [StemResult] {
2067 + return
2068 + try await uniffiRustCallAsync(
2069 + rustFutureFunc: {
2070 + uniffi_demucs_fn_func_separate_with_progress(FfiConverterTypeDemucsEngine_lower(engine),FfiConverterSequenceFloat.lower(left),FfiConverterSequenceFloat.lower(right),FfiConverterUInt32.lower(sampleRate),FfiConverterCallbackInterfaceSeparationProgressListener_lower(listener)
2071 + )
2072 + },
2073 + pollFunc: ffi_demucs_rust_future_poll_rust_buffer,
2074 + completeFunc: ffi_demucs_rust_future_complete_rust_buffer,
2075 + freeFunc: ffi_demucs_rust_future_free_rust_buffer,
2076 + liftFunc: FfiConverterSequenceTypeStemResult.lift,
2077 + errorHandler: FfiConverterTypeDemucsFfiError_lift
2078 + )
2079 +}
2080 +
2081 +private enum InitializationResult {
2082 + case ok
2083 + case contractVersionMismatch
2084 + case apiChecksumMismatch
2085 +}
2086 +// Use a global variable to perform the versioning checks. Swift ensures that
2087 +// the code inside is only computed once.
2088 +private let initializationResult: InitializationResult = {
2089 + // Get the bindings contract version from our ComponentInterface
2090 + let bindings_contract_version = 30
2091 + // Get the scaffolding contract version by calling the into the dylib
2092 + let scaffolding_contract_version = ffi_demucs_uniffi_contract_version()
2093 + if bindings_contract_version != scaffolding_contract_version {
2094 + return InitializationResult.contractVersionMismatch
2095 + }
2096 + if (uniffi_demucs_checksum_func_all_models() != 40632) {
2097 + return InitializationResult.apiChecksumMismatch
2098 + }
2099 + if (uniffi_demucs_checksum_func_cached_model_path() != 59385) {
2100 + return InitializationResult.apiChecksumMismatch
2101 + }
2102 + if (uniffi_demucs_checksum_func_configure_cache_dir() != 33315) {
2103 + return InitializationResult.apiChecksumMismatch
2104 + }
2105 + if (uniffi_demucs_checksum_func_delete_cached_model() != 23501) {
2106 + return InitializationResult.apiChecksumMismatch
2107 + }
2108 + if (uniffi_demucs_checksum_func_is_model_cached() != 9391) {
2109 + return InitializationResult.apiChecksumMismatch
2110 + }
2111 + if (uniffi_demucs_checksum_func_model_metadata() != 64919) {
2112 + return InitializationResult.apiChecksumMismatch
2113 + }
2114 + if (uniffi_demucs_checksum_func_num_chunks() != 27500) {
2115 + return InitializationResult.apiChecksumMismatch
2116 + }
2117 + if (uniffi_demucs_checksum_func_download_model() != 37675) {
2118 + return InitializationResult.apiChecksumMismatch
2119 + }
2120 + if (uniffi_demucs_checksum_func_separate_with_progress() != 6510) {
2121 + return InitializationResult.apiChecksumMismatch
2122 + }
2123 + if (uniffi_demucs_checksum_method_demucsengine_is_loaded() != 28086) {
2124 + return InitializationResult.apiChecksumMismatch
2125 + }
2126 + if (uniffi_demucs_checksum_method_demucsengine_load_model() != 54613) {
2127 + return InitializationResult.apiChecksumMismatch
2128 + }
2129 + if (uniffi_demucs_checksum_method_demucsengine_loaded_model() != 45821) {
2130 + return InitializationResult.apiChecksumMismatch
2131 + }
2132 + if (uniffi_demucs_checksum_method_demucsengine_separate() != 52086) {
2133 + return InitializationResult.apiChecksumMismatch
2134 + }
2135 + if (uniffi_demucs_checksum_method_demucsengine_unload_model() != 24792) {
2136 + return InitializationResult.apiChecksumMismatch
2137 + }
2138 + if (uniffi_demucs_checksum_method_demucsengine_warmup() != 20811) {
2139 + return InitializationResult.apiChecksumMismatch
2140 + }
2141 + if (uniffi_demucs_checksum_constructor_demucsengine_new() != 51674) {
2142 + return InitializationResult.apiChecksumMismatch
2143 + }
2144 + if (uniffi_demucs_checksum_method_downloadprogresslistener_on_progress() != 44819) {
2145 + return InitializationResult.apiChecksumMismatch
2146 + }
2147 + if (uniffi_demucs_checksum_method_separationprogresslistener_on_progress() != 56005) {
2148 + return InitializationResult.apiChecksumMismatch
2149 + }
2150 +
2151 + uniffiCallbackInitDownloadProgressListener()
2152 + uniffiCallbackInitSeparationProgressListener()
2153 + return InitializationResult.ok
2154 +}()
2155 +
2156 +// Make the ensure init function public so that other modules which have external type references to
2157 +// our types can call it.
2158 +public func uniffiEnsureDemucsInitialized() {
2159 + switch initializationResult {
2160 + case .ok:
2161 + break
2162 + case .contractVersionMismatch:
2163 + fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project")
2164 + case .apiChecksumMismatch:
2165 + fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
2166 + }
2167 +}
2168 +
2169 +// swiftlint:enable all
\ No newline at end of file