Red de conocimiento informático - Material del sitio web - Dibujar formas de onda de audio grabadas en iOS

Dibujar formas de onda de audio grabadas en iOS

Efectos

Forma de onda de tira

Forma de onda de línea

Configurar AvAudioSession

Antes de dibujar una forma de onda, necesita configurar una AVAudioSession y crear una matriz para almacenar datos de volumen.

Propiedades relacionadas

recorderSetting se utiliza para configurar la calidad de grabación y otros datos relacionados.

el temporizador y la frecuencia de actualización se utilizan para actualizar las formas de onda con regularidad.

soundMeter y soundMeterCount se utilizan para guardar grupos de recuento de volumen.

recordTime se utiliza para registrar el tiempo de grabación y se puede utilizar para determinar si el tiempo de grabación alcanza el nivel requerido y otros requisitos adicionales.

/// Grabador

grabador var privado: AVAudioRecorder! /// Configuración de la grabadora

private let recorderSetting = [AVSampleRateKey: NSNumber(value.Float(44100.0)), // frecuencia de muestreo de sonido

AVFormatIDKey: NSNumber(value: Int32(kAudioFormatMPEG4AAC )), // Formato de codificación

AVNumberOfChannelsKey: NSNumber(valor: 1), // Capturar pista de audio

AVencoderAudioQualityKey: NSNumber(valor: Int32(AVAudioQuality.medium.rawValue)] // Calidad de sonido

/// Temporizador de grabación

temporizador var privado: Temporizador /// Intervalo de actualización de forma de onda

privado let updateFequency = 0,05

/// Matriz de datos de sonido

private var soundMeters: [Float]! /// capacidad de la matriz de datos de sonido

private let soundMeterCount = 10

/// recordTime

private var recordTime = 0.00

Configuración relacionada con AvAudioSession

configAVAudioSession se usa para configurar AVAudioSession, donde AVAudioSessionCategoryRecord significa usar solo esta sesión para grabar operación, y la operación de reproducción se puede configurar en AVAudioSessionCategoryPlayAndRecord o AVAudioSessionCategoryPlayBlack. La diferencia entre los dos es que uno puede grabar y reproducir, y el otro puede reproducir en segundo plano (es decir, la voz aún se puede reproducir después de silenciar)

Se utiliza configRecord. Configure todo AVAudioRecoder, incluida la obtención de permisos, la configuración de la fuente del proxy y si se debe registrar el medidor de volumen.

El directorio URL se utiliza para guardar el archivo de configuración.

función privada configAVAudioSession() { let session = AVAudioSession.sharedInstance() do { try session.setCategory( AVAudioSessionCategoryPlayAndRecord, with: .defaultToSpeaker) } catch { print("error de configuración de sesión") }

}

función privada configRecord() { AVAudioSession.sharedInstance().requestRecordPermission { (permitido) en

si !permitido { retorno

}

} let session = AVAudioSession.sharedInstance() do { try session.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .defaultToSpeaker) } catch { print("falló la configuración de la sesión") } do { self.recorder = try AVAudioRecorder (url: self.directoryURL()!, configuración: self.recorderSetting) self.recorder.delegate = self

self.recorder.prepareToRecord() self.recorder.isMeteringEnabled = true

} catch { print(error.localizedDescription)

} do { try AVAudioSession.sharedInstance().setActive(true) } catch { print(" sesión activa fallida") }

}

diversión privada divertida.

función privada directorioURL() -gt; URL?{ // hacer algo...

devolver URLArchivoSonido

}

Grabar datos de audio

Después de que comience la grabación, usaremos el temporizador recién configurado para obtener continuamente la potencia promedio y guardarla en una matriz.

El temporizador llama a UpdateMeters(updateMeters) para guardar continuamente los datos de volumen grabados en la grabadora en la matriz del sonómetro.

addSoundMeter realiza el trabajo de agregar datos.

función privada updateMeters() {

recorder.updateMeters()

recordTime = updateFequency

addSoundMeter(elemento: recorder .averagePower( forChannel: 0))

}

función privada addSoundMeter(elemento: Float) { if soundMeters.count lt; soundMeterCount {

soundMeters.append(elemento)

} else { for (index, _) in soundMeters.enumeated() { if index lt; soundMeterCount - 1 {

soundMeters[índice] = soundMeters[índice 1]

}

}

}//Insertar nuevos datos

soundMeters[soundMeterCount - 1] = elemento NotificationCenter.default.post(name. NSNotification.Name.init("updateMeters"), objeto: soundMeters)

}

}

}

Comience a dibujar la forma de onda

Ahora que tenemos todos los datos que necesitamos, podemos empezar a dibujar la forma de onda. En este punto, vayamos al archivo MCVolumeView.swift. En el paso anterior, enviamos una notificación llamada updateMeters para notificar a MCVolumeView que actualice la forma de onda.

