This repository has been archived on 2025-08-26. You can view files and clone it, but cannot push or open issues or pull requests.
Files
enginex-mr_series-sherpa-onnx/ios-swiftui/SherpaOnnxLangID/SherpaOnnxLangID/ViewModel.swift
2024-04-01 20:34:14 +08:00

132 lines
3.5 KiB
Swift

//
// ViewModel.swift
// SherpaOnnxLangID
//
// Created by knight on 2024/4/1.
//
import SwiftUI
import AVFoundation
enum Status {
case stop
case recording
}
@MainActor
class ViewModel:ObservableObject {
@Published var status: Status = .stop
@Published var language: String = ""
var languageIdentifier: SherpaOnnxSpokenLanguageIdentificationWrapper? = nil
var audioEngine: AVAudioEngine? = nil
var voices: [Float] = []
init() {
initRecorder()
initRecognizer()
}
private func initRecognizer() {
var config = getLanguageIdentificationTiny()
self.languageIdentifier = SherpaOnnxSpokenLanguageIdentificationWrapper(config: &config)
}
private func initRecorder() {
print("init recorder")
audioEngine = AVAudioEngine()
let inputNode = self.audioEngine?.inputNode
let bus = 0
let inputFormat = inputNode?.outputFormat(forBus: bus)
let outputFormat = AVAudioFormat(
commonFormat: .pcmFormatFloat32,
sampleRate: 16000, channels: 1,
interleaved: false)!
let converter = AVAudioConverter(from: inputFormat!, to: outputFormat)!
inputNode!.installTap(
onBus: bus,
bufferSize: 1024,
format: inputFormat
) {
(buffer: AVAudioPCMBuffer, when: AVAudioTime) in
var newBufferAvailable = true
let inputCallback: AVAudioConverterInputBlock = {
inNumPackets, outStatus in
if newBufferAvailable {
outStatus.pointee = .haveData
newBufferAvailable = false
return buffer
} else {
outStatus.pointee = .noDataNow
return nil
}
}
let convertedBuffer = AVAudioPCMBuffer(
pcmFormat: outputFormat,
frameCapacity:
AVAudioFrameCount(outputFormat.sampleRate)
* buffer.frameLength
/ AVAudioFrameCount(buffer.format.sampleRate))!
var error: NSError?
let _ = converter.convert(
to: convertedBuffer,
error: &error, withInputFrom: inputCallback)
// TODO(fangjun): Handle status != haveData
let array = convertedBuffer.array()
if !array.isEmpty {
self.voices.append(contentsOf: array)
}
}
}
public func toggleRecorder() async{
if status == .stop {
await startRecorder()
} else {
await stopRecorder()
}
}
private func startRecorder() async {
await MainActor.run {
self.language = ""
}
if !self.voices.isEmpty {
self.voices = []
}
do {
try self.audioEngine?.start()
status = .recording
print("started")
} catch let error as NSError {
print("Got an error starting audioEngine: \(error.domain), \(error)")
}
}
private func stopRecorder() async {
audioEngine?.stop()
print("stopped, and begin identify language")
await self.identify()
status = .stop
}
private func identify() async {
let result = self.languageIdentifier? .decode(samples: self.voices)
if let language = result?.lang {
await MainActor.run {
self.language = language
}
}
}
}