@@ -1122,7 +1122,8 @@ func sherpaOnnxOfflineTtsModelConfig(
11221122 kitten: SherpaOnnxOfflineTtsKittenModelConfig = sherpaOnnxOfflineTtsKittenModelConfig ( ) ,
11231123 zipvoice: SherpaOnnxOfflineTtsZipvoiceModelConfig = sherpaOnnxOfflineTtsZipvoiceModelConfig ( ) ,
11241124 pocket: SherpaOnnxOfflineTtsPocketModelConfig = sherpaOnnxOfflineTtsPocketModelConfig ( ) ,
1125- supertonic: SherpaOnnxOfflineTtsSupertonicModelConfig = sherpaOnnxOfflineTtsSupertonicModelConfig ( )
1125+ supertonic: SherpaOnnxOfflineTtsSupertonicModelConfig =
1126+ sherpaOnnxOfflineTtsSupertonicModelConfig ( )
11261127) -> SherpaOnnxOfflineTtsModelConfig {
11271128 return SherpaOnnxOfflineTtsModelConfig (
11281129 vits: vits,
@@ -1353,7 +1354,8 @@ class SherpaOnnxOfflineTtsWrapper {
13531354 let p = Unmanaged < SherpaOnnxCallbackPair > . fromOpaque ( rawArg!) . takeUnretainedValue ( )
13541355 return p. cb!( samples, n, p. arg)
13551356 }
1356- let result = generateWithConfig ( text: text, config: config, callback: wrapper, arg: unmanaged. toOpaque ( ) )
1357+ let result = generateWithConfig (
1358+ text: text, config: config, callback: wrapper, arg: unmanaged. toOpaque ( ) )
13571359 unmanaged. release ( )
13581360 return result
13591361 }
@@ -2037,3 +2039,163 @@ func getSherpaOnnxGitSha1() -> String {
20372039func getSherpaOnnxGitDate( ) -> String {
20382040 return String ( cString: SherpaOnnxGetGitDate ( ) )
20392041}
2042+ //---------------------------
2043+ // Source separation
2044+ //---------------------------
2045+
2046+ // MARK: - Audio Buffer
2047+ struct AudioBuffer {
2048+ private enum Storage {
2049+ case owned( [ Float ] )
2050+ case wrapped( ManagedWave )
2051+ }
2052+
2053+ private class ManagedWave {
2054+ let pointer : UnsafePointer < SherpaOnnxMultiChannelWave >
2055+ init ( _ p: UnsafePointer < SherpaOnnxMultiChannelWave > ) { self . pointer = p }
2056+ deinit { SherpaOnnxFreeMultiChannelWave ( pointer) }
2057+ }
2058+
2059+ private let storage : Storage
2060+ let channelCount : Int
2061+ let samplesPerChannel : Int
2062+ let sampleRate : Int
2063+
2064+ init ( samples: [ Float ] , channelCount: Int , sampleRate: Int ) {
2065+ self . storage = . owned( samples)
2066+ self . channelCount = channelCount
2067+ self . sampleRate = sampleRate
2068+ self . samplesPerChannel = channelCount > 0 ? samples. count / channelCount : 0
2069+ }
2070+
2071+ init ? ( filename: String ) {
2072+ guard let ptr = SherpaOnnxReadWaveMultiChannel ( filename) else { return nil }
2073+ self . storage = . wrapped( ManagedWave ( ptr) )
2074+ self . channelCount = Int ( ptr. pointee. num_channels)
2075+ self . samplesPerChannel = Int ( ptr. pointee. num_samples)
2076+ self . sampleRate = Int ( ptr. pointee. sample_rate)
2077+ }
2078+
2079+ func withUnsafeBufferPointer< R> ( _ body: ( UnsafeBufferPointer < Float > ) -> R ) -> R {
2080+ switch storage {
2081+ case . owned( let array) :
2082+ return array. withUnsafeBufferPointer ( body)
2083+ case . wrapped( let managed) :
2084+ let total = Int ( managed. pointer. pointee. num_channels * managed. pointer. pointee. num_samples)
2085+ // Ensure we start from the first channel's pointer
2086+ return body ( UnsafeBufferPointer ( start: managed. pointer. pointee. samples [ 0 ] , count: total) )
2087+ }
2088+ }
2089+
2090+ @discardableResult
2091+ func save( to filename: String ) -> Bool {
2092+ return withUnsafeBufferPointer { buf in
2093+ guard let base = buf. baseAddress else { return false }
2094+ // FIX: Explicitly type the array as Optional pointers to match C 'float* const*'
2095+ var ptrs : [ UnsafePointer < Float > ? ] = ( 0 ..< channelCount) . map { base + ( $0 * samplesPerChannel) }
2096+
2097+ return SherpaOnnxWriteWaveMultiChannel (
2098+ & ptrs,
2099+ Int32 ( samplesPerChannel) ,
2100+ Int32 ( sampleRate) ,
2101+ Int32 ( channelCount) ,
2102+ filename
2103+ ) == 1
2104+ }
2105+ }
2106+ }
2107+
2108+ // MARK: - Configuration Struct
2109+ struct SourceSeparationConfig {
2110+ struct Spleeter {
2111+ var vocals : String
2112+ var accompaniment : String
2113+ }
2114+ struct Uvr { var model : String }
2115+
2116+ var spleeter : Spleeter ?
2117+ var uvr : Uvr ?
2118+ var numThreads : Int = 1
2119+ var debug : Bool = false
2120+ var provider : String = " cpu "
2121+
2122+ func withCConfig< R> ( _ body: ( UnsafePointer < SherpaOnnxOfflineSourceSeparationConfig > ) -> R ) -> R {
2123+ var cConfig = SherpaOnnxOfflineSourceSeparationConfig ( )
2124+ cConfig. model. num_threads = Int32 ( self . numThreads)
2125+ cConfig. model. debug = self . debug ? 1 : 0
2126+
2127+ var s : [ String : [ Int8 ] ] = [ : ]
2128+ func b( _ k: String , _ v: String ? ) -> UnsafePointer < Int8 > ? {
2129+ guard let v = v else { return nil }
2130+ s [ k] = Array ( v. utf8CString)
2131+ return s [ k] !. withUnsafeBufferPointer { $0. baseAddress }
2132+ }
2133+
2134+ cConfig. model. provider = b ( " provider " , self . provider)
2135+ cConfig. model. spleeter. vocals = b ( " spleeter.vocals " , self . spleeter? . vocals)
2136+ cConfig. model. spleeter. accompaniment = b ( " spleeter.accompaniment " , self . spleeter? . accompaniment)
2137+ cConfig. model. uvr. model = b ( " uvr.model " , self . uvr? . model)
2138+
2139+ return body ( & cConfig)
2140+ }
2141+ }
2142+
2143+ class SourceSeparator {
2144+ private var engine : OpaquePointer ?
2145+
2146+ init ? ( config: SourceSeparationConfig ) {
2147+ self . engine = config. withCConfig { SherpaOnnxCreateOfflineSourceSeparation ( $0) }
2148+
2149+ if self . engine == nil { return nil }
2150+ }
2151+
2152+ deinit {
2153+ if let e = engine {
2154+ SherpaOnnxDestroyOfflineSourceSeparation ( e)
2155+ }
2156+ }
2157+
2158+ func process( buffer: AudioBuffer ) -> [ AudioBuffer ] ? {
2159+ guard let engine = engine else { return nil }
2160+
2161+ return buffer. withUnsafeBufferPointer { flatBuf in
2162+ guard let base = flatBuf. baseAddress else { return nil }
2163+ var ptrs : [ UnsafePointer < Float > ? ] = ( 0 ..< buffer. channelCount) . map {
2164+ base + ( $0 * buffer. samplesPerChannel)
2165+ }
2166+
2167+ guard
2168+ let raw = SherpaOnnxOfflineSourceSeparationProcess (
2169+ engine,
2170+ & ptrs,
2171+ Int32 ( buffer. channelCount) ,
2172+ Int32 ( buffer. samplesPerChannel) ,
2173+ Int32 ( buffer. sampleRate)
2174+ )
2175+ else { return nil }
2176+
2177+ let stemCount = Int ( raw. pointee. num_stems)
2178+ let result = ( 0 ..< stemCount) . map { i in
2179+ let stem = raw. pointee. stems [ i]
2180+ let chs = Int ( stem. num_channels)
2181+ let n = Int ( stem. n)
2182+ var flat = [ Float] ( repeating: 0 , count: chs * n)
2183+
2184+ for c in 0 ..< chs {
2185+ if let src = stem. samples [ c] {
2186+ let offset = c * n
2187+ flat. withUnsafeMutableBufferPointer { dest in
2188+ let destPtr = dest. baseAddress!. advanced ( by: offset)
2189+ destPtr. initialize ( from: src, count: n)
2190+ }
2191+ }
2192+ }
2193+ return AudioBuffer (
2194+ samples: flat, channelCount: chs, sampleRate: Int ( raw. pointee. sample_rate) )
2195+ }
2196+
2197+ SherpaOnnxDestroySourceSeparationOutput ( raw)
2198+ return result
2199+ }
2200+ }
2201+ }
0 commit comments