anular init(frame: CGRect) { super.init(frame: frame)

backgroundColor = UIColor.clear

contentMode = .redraw?

contentMode = .redraw? porque necesita volver a dibujar el medidor de volumen varias veces

NotificationCenter.default.addObserver(self, selector: #name: NSNotification.Name. init("updateMeters"), objeto: nulo)

}

@obotifyCenter.default.addObserver(self, selector: updateView(aviso:)), nombre: NSNotification.Name.

@ objc función privada updateView(aviso: Notificación) {

soundMeters = aviso.objeto como! [Float]

setNeedsDisplay()

}

Una vez que se llama a setNeedsDisplay, se llama al método drawRect y podemos dibujar la forma de onda aquí.

noVoice y maxVolume se utilizan para garantizar que el sonido se muestre dentro de un rango determinado.

La forma de onda se dibuja usando CGContext y, por supuesto, también se puede dibujar usando UIBezierPath.

anular func draw(_ rect: CGRect) { if soundMeters ! = nil amp; soundMeters.count gt; 0 { let contexto = UIGraphicsGetCurrentContext()

contexto?.setLineCap(.round)

contexto?.setLineJoin(.round)

context?.setStrokeColor(UIColor.white.cgColor)

context?cgColor)

let noVoice = -46.0 // Este valor representa un valor inferior a -46.0 Cualquiera se considera que el contenido no tiene sonido

let maxVolume = 55.0 // Este valor representa un volumen máximo de 55.0

// Dibuja el volumen...

context ?.strokePath()

}

}

Dibujo de forma de onda de columna

Calcula la altura de cada columna según maxVolume y noVoice y muévalo al contexto para dibujarlo

Otro problema a tener en cuenta es que los puntos de coordenadas en CGContext están invertidos, por lo que los ejes de coordenadas deben invertirse para el cálculo.

case .bar: ?

context?.setLineWidth(3) ? for (índice, elemento) in soundMeters.enumeated() { let barHeight = maxVolume - (Double(item) - noVoice) // Calcula la altura de la mesa de sonido que debe mostrar la mesa de sonido actual

context?.move( to: CGPoint(x: index * 6 3, y: 40))

contexto?.addLine(to: CGPoint(x: index * 6 3, y. Int(barHeight)))

contexto?Int(barHeight)))

}

Dibujar un gráfico de líneas

Los gráficos de líneas y de barras utilizan el mismo método para calcular la "altura", pero en un gráfico de barras, la línea se dibuja primero y luego se mueve ; en un gráfico de líneas, primero mueva la polilínea y luego dibuje la polilínea.

case .line:

contexto?.setLineWidth(1.5) for (índice, elemento) in soundMeters.enumeated() { let position = maxVolume - (Double(item) - noVoice ) // Calcula la altura del segmento de línea correspondiente

context?.addLine(to: CGPoint(x: double(index * 6 3), y: position))

context ?.move (to: CGPoint(x: Double(index * 6 3), y: position))

}

}

Mejorar aún más nuestra forma de onda

p>

En muchos casos, la grabación necesita mostrar no solo la forma de onda, sino también el tiempo y el progreso de la grabación actual, por lo que podemos agregar una barra de progreso de grabación en la forma de onda. Podemos hacer esto usando el archivo MCProgressView.swift.

Dibuja usando UIBezierPath y CAShapeLayer.

maskPath se usa como máscara para toda la ruta de progreso. Debido a que nuestro HUD de grabación no es cuadrado, necesitamos usar la ruta de progreso de la máscara para recortar.

ProgressPath es la ruta de progreso y el progreso se dibuja de izquierda a derecha.

la animación es la animación que dibuja la ruta de progreso.

función privada configAnimate() { let maskPath = UIBezierPath(roundedRect: CGRect.init(x: 0, y: 0, ancho: frame.width, alto: frame.height), cornerRadius: HUDCornerRadius) let MaskLayer = CAShapeLayer()

MaskLayer.BackgroundColor = UIColor.clear.cgColor

MaskLayer.frame = límites

// ProgressPath

/*

El centro del camino es el centro del HUD, el ancho es la altura del HUD, dibujado de izquierda a derecha

*/

let ProgressPath = CGMutablePath()

ProgressPath.move(a: CGPoint(x: 0, y: frame.height/2))

ProgressPath.addLine(a: CGPoint( x. frame.width, y : frame.height / 2))

ProgressLayer = CAShapeLayer()

ProgressLayer.frame = límites

ProgressLayer.fillColor = UIColor.clear.cgColor // Color de fondo de la capa

ProgressLayer.strokeColor = UIColor(rojo: 0,29, verde: 0,29, azul: 0,29, alfa: 0,90).cgColor?//Color de dibujo de la capa

ProgressLayer.frame = CAShapeLayer()

ProgressLayer.frame = límites

ProgressLayer.fillColor = UIColor.clear.cgColor p>

ProgressLayer? .lineCap = kCALineCapButt

ProgressLayer.lineCapButt = kCALineCapButt

ProgressLayer.fillColor = UIColor.clear.cgColor?timingFunction = CAMediaTimingFunction(nombre: kCAMediaTimingFunctionLinear) // Incluso hacia adelante

animación.fillMode = kCAFillModeForwards

animación.fromValue = 0.0

animación.toValue = 1.0

animación.autoreverses = false

animación.repeatCount = 1