正在显示
2 个修改的文件
包含
126 行增加
和
139 行删除
| @@ -198,81 +198,64 @@ func sherpaOnnxOnlineRecognizerConfig( | @@ -198,81 +198,64 @@ func sherpaOnnxOnlineRecognizerConfig( | ||
| 198 | /// | 198 | /// |
| 199 | class SherpaOnnxOnlineRecongitionResult { | 199 | class SherpaOnnxOnlineRecongitionResult { |
| 200 | /// A pointer to the underlying counterpart in C | 200 | /// A pointer to the underlying counterpart in C |
| 201 | - let result: UnsafePointer<SherpaOnnxOnlineRecognizerResult>! | 201 | + private let result: UnsafePointer<SherpaOnnxOnlineRecognizerResult> |
| 202 | 202 | ||
| 203 | - /// Return the actual recognition result. | ||
| 204 | - /// For English models, it contains words separated by spaces. | ||
| 205 | - /// For Chinese models, it contains Chinese words. | ||
| 206 | - var text: String { | ||
| 207 | - return String(cString: result.pointee.text) | ||
| 208 | - } | 203 | + private lazy var _text: String = { |
| 204 | + guard let cstr = result.pointee.text else { return "" } | ||
| 205 | + return String(cString: cstr) | ||
| 206 | + }() | ||
| 209 | 207 | ||
| 210 | - var count: Int32 { | ||
| 211 | - return result.pointee.count | 208 | + private lazy var _tokens: [String] = { |
| 209 | + guard let tokensPointer = result.pointee.tokens_arr else { return [] } | ||
| 210 | + return (0..<count).compactMap { index in | ||
| 211 | + guard let ptr = tokensPointer[index] else { return nil } | ||
| 212 | + return String(cString: ptr) | ||
| 212 | } | 213 | } |
| 214 | + }() | ||
| 213 | 215 | ||
| 214 | - var tokens: [String] { | ||
| 215 | - if let tokensPointer = result.pointee.tokens_arr { | ||
| 216 | - var tokens: [String] = [] | ||
| 217 | - for index in 0..<count { | ||
| 218 | - if let tokenPointer = tokensPointer[Int(index)] { | ||
| 219 | - let token = String(cString: tokenPointer) | ||
| 220 | - tokens.append(token) | ||
| 221 | - } | ||
| 222 | - } | ||
| 223 | - return tokens | ||
| 224 | - } else { | ||
| 225 | - let tokens: [String] = [] | ||
| 226 | - return tokens | ||
| 227 | - } | ||
| 228 | - } | 216 | + private lazy var _timestamps: [Float] = { |
| 217 | + guard let timestampsPointer = result.pointee.timestamps else { return [] } | ||
| 218 | + return (0..<count).map { index in timestampsPointer[index] } | ||
| 219 | + }() | ||
| 229 | 220 | ||
| 230 | - var timestamps: [Float] { | ||
| 231 | - if let p = result.pointee.timestamps { | ||
| 232 | - var timestamps: [Float] = [] | ||
| 233 | - for index in 0..<count { | ||
| 234 | - timestamps.append(p[Int(index)]) | ||
| 235 | - } | ||
| 236 | - return timestamps | ||
| 237 | - } else { | ||
| 238 | - let timestamps: [Float] = [] | ||
| 239 | - return timestamps | ||
| 240 | - } | ||
| 241 | - } | ||
| 242 | - | ||
| 243 | - init(result: UnsafePointer<SherpaOnnxOnlineRecognizerResult>!) { | 221 | + init(result: UnsafePointer<SherpaOnnxOnlineRecognizerResult>) { |
| 244 | self.result = result | 222 | self.result = result |
| 245 | } | 223 | } |
| 246 | 224 | ||
| 247 | deinit { | 225 | deinit { |
| 248 | - if let result { | ||
| 249 | SherpaOnnxDestroyOnlineRecognizerResult(result) | 226 | SherpaOnnxDestroyOnlineRecognizerResult(result) |
| 250 | } | 227 | } |
| 251 | - } | 228 | + |
| 229 | + /// Return the actual recognition result. | ||
| 230 | + /// For English models, it contains words separated by spaces. | ||
| 231 | + /// For Chinese models, it contains Chinese words. | ||
| 232 | + var text: String { _text } | ||
| 233 | + | ||
| 234 | + var count: Int { Int(result.pointee.count) } | ||
| 235 | + | ||
| 236 | + var tokens: [String] { _tokens } | ||
| 237 | + | ||
| 238 | + var timestamps: [Float] { _timestamps } | ||
| 252 | } | 239 | } |
| 253 | 240 | ||
| 254 | class SherpaOnnxRecognizer { | 241 | class SherpaOnnxRecognizer { |
| 255 | /// A pointer to the underlying counterpart in C | 242 | /// A pointer to the underlying counterpart in C |
| 256 | - let recognizer: OpaquePointer! | ||
| 257 | - var stream: OpaquePointer! | 243 | + private let recognizer: OpaquePointer |
| 244 | + private var stream: OpaquePointer | ||
| 245 | + private let lock = NSLock() // for thread-safe stream replacement | ||
| 258 | 246 | ||
| 259 | /// Constructor taking a model config | 247 | /// Constructor taking a model config |
| 260 | init( | 248 | init( |
| 261 | - config: UnsafePointer<SherpaOnnxOnlineRecognizerConfig>! | 249 | + config: UnsafePointer<SherpaOnnxOnlineRecognizerConfig> |
| 262 | ) { | 250 | ) { |
| 263 | - recognizer = SherpaOnnxCreateOnlineRecognizer(config) | ||
| 264 | - stream = SherpaOnnxCreateOnlineStream(recognizer) | 251 | + self.recognizer = SherpaOnnxCreateOnlineRecognizer(config) |
| 252 | + self.stream = SherpaOnnxCreateOnlineStream(recognizer) | ||
| 265 | } | 253 | } |
| 266 | 254 | ||
| 267 | deinit { | 255 | deinit { |
| 268 | - if let stream { | ||
| 269 | SherpaOnnxDestroyOnlineStream(stream) | 256 | SherpaOnnxDestroyOnlineStream(stream) |
| 270 | - } | ||
| 271 | - | ||
| 272 | - if let recognizer { | ||
| 273 | SherpaOnnxDestroyOnlineRecognizer(recognizer) | 257 | SherpaOnnxDestroyOnlineRecognizer(recognizer) |
| 274 | } | 258 | } |
| 275 | - } | ||
| 276 | 259 | ||
| 277 | /// Decode wave samples. | 260 | /// Decode wave samples. |
| 278 | /// | 261 | /// |
| @@ -280,12 +263,12 @@ class SherpaOnnxRecognizer { | @@ -280,12 +263,12 @@ class SherpaOnnxRecognizer { | ||
| 280 | /// - samples: Audio samples normalized to the range [-1, 1] | 263 | /// - samples: Audio samples normalized to the range [-1, 1] |
| 281 | /// - sampleRate: Sample rate of the input audio samples. Must match | 264 | /// - sampleRate: Sample rate of the input audio samples. Must match |
| 282 | /// the one expected by the model. | 265 | /// the one expected by the model. |
| 283 | - func acceptWaveform(samples: [Float], sampleRate: Int = 16000) { | 266 | + func acceptWaveform(samples: [Float], sampleRate: Int = 16_000) { |
| 284 | SherpaOnnxOnlineStreamAcceptWaveform(stream, Int32(sampleRate), samples, Int32(samples.count)) | 267 | SherpaOnnxOnlineStreamAcceptWaveform(stream, Int32(sampleRate), samples, Int32(samples.count)) |
| 285 | } | 268 | } |
| 286 | 269 | ||
| 287 | func isReady() -> Bool { | 270 | func isReady() -> Bool { |
| 288 | - return SherpaOnnxIsOnlineStreamReady(recognizer, stream) == 1 ? true : false | 271 | + return SherpaOnnxIsOnlineStreamReady(recognizer, stream) != 0 |
| 289 | } | 272 | } |
| 290 | 273 | ||
| 291 | /// If there are enough number of feature frames, it invokes the neural | 274 | /// If there are enough number of feature frames, it invokes the neural |
| @@ -296,8 +279,9 @@ class SherpaOnnxRecognizer { | @@ -296,8 +279,9 @@ class SherpaOnnxRecognizer { | ||
| 296 | 279 | ||
| 297 | /// Get the decoding results so far | 280 | /// Get the decoding results so far |
| 298 | func getResult() -> SherpaOnnxOnlineRecongitionResult { | 281 | func getResult() -> SherpaOnnxOnlineRecongitionResult { |
| 299 | - let result: UnsafePointer<SherpaOnnxOnlineRecognizerResult>? = SherpaOnnxGetOnlineStreamResult( | ||
| 300 | - recognizer, stream) | 282 | + guard let result = SherpaOnnxGetOnlineStreamResult(recognizer, stream) else { |
| 283 | + fatalError("SherpaOnnxGetOnlineStreamResult returned nil") | ||
| 284 | + } | ||
| 301 | return SherpaOnnxOnlineRecongitionResult(result: result) | 285 | return SherpaOnnxOnlineRecongitionResult(result: result) |
| 302 | } | 286 | } |
| 303 | 287 | ||
| @@ -313,12 +297,14 @@ class SherpaOnnxRecognizer { | @@ -313,12 +297,14 @@ class SherpaOnnxRecognizer { | ||
| 313 | } | 297 | } |
| 314 | 298 | ||
| 315 | words.withCString { cString in | 299 | words.withCString { cString in |
| 316 | - let newStream = SherpaOnnxCreateOnlineStreamWithHotwords(recognizer, cString) | 300 | + guard let newStream = SherpaOnnxCreateOnlineStreamWithHotwords(recognizer, cString) else { |
| 301 | + fatalError("SherpaOnnxCreateOnlineStreamWithHotwords returned nil") | ||
| 302 | + } | ||
| 303 | + lock.lock() | ||
| 317 | // lock while release and replace stream | 304 | // lock while release and replace stream |
| 318 | - objc_sync_enter(self) | ||
| 319 | SherpaOnnxDestroyOnlineStream(stream) | 305 | SherpaOnnxDestroyOnlineStream(stream) |
| 320 | stream = newStream | 306 | stream = newStream |
| 321 | - objc_sync_exit(self) | 307 | + lock.unlock() |
| 322 | } | 308 | } |
| 323 | } | 309 | } |
| 324 | 310 | ||
| @@ -330,7 +316,7 @@ class SherpaOnnxRecognizer { | @@ -330,7 +316,7 @@ class SherpaOnnxRecognizer { | ||
| 330 | 316 | ||
| 331 | /// Return true is an endpoint has been detected. | 317 | /// Return true is an endpoint has been detected. |
| 332 | func isEndpoint() -> Bool { | 318 | func isEndpoint() -> Bool { |
| 333 | - return SherpaOnnxOnlineStreamIsEndpoint(recognizer, stream) == 1 ? true : false | 319 | + return SherpaOnnxOnlineStreamIsEndpoint(recognizer, stream) != 0 |
| 334 | } | 320 | } |
| 335 | } | 321 | } |
| 336 | 322 | ||
| @@ -541,31 +527,39 @@ func sherpaOnnxOfflineRecognizerConfig( | @@ -541,31 +527,39 @@ func sherpaOnnxOfflineRecognizerConfig( | ||
| 541 | 527 | ||
| 542 | class SherpaOnnxOfflineRecongitionResult { | 528 | class SherpaOnnxOfflineRecongitionResult { |
| 543 | /// A pointer to the underlying counterpart in C | 529 | /// A pointer to the underlying counterpart in C |
| 544 | - let result: UnsafePointer<SherpaOnnxOfflineRecognizerResult>! | 530 | + let result: UnsafePointer<SherpaOnnxOfflineRecognizerResult> |
| 531 | + | ||
| 532 | + private lazy var _text: String = { | ||
| 533 | + guard let cstr = result.pointee.text else { return "" } | ||
| 534 | + return String(cString: cstr) | ||
| 535 | + }() | ||
| 536 | + | ||
| 537 | + private lazy var _timestamps: [Float] = { | ||
| 538 | + guard let p = result.pointee.timestamps else { return [] } | ||
| 539 | + return (0..<result.pointee.count).map { p[Int($0)] } | ||
| 540 | + }() | ||
| 541 | + | ||
| 542 | + private lazy var _lang: String = { | ||
| 543 | + guard let cstr = result.pointee.lang else { return "" } | ||
| 544 | + return String(cString: cstr) | ||
| 545 | + }() | ||
| 546 | + | ||
| 547 | + private lazy var _emotion: String = { | ||
| 548 | + guard let cstr = result.pointee.emotion else { return "" } | ||
| 549 | + return String(cString: cstr) | ||
| 550 | + }() | ||
| 551 | + | ||
| 552 | + private lazy var _event: String = { | ||
| 553 | + guard let cstr = result.pointee.event else { return "" } | ||
| 554 | + return String(cString: cstr) | ||
| 555 | + }() | ||
| 545 | 556 | ||
| 546 | /// Return the actual recognition result. | 557 | /// Return the actual recognition result. |
| 547 | /// For English models, it contains words separated by spaces. | 558 | /// For English models, it contains words separated by spaces. |
| 548 | /// For Chinese models, it contains Chinese words. | 559 | /// For Chinese models, it contains Chinese words. |
| 549 | - var text: String { | ||
| 550 | - return String(cString: result.pointee.text) | ||
| 551 | - } | ||
| 552 | - | ||
| 553 | - var count: Int32 { | ||
| 554 | - return result.pointee.count | ||
| 555 | - } | ||
| 556 | - | ||
| 557 | - var timestamps: [Float] { | ||
| 558 | - if let p = result.pointee.timestamps { | ||
| 559 | - var timestamps: [Float] = [] | ||
| 560 | - for index in 0..<count { | ||
| 561 | - timestamps.append(p[Int(index)]) | ||
| 562 | - } | ||
| 563 | - return timestamps | ||
| 564 | - } else { | ||
| 565 | - let timestamps: [Float] = [] | ||
| 566 | - return timestamps | ||
| 567 | - } | ||
| 568 | - } | 560 | + var text: String { _text } |
| 561 | + var count: Int { Int(result.pointee.count) } | ||
| 562 | + var timestamps: [Float] { _timestamps } | ||
| 569 | 563 | ||
| 570 | // For SenseVoice models, it can be zh, en, ja, yue, ko | 564 | // For SenseVoice models, it can be zh, en, ja, yue, ko |
| 571 | // where zh is for Chinese | 565 | // where zh is for Chinese |
| @@ -573,46 +567,39 @@ class SherpaOnnxOfflineRecongitionResult { | @@ -573,46 +567,39 @@ class SherpaOnnxOfflineRecongitionResult { | ||
| 573 | // ja is for Japanese | 567 | // ja is for Japanese |
| 574 | // yue is for Cantonese | 568 | // yue is for Cantonese |
| 575 | // ko is for Korean | 569 | // ko is for Korean |
| 576 | - var lang: String { | ||
| 577 | - return String(cString: result.pointee.lang) | ||
| 578 | - } | 570 | + var lang: String { _lang } |
| 579 | 571 | ||
| 580 | // for SenseVoice models | 572 | // for SenseVoice models |
| 581 | - var emotion: String { | ||
| 582 | - return String(cString: result.pointee.emotion) | ||
| 583 | - } | 573 | + var emotion: String { _emotion } |
| 584 | 574 | ||
| 585 | // for SenseVoice models | 575 | // for SenseVoice models |
| 586 | - var event: String { | ||
| 587 | - return String(cString: result.pointee.event) | ||
| 588 | - } | 576 | + var event: String { _event } |
| 589 | 577 | ||
| 590 | - init(result: UnsafePointer<SherpaOnnxOfflineRecognizerResult>!) { | 578 | + init(result: UnsafePointer<SherpaOnnxOfflineRecognizerResult>) { |
| 591 | self.result = result | 579 | self.result = result |
| 592 | } | 580 | } |
| 593 | 581 | ||
| 594 | deinit { | 582 | deinit { |
| 595 | - if let result { | ||
| 596 | SherpaOnnxDestroyOfflineRecognizerResult(result) | 583 | SherpaOnnxDestroyOfflineRecognizerResult(result) |
| 597 | } | 584 | } |
| 598 | - } | ||
| 599 | } | 585 | } |
| 600 | 586 | ||
| 601 | class SherpaOnnxOfflineRecognizer { | 587 | class SherpaOnnxOfflineRecognizer { |
| 602 | /// A pointer to the underlying counterpart in C | 588 | /// A pointer to the underlying counterpart in C |
| 603 | - let recognizer: OpaquePointer! | 589 | + private let recognizer: OpaquePointer |
| 604 | 590 | ||
| 605 | init( | 591 | init( |
| 606 | - config: UnsafePointer<SherpaOnnxOfflineRecognizerConfig>! | 592 | + config: UnsafePointer<SherpaOnnxOfflineRecognizerConfig> |
| 607 | ) { | 593 | ) { |
| 608 | - recognizer = SherpaOnnxCreateOfflineRecognizer(config) | 594 | + guard let ptr = SherpaOnnxCreateOfflineRecognizer(config) else { |
| 595 | + fatalError("Failed to create SherpaOnnxOfflineRecognizer") | ||
| 596 | + } | ||
| 597 | + self.recognizer = ptr | ||
| 609 | } | 598 | } |
| 610 | 599 | ||
| 611 | deinit { | 600 | deinit { |
| 612 | - if let recognizer { | ||
| 613 | SherpaOnnxDestroyOfflineRecognizer(recognizer) | 601 | SherpaOnnxDestroyOfflineRecognizer(recognizer) |
| 614 | } | 602 | } |
| 615 | - } | ||
| 616 | 603 | ||
| 617 | /// Decode wave samples. | 604 | /// Decode wave samples. |
| 618 | /// | 605 | /// |
| @@ -620,23 +607,25 @@ class SherpaOnnxOfflineRecognizer { | @@ -620,23 +607,25 @@ class SherpaOnnxOfflineRecognizer { | ||
| 620 | /// - samples: Audio samples normalized to the range [-1, 1] | 607 | /// - samples: Audio samples normalized to the range [-1, 1] |
| 621 | /// - sampleRate: Sample rate of the input audio samples. Must match | 608 | /// - sampleRate: Sample rate of the input audio samples. Must match |
| 622 | /// the one expected by the model. | 609 | /// the one expected by the model. |
| 623 | - func decode(samples: [Float], sampleRate: Int = 16000) -> SherpaOnnxOfflineRecongitionResult { | ||
| 624 | - let stream: OpaquePointer! = SherpaOnnxCreateOfflineStream(recognizer) | 610 | + func decode(samples: [Float], sampleRate: Int = 16_000) -> SherpaOnnxOfflineRecongitionResult { |
| 611 | + guard let stream = SherpaOnnxCreateOfflineStream(recognizer) else { | ||
| 612 | + fatalError("Failed to create offline stream") | ||
| 613 | + } | ||
| 614 | + | ||
| 615 | + defer { SherpaOnnxDestroyOfflineStream(stream) } | ||
| 625 | 616 | ||
| 626 | SherpaOnnxAcceptWaveformOffline(stream, Int32(sampleRate), samples, Int32(samples.count)) | 617 | SherpaOnnxAcceptWaveformOffline(stream, Int32(sampleRate), samples, Int32(samples.count)) |
| 627 | 618 | ||
| 628 | SherpaOnnxDecodeOfflineStream(recognizer, stream) | 619 | SherpaOnnxDecodeOfflineStream(recognizer, stream) |
| 629 | 620 | ||
| 630 | - let result: UnsafePointer<SherpaOnnxOfflineRecognizerResult>? = | ||
| 631 | - SherpaOnnxGetOfflineStreamResult( | ||
| 632 | - stream) | ||
| 633 | - | ||
| 634 | - SherpaOnnxDestroyOfflineStream(stream) | 621 | + guard let resultPtr = SherpaOnnxGetOfflineStreamResult(stream) else { |
| 622 | + fatalError("Failed to get offline recognition result") | ||
| 623 | + } | ||
| 635 | 624 | ||
| 636 | - return SherpaOnnxOfflineRecongitionResult(result: result) | 625 | + return SherpaOnnxOfflineRecongitionResult(result: resultPtr) |
| 637 | } | 626 | } |
| 638 | 627 | ||
| 639 | - func setConfig(config: UnsafePointer<SherpaOnnxOfflineRecognizerConfig>!) { | 628 | + func setConfig(config: UnsafePointer<SherpaOnnxOfflineRecognizerConfig>) { |
| 640 | SherpaOnnxOfflineRecognizerSetConfig(recognizer, config) | 629 | SherpaOnnxOfflineRecognizerSetConfig(recognizer, config) |
| 641 | } | 630 | } |
| 642 | } | 631 | } |
| @@ -696,37 +685,38 @@ func sherpaOnnxVadModelConfig( | @@ -696,37 +685,38 @@ func sherpaOnnxVadModelConfig( | ||
| 696 | } | 685 | } |
| 697 | 686 | ||
| 698 | class SherpaOnnxCircularBufferWrapper { | 687 | class SherpaOnnxCircularBufferWrapper { |
| 699 | - let buffer: OpaquePointer! | 688 | + private let buffer: OpaquePointer |
| 700 | 689 | ||
| 701 | init(capacity: Int) { | 690 | init(capacity: Int) { |
| 702 | - buffer = SherpaOnnxCreateCircularBuffer(Int32(capacity)) | 691 | + guard let ptr = SherpaOnnxCreateCircularBuffer(Int32(capacity)) else { |
| 692 | + fatalError("Failed to create SherpaOnnxCircularBuffer") | ||
| 693 | + } | ||
| 694 | + self.buffer = ptr | ||
| 703 | } | 695 | } |
| 704 | 696 | ||
| 705 | deinit { | 697 | deinit { |
| 706 | - if let buffer { | ||
| 707 | SherpaOnnxDestroyCircularBuffer(buffer) | 698 | SherpaOnnxDestroyCircularBuffer(buffer) |
| 708 | } | 699 | } |
| 709 | - } | ||
| 710 | 700 | ||
| 711 | func push(samples: [Float]) { | 701 | func push(samples: [Float]) { |
| 702 | + guard !samples.isEmpty else { return } | ||
| 712 | SherpaOnnxCircularBufferPush(buffer, samples, Int32(samples.count)) | 703 | SherpaOnnxCircularBufferPush(buffer, samples, Int32(samples.count)) |
| 713 | } | 704 | } |
| 714 | 705 | ||
| 715 | func get(startIndex: Int, n: Int) -> [Float] { | 706 | func get(startIndex: Int, n: Int) -> [Float] { |
| 716 | - let p: UnsafePointer<Float>! = SherpaOnnxCircularBufferGet(buffer, Int32(startIndex), Int32(n)) | 707 | + guard startIndex >= 0 else { return [] } |
| 708 | + guard n > 0 else { return [] } | ||
| 717 | 709 | ||
| 718 | - var samples: [Float] = [] | ||
| 719 | - | ||
| 720 | - for index in 0..<n { | ||
| 721 | - samples.append(p[Int(index)]) | 710 | + guard let ptr = SherpaOnnxCircularBufferGet(buffer, Int32(startIndex), Int32(n)) else { |
| 711 | + return [] | ||
| 722 | } | 712 | } |
| 713 | + defer { SherpaOnnxCircularBufferFree(ptr) } | ||
| 723 | 714 | ||
| 724 | - SherpaOnnxCircularBufferFree(p) | ||
| 725 | - | ||
| 726 | - return samples | 715 | + return Array(UnsafeBufferPointer(start: ptr, count: n)) |
| 727 | } | 716 | } |
| 728 | 717 | ||
| 729 | func pop(n: Int) { | 718 | func pop(n: Int) { |
| 719 | + guard n > 0 else { return } | ||
| 730 | SherpaOnnxCircularBufferPop(buffer, Int32(n)) | 720 | SherpaOnnxCircularBufferPop(buffer, Int32(n)) |
| 731 | } | 721 | } |
| 732 | 722 | ||
| @@ -740,48 +730,43 @@ class SherpaOnnxCircularBufferWrapper { | @@ -740,48 +730,43 @@ class SherpaOnnxCircularBufferWrapper { | ||
| 740 | } | 730 | } |
| 741 | 731 | ||
| 742 | class SherpaOnnxSpeechSegmentWrapper { | 732 | class SherpaOnnxSpeechSegmentWrapper { |
| 743 | - let p: UnsafePointer<SherpaOnnxSpeechSegment>! | 733 | + private let p: UnsafePointer<SherpaOnnxSpeechSegment> |
| 744 | 734 | ||
| 745 | - init(p: UnsafePointer<SherpaOnnxSpeechSegment>!) { | 735 | + init(p: UnsafePointer<SherpaOnnxSpeechSegment>) { |
| 746 | self.p = p | 736 | self.p = p |
| 747 | } | 737 | } |
| 748 | 738 | ||
| 749 | deinit { | 739 | deinit { |
| 750 | - if let p { | ||
| 751 | SherpaOnnxDestroySpeechSegment(p) | 740 | SherpaOnnxDestroySpeechSegment(p) |
| 752 | } | 741 | } |
| 753 | - } | ||
| 754 | 742 | ||
| 755 | var start: Int { | 743 | var start: Int { |
| 756 | - return Int(p.pointee.start) | 744 | + Int(p.pointee.start) |
| 757 | } | 745 | } |
| 758 | 746 | ||
| 759 | var n: Int { | 747 | var n: Int { |
| 760 | - return Int(p.pointee.n) | 748 | + Int(p.pointee.n) |
| 761 | } | 749 | } |
| 762 | 750 | ||
| 763 | - var samples: [Float] { | ||
| 764 | - var samples: [Float] = [] | ||
| 765 | - for index in 0..<n { | ||
| 766 | - samples.append(p.pointee.samples[Int(index)]) | ||
| 767 | - } | ||
| 768 | - return samples | ||
| 769 | - } | 751 | + lazy var samples: [Float] = { |
| 752 | + Array(UnsafeBufferPointer(start: p.pointee.samples, count: n)) | ||
| 753 | + }() | ||
| 770 | } | 754 | } |
| 771 | 755 | ||
| 772 | class SherpaOnnxVoiceActivityDetectorWrapper { | 756 | class SherpaOnnxVoiceActivityDetectorWrapper { |
| 773 | /// A pointer to the underlying counterpart in C | 757 | /// A pointer to the underlying counterpart in C |
| 774 | - let vad: OpaquePointer! | 758 | + private let vad: OpaquePointer |
| 775 | 759 | ||
| 776 | - init(config: UnsafePointer<SherpaOnnxVadModelConfig>!, buffer_size_in_seconds: Float) { | ||
| 777 | - vad = SherpaOnnxCreateVoiceActivityDetector(config, buffer_size_in_seconds) | 760 | + init(config: UnsafePointer<SherpaOnnxVadModelConfig>, buffer_size_in_seconds: Float) { |
| 761 | + guard let vad = SherpaOnnxCreateVoiceActivityDetector(config, buffer_size_in_seconds) else { | ||
| 762 | + fatalError("SherpaOnnxCreateVoiceActivityDetector returned nil") | ||
| 763 | + } | ||
| 764 | + self.vad = vad | ||
| 778 | } | 765 | } |
| 779 | 766 | ||
| 780 | deinit { | 767 | deinit { |
| 781 | - if let vad { | ||
| 782 | SherpaOnnxDestroyVoiceActivityDetector(vad) | 768 | SherpaOnnxDestroyVoiceActivityDetector(vad) |
| 783 | } | 769 | } |
| 784 | - } | ||
| 785 | 770 | ||
| 786 | func acceptWaveform(samples: [Float]) { | 771 | func acceptWaveform(samples: [Float]) { |
| 787 | SherpaOnnxVoiceActivityDetectorAcceptWaveform(vad, samples, Int32(samples.count)) | 772 | SherpaOnnxVoiceActivityDetectorAcceptWaveform(vad, samples, Int32(samples.count)) |
| @@ -804,7 +789,9 @@ class SherpaOnnxVoiceActivityDetectorWrapper { | @@ -804,7 +789,9 @@ class SherpaOnnxVoiceActivityDetectorWrapper { | ||
| 804 | } | 789 | } |
| 805 | 790 | ||
| 806 | func front() -> SherpaOnnxSpeechSegmentWrapper { | 791 | func front() -> SherpaOnnxSpeechSegmentWrapper { |
| 807 | - let p: UnsafePointer<SherpaOnnxSpeechSegment>? = SherpaOnnxVoiceActivityDetectorFront(vad) | 792 | + guard let p = SherpaOnnxVoiceActivityDetectorFront(vad) else { |
| 793 | + fatalError("SherpaOnnxVoiceActivityDetectorFront returned nil") | ||
| 794 | + } | ||
| 808 | return SherpaOnnxSpeechSegmentWrapper(p: p) | 795 | return SherpaOnnxSpeechSegmentWrapper(p: p) |
| 809 | } | 796 | } |
| 810 | 797 |
| @@ -94,9 +94,9 @@ class SpeechSegment: CustomStringConvertible { | @@ -94,9 +94,9 @@ class SpeechSegment: CustomStringConvertible { | ||
| 94 | func run() { | 94 | func run() { |
| 95 | var recognizer: SherpaOnnxOfflineRecognizer | 95 | var recognizer: SherpaOnnxOfflineRecognizer |
| 96 | var modelConfig: SherpaOnnxOfflineModelConfig | 96 | var modelConfig: SherpaOnnxOfflineModelConfig |
| 97 | - var modelType = "whisper" | 97 | + let modelType = "whisper" |
| 98 | // modelType = "paraformer" | 98 | // modelType = "paraformer" |
| 99 | - var filePath = "/Users/fangjun/Desktop/Obama.wav" // English | 99 | + let filePath = "/Users/fangjun/Desktop/Obama.wav" // English |
| 100 | // filePath = "/Users/fangjun/Desktop/lei-jun.wav" // Chinese | 100 | // filePath = "/Users/fangjun/Desktop/lei-jun.wav" // Chinese |
| 101 | // please go to https://huggingface.co/csukuangfj/vad | 101 | // please go to https://huggingface.co/csukuangfj/vad |
| 102 | // to download the above two files | 102 | // to download the above two files |
| @@ -192,7 +192,7 @@ func run() { | @@ -192,7 +192,7 @@ func run() { | ||
| 192 | let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: audioFrameCount) | 192 | let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: audioFrameCount) |
| 193 | 193 | ||
| 194 | try! audioFile.read(into: audioFileBuffer!) | 194 | try! audioFile.read(into: audioFileBuffer!) |
| 195 | - var array: [Float]! = audioFileBuffer?.array() | 195 | + let array: [Float]! = audioFileBuffer?.array() |
| 196 | 196 | ||
| 197 | var segments: [SpeechSegment] = [] | 197 | var segments: [SpeechSegment] = [] |
| 198 | 198 |
-
请 注册 或 登录 后发表评论