11//
2- // Copyright 2024 Picovoice Inc.
2+ // Copyright 2024-2025 Picovoice Inc.
33// You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE"
44// file accompanying this source.
55// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
@@ -135,8 +135,8 @@ public class Orca {
135135 & cNumSamples,
136136 & cPcm)
137137 if status != PV_STATUS_SUCCESS {
138- let messageStack = try orca . getMessageStack ( )
139- throw orca . pvStatusToOrcaError ( status, " Unable to synthesize streaming speech " , messageStack)
138+ let messageStack = try Orca . getMessageStack ( )
139+ throw Orca . pvStatusToOrcaError ( status, " Unable to synthesize streaming speech " , messageStack)
140140 }
141141
142142 let buffer = UnsafeBufferPointer ( start: cPcm, count: Int ( cNumSamples) )
@@ -166,8 +166,8 @@ public class Orca {
166166 & cNumSamples,
167167 & cPcm)
168168 if status != PV_STATUS_SUCCESS {
169- let messageStack = try orca . getMessageStack ( )
170- throw orca . pvStatusToOrcaError ( status, " Unable to flush streaming speech " , messageStack)
169+ let messageStack = try Orca . getMessageStack ( )
170+ throw Orca . pvStatusToOrcaError ( status, " Unable to flush streaming speech " , messageStack)
171171 }
172172
173173 let buffer = UnsafeBufferPointer ( start: cPcm, count: Int ( cNumSamples) )
@@ -195,6 +195,30 @@ public class Orca {
195195 public static func setSdk( sdk: String ) {
196196 self . sdk = sdk
197197 }
198+
199+ /// Lists all available devices that Orca can use for inference.
200+ /// Entries in the list can be used as the `device` argument when initializing Orca.
201+ ///
202+ /// - Throws: OrcaError
203+ /// - Returns: Array of available devices that Orca can be used for inference.
204+ public static func getAvailableDevices( ) throws -> [ String ] {
205+ var cHardwareDevices : UnsafeMutablePointer < UnsafeMutablePointer < Int8 > ? > ?
206+ var numHardwareDevices : Int32 = 0
207+ let status = pv_orca_list_hardware_devices ( & cHardwareDevices, & numHardwareDevices)
208+ if status != PV_STATUS_SUCCESS {
209+ let messageStack = try Orca . getMessageStack ( )
210+ throw Orca . pvStatusToOrcaError ( status, " Orca getAvailableDevices failed " , messageStack)
211+ }
212+
213+ var hardwareDevices : [ String ] = [ ]
214+ for i in 0 ..< numHardwareDevices {
215+ hardwareDevices. append ( String ( cString: cHardwareDevices!. advanced ( by: Int ( i) ) . pointee!) )
216+ }
217+
218+ pv_orca_free_hardware_devices ( cHardwareDevices, numHardwareDevices)
219+
220+ return hardwareDevices
221+ }
198222
199223 /// Set of characters supported by Orca.
200224 public var validCharacters : Set < String > ? {
@@ -216,30 +240,42 @@ public class Orca {
216240 /// - Parameters:
217241 /// - accessKey: AccessKey obtained from the Picovoice Console (https://console.picovoice.ai/)
218242 /// - modelPath: Absolute path to file containing model parameters.
243+ /// - device: String representation of the device (e.g., CPU or GPU) to use. If set to `best`, the most
244+ /// suitable device is selected automatically. If set to `gpu`, the engine uses the first available GPU
245+ /// device. To select a specific GPU device, set this argument to `gpu:${GPU_INDEX}`, where `${GPU_INDEX}`
246+ /// is the index of the target GPU. If set to `cpu`, the engine will run on the CPU with the default
247+ /// number of threads. To specify the number of threads, set this argument to `cpu:${NUM_THREADS}`,
248+ /// where `${NUM_THREADS}` is the desired number of threads.
219249 /// - Throws: OrcaError
220250 public init (
221251 accessKey: String ,
222- modelPath: String ) throws {
252+ modelPath: String ,
253+ device: String ? = nil ) throws {
223254
224255 var modelPathArg = modelPath
225256 if !FileManager( ) . fileExists ( atPath: modelPathArg) {
226257 modelPathArg = try getResourcePath ( modelPathArg)
227258 }
228259
260+ var deviceArg = device
261+ if device == nil {
262+ deviceArg = " best "
263+ }
264+
229265 pv_set_sdk ( Orca . sdk)
230266
231267 let initStatus = pv_orca_init ( accessKey, modelPathArg, & handle)
232268 if initStatus != PV_STATUS_SUCCESS {
233- let messageStack = try getMessageStack ( )
234- throw pvStatusToOrcaError ( initStatus, " Orca init failed " , messageStack)
269+ let messageStack = try Orca . getMessageStack ( )
270+ throw Orca . pvStatusToOrcaError ( initStatus, " Orca init failed " , messageStack)
235271 }
236272
237273 var cNumCharacters : Int32 = 0
238274 var cCharacters : UnsafePointer < UnsafePointer < Int8 > ? > ?
239275 let validCharactersStatus = pv_orca_valid_characters ( handle, & cNumCharacters, & cCharacters)
240276 if validCharactersStatus != PV_STATUS_SUCCESS {
241- let messageStack = try getMessageStack ( )
242- throw pvStatusToOrcaError ( validCharactersStatus, " Unable to get Orca valid characters " , messageStack)
277+ let messageStack = try Orca . getMessageStack ( )
278+ throw Orca . pvStatusToOrcaError ( validCharactersStatus, " Unable to get Orca valid characters " , messageStack)
243279 }
244280 var validCharacters : Set < String > = [ " ‘ " , " ’ " , " “ " , " ” " ]
245281 for i in 0 ..< cNumCharacters {
@@ -254,16 +290,16 @@ public class Orca {
254290 var cSampleRate : Int32 = 0
255291 let sampleRateStatus = pv_orca_sample_rate ( handle, & cSampleRate)
256292 if sampleRateStatus != PV_STATUS_SUCCESS {
257- let messageStack = try getMessageStack ( )
258- throw pvStatusToOrcaError ( sampleRateStatus, " Orca failed to get sample rate " , messageStack)
293+ let messageStack = try Orca . getMessageStack ( )
294+ throw Orca . pvStatusToOrcaError ( sampleRateStatus, " Orca failed to get sample rate " , messageStack)
259295 }
260296 self . _sampleRate = cSampleRate
261297
262298 var cMaxCharacterLimit : Int32 = 0
263299 let maxCharacterLimitStatus = pv_orca_max_character_limit ( handle, & cMaxCharacterLimit)
264300 if maxCharacterLimitStatus != PV_STATUS_SUCCESS {
265- let messageStack = try getMessageStack ( )
266- throw pvStatusToOrcaError ( maxCharacterLimitStatus, " Orca failed to get max character limit " , messageStack)
301+ let messageStack = try Orca . getMessageStack ( )
302+ throw Orca . pvStatusToOrcaError ( maxCharacterLimitStatus, " Orca failed to get max character limit " , messageStack)
267303 }
268304 self . _maxCharacterLimit = cMaxCharacterLimit
269305 }
@@ -273,14 +309,22 @@ public class Orca {
273309 /// - Parameters:
274310 /// - accessKey: The AccessKey obtained from Picovoice Console (https://console.picovoice.ai).
275311 /// - modelURL: URL to file containing model parameters.
312+ /// - device: String representation of the device (e.g., CPU or GPU) to use. If set to `best`, the most
313+ /// suitable device is selected automatically. If set to `gpu`, the engine uses the first available GPU
314+ /// device. To select a specific GPU device, set this argument to `gpu:${GPU_INDEX}`, where `${GPU_INDEX}`
315+ /// is the index of the target GPU. If set to `cpu`, the engine will run on the CPU with the default
316+ /// number of threads. To specify the number of threads, set this argument to `cpu:${NUM_THREADS}`,
317+ /// where `${NUM_THREADS}` is the desired number of threads.
276318 /// - Throws: OrcaError
277319 public convenience init (
278320 accessKey: String ,
279- modelURL: URL ) throws {
321+ modelURL: URL ,
322+ device: String ? = nil ) throws {
280323
281324 try self . init (
282325 accessKey: accessKey,
283- modelPath: modelURL. path)
326+ modelPath: modelURL. path,
327+ device: device)
284328 }
285329
286330 deinit {
@@ -340,8 +384,8 @@ public class Orca {
340384 & cNumAlignments,
341385 & cAlignments)
342386 if status != PV_STATUS_SUCCESS {
343- let messageStack = try getMessageStack ( )
344- throw pvStatusToOrcaError ( status, " Unable to synthesize speech " , messageStack)
387+ let messageStack = try Orca . getMessageStack ( )
388+ throw Orca . pvStatusToOrcaError ( status, " Unable to synthesize speech " , messageStack)
345389 }
346390
347391 let buffer = UnsafeBufferPointer ( start: cPcm, count: Int ( cNumSamples) )
@@ -426,8 +470,8 @@ public class Orca {
426470 & cNumAlignments,
427471 & cAlignments)
428472 if status != PV_STATUS_SUCCESS {
429- let messageStack = try getMessageStack ( )
430- throw pvStatusToOrcaError ( status, " Unable to synthesize speech to file " , messageStack)
473+ let messageStack = try Orca . getMessageStack ( )
474+ throw Orca . pvStatusToOrcaError ( status, " Unable to synthesize speech to file " , messageStack)
431475 }
432476
433477 var wordArray = [ OrcaWord] ( )
@@ -492,23 +536,23 @@ public class Orca {
492536
493537 var status = pv_orca_synthesize_params_init ( & cParams)
494538 if status != PV_STATUS_SUCCESS {
495- let messageStack = try getMessageStack ( )
496- throw pvStatusToOrcaError ( status, " Unable to create Orca synthesize params object " , messageStack)
539+ let messageStack = try Orca . getMessageStack ( )
540+ throw Orca . pvStatusToOrcaError ( status, " Unable to create Orca synthesize params object " , messageStack)
497541 }
498542
499543 if speechRate != nil {
500544 status = pv_orca_synthesize_params_set_speech_rate ( cParams, Float ( speechRate!) )
501545 if status != PV_STATUS_SUCCESS {
502- let messageStack = try getMessageStack ( )
503- throw pvStatusToOrcaError ( status, " Unable to set Orca speech rate " , messageStack)
546+ let messageStack = try Orca . getMessageStack ( )
547+ throw Orca . pvStatusToOrcaError ( status, " Unable to set Orca speech rate " , messageStack)
504548 }
505549 }
506550
507551 if randomState != nil {
508552 status = pv_orca_synthesize_params_set_random_state ( cParams, randomState!)
509553 if status != PV_STATUS_SUCCESS {
510- let messageStack = try getMessageStack ( )
511- throw pvStatusToOrcaError ( status, " Unable to set Orca random state " , messageStack)
554+ let messageStack = try Orca . getMessageStack ( )
555+ throw Orca . pvStatusToOrcaError ( status, " Unable to set Orca random state " , messageStack)
512556 }
513557 }
514558
@@ -534,8 +578,8 @@ public class Orca {
534578 cSynthesizeParams,
535579 & stream)
536580 if status != PV_STATUS_SUCCESS {
537- let messageStack = try getMessageStack ( )
538- throw pvStatusToOrcaError ( status, " Unable to open stream " , messageStack)
581+ let messageStack = try Orca . getMessageStack ( )
582+ throw Orca . pvStatusToOrcaError ( status, " Unable to open stream " , messageStack)
539583 }
540584
541585 return OrcaStream ( orca: self , stream: stream!)
@@ -558,7 +602,7 @@ public class Orca {
558602 " If this is a packaged asset, ensure you have added it to your xcode project. " )
559603 }
560604
561- private func pvStatusToOrcaError(
605+ private static func pvStatusToOrcaError(
562606 _ status: pv_status_t ,
563607 _ message: String ,
564608 _ messageStack: [ String ] = [ ] ) -> OrcaError {
@@ -591,12 +635,12 @@ public class Orca {
591635 }
592636 }
593637
594- private func getMessageStack( ) throws -> [ String ] {
638+ private static func getMessageStack( ) throws -> [ String ] {
595639 var messageStackRef : UnsafeMutablePointer < UnsafeMutablePointer < Int8 > ? > ?
596640 var messageStackDepth : Int32 = 0
597641 let status = pv_get_error_stack ( & messageStackRef, & messageStackDepth)
598642 if status != PV_STATUS_SUCCESS {
599- throw pvStatusToOrcaError ( status, " Unable to get Orca error state " )
643+ throw Orca . pvStatusToOrcaError ( status, " Unable to get Orca error state " )
600644 }
601645
602646 var messageStack : [ String ] = [ ]
0 commit comments