Mi viaje con SoundAnalysis

Dec 09 2022
¡No soy un maestro, pero estoy dispuesto a aprender sobre análisis de sonido! En este Macro Desafío, mi equipo decide hacer Komka, una aplicación para ayudar a los Niños con Síndrome de Down a mejorar su habilidad de comunicación expresiva. Una de las características que tiene Komka es Sound Practice.

¡No soy un maestro, pero estoy dispuesto a aprender sobre análisis de sonido!

En este Macro Desafío, mi equipo decide hacer Komka, una aplicación para ayudar a los Niños con Síndrome de Down a mejorar su habilidad de comunicación expresiva. Una de las características que tiene Komka es Sound Practice. Esta característica tiene una barra de progreso circular que aumentará según la similitud de cómo el niño pronuncia la palabra.

Función de práctica de sonido

¡Intentaré explicar cómo mi equipo creó esta característica!

En primer lugar, mi equipo entrena el modelo con createML. Una vez que tenemos el modelo, comenzamos a hacer la configuración de nuestra característica.

Lo primero que hago es crear una clase para el administrador de transmisión de audio que importa AVFoundation . AVFoundation es un marco en iOS que le permite inspeccionar, reproducir, capturar y procesar medios audiovisuales en plataformas Apple.

Estas son variables que necesitamos hacer.

private var audioEngine: AVAudioEngine?
private var soundAnalyzer: SNAudioStreamAnalyzer?
private var soundClassifierRequest: SNClassifySoundRequest?

También tenemos que hacer una función para detener la sesión de audio cuando ya no queremos detectar los sonidos. El uso de una sesión de audio es comunicar al sistema operativo la naturaleza general del audio de su aplicación sin detallar el comportamiento específico o las interacciones requeridas con el hardware de audio.

func stopAudioSession() {
    let audioSession = AVAudioSession.sharedInstance()
    try? audioSession.setActive(false)
}

También necesitamos hacer otra función para detener la grabación de audio en vivo que está conectada al final del audio. Por lo tanto, debemos asegurarnos de eliminar el nodo del motor de audio.

func stopLiveRecord(){
    guard let audioEngine = audioEngine else {
        print("ERROR: AudioEngine Unavailable")
        return
    }
    audioEngine.inputNode.removeTap(onBus: 0)
    stopAudioSession()
}

La siguiente función es la función para preparar el clasificador de sonido usando el modelo que se ha hecho antes.

private func prepareSoundClassifier(){
    let config = MLModelConfiguration()
    let soundClassifier = try? SoundPracticeModel_Rev(configuration: config)
    
    guard let soundClassifier = soundClassifier else{
        print("ERROR: Model doesn't Exist")
        return
    }
    soundClassifierRequest = try? SNClassifySoundRequest(mlModel: soundClassifier.model)
}

Por último, para el administrador de transmisión de audio. Haremos la funcion para iniciar la grabacion en vivo

func startLiveRecord(){
    stopLiveRecord()
    do {
        let audioSession = AVAudioSession.sharedInstance()
        try audioSession.setCategory(.record, options: .mixWithOthers)
        try audioSession.setActive(true)
    } catch {
        stopAudioSession()
        print("ERROR: Stop Live record")
    }
    do{
        let newAudioEngine = AVAudioEngine()
        let busIndex = AVAudioNodeBus(0)
        let audioFormat = newAudioEngine.inputNode.inputFormat(forBus: busIndex)
        soundAnalyzer = SNAudioStreamAnalyzer(format: audioFormat)
        
        newAudioEngine.inputNode.removeTap(onBus: busIndex)
        newAudioEngine.inputNode.installTap(onBus: busIndex, bufferSize: 1024, format: audioFormat) {
            (buffer, time) in
            DispatchQueue.main.async {
                self.soundAnalyzer?.analyze(buffer, atAudioFramePosition: time.sampleTime)
            }
        }
        try newAudioEngine.start()
        prepareSoundClassifier()
    }
    catch {
       print("ERROR: \(error)")
    }
}

Para verificar el nivel de confianza de su modelo, puede crear otra clase que use SNResultObserving .

class SoundAnalyzer: NSObject, ObservableObject, SNResultsObserving {    
    var confidence: Double?
    var confidencePublisher = PublishSubject<Double>()
    
    var currentWord: String = ""
        
    func request(_ request: SNRequest, didProduce result: SNResult) {
        guard let result = result as? SNClassificationResult else{
            return
        }
        
        guard let highestResult = result.classifications.first else{
            return
        }
        
        DispatchQueue.main.async {
            if(self.currentWord == highestResult.identifier){
                self.confidence = highestResult.confidence
                self.confidencePublisher.onNext(self.confidence ?? 0)
            }
        }
    }
}

¡Eso es todo lo que hice para crear la función Práctica de sonido que usaba el analizador de sonido! Después de todo, este es solo el paso básico para dominar el viaje de Sound Analyzer.

Gracias por su tiempo para leer este artículo, ¡espero que lo ayude en su viaje para dominar Sound Analyzer!