Dibujar la forma de onda de audio de grabación en iOS
Gráfico de forma de onda de tira
Gráfico de forma de onda lineal
Configuración de la sesión de audio
Antes de dibujar el gráfico de forma de onda, debe configurar AVAudioSession y crear una matriz. Guardar 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 el gráfico de forma de onda periódicamente.
SoundMeter y soundMeterCount se utilizan para guardar la matriz de medidores de volumen.
RecordTime se utiliza para registrar el tiempo de grabación y se puede utilizar para determinar si el tiempo de grabación cumple con los requisitos, etc.
///Grabadora
Grabadora var privada: ¡AVAudioRecorder! ///Configuración de la grabadora de video
Configuración de la grabadora de mensajes privados=[avsampleratekey:ns number(value:float(44100.0)), //Frecuencia de muestreo de sonido.
Avformatidkey: ns número (valor: int 32 (kaudioformatmpg 4 AAC)), //formato de codificación.
Avnumberofchannelskey: ns number (valor: 1), //Recopila pistas de audio.
Clave de calidad de audio de Avencode: número ns (valor: int 32 (calidad de audio. valor medio.raw))]//Calidad de sonido
///Temporizador de grabación
Temporizador var privado: ¿temporizador? ///Intervalo de actualización de forma de onda
Frecuencia de actualización de mensajes privados = 0,05
///Matriz de datos de sonido
Medidores de sonido var privados: [Float]! ///Capacidad de la matriz de datos de sonido
Mensaje privado soundMeterCount = 10
///Tiempo de grabación
Tiempo de grabación de var privado = 0,00
Configuración relacionada con la sesión de audio
Configurar AVAudioSession se utiliza para configurar avaudiosession, donde AVAudioSessionCategoryRecord significa que solo se graba esta sesión. Si se requiere reproducción, se puede configurar en avaudiesessioncategoryplayandrerecord o AvaudieSessionCategoryplayBlack. 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 silenciarla).
ConfigRecord se utiliza para configurar todo AVAudioRecoder, incluida la adquisición de permisos, la configuración de fuente de proxy, si se deben grabar tablas de volúmenes, etc.
DirectoryURL es la dirección donde se guarda el archivo de configuración.
configuración de función privadaAVAudioSession(){ let session = avaudiosession . instancia compartida()do { try session . set Category(avaudiosessioncategoryplayandrerecord, with: .defaultToSpeaker) } catch { print("Error en la configuración de la sesión")}
}
registro de configuración de función privada(){ avaudiosession instancia compartida().
requestRecordPermission {(permitir)
si! permitir {return
}
} let session = avaudiosession . instancia compartida()do { try session . configuración fallida ")} hacer { self . recorder = probar AVAudioRecorder(URL:self . directorio yurl()!, configuración:self . recorder settings)self . recorder . delegado = self
self . recorder . preparetorecord ()self . recorder . ismeteringenabled = true
} catch { print(error . descripción localizada)
} do { prueba avaudiosession(). setActive(true) } catch { print("Error en la actividad de la sesión")}
}
URL del directorio de funciones privadas()-& gt; { //Hacer algo...
Devolver la URL del archivo de sonido
}
Grabar datos de audio
Después de grabar, usamos El temporizador que acaba de configurar obtiene continuamente la potencia promedio y la guarda en una matriz.
El temporizador llama a UpdateMeters y los datos de volumen grabados en la grabadora se guardan continuamente en la matriz soundMeter.
AddSoundMeter se utiliza para agregar datos.
Contador de actualización de función privada(){
recorder.updateMeters()
Tiempo de grabación += frecuencia de actualización
añadir sonómetro(elemento :recorder potencia promedio(para canal:0))
}
función privada agregar sonómetro(elemento:Float){ si los sonómetros cuentan & lt;soundMeterCount {
.soundMeters.append(item)
} else { for (index, _)in sonómetros enumerados(){ if index <soundMeterCount - 1 {
SoundMeter Sounder[ index] = sounder[index + 1]
}
}//Insertar nuevos datos
soundMeters[soundMeterCount-1]= centro de notificación de elementos predeterminado. post(name: NSNotification. Name.init("updateMeters "), objeto: soundMeters)
}
}
Empiece a dibujar formas de onda
Ahora que tenemos todos los datos que necesitamos, podemos comenzar a dibujar el gráfico de forma de onda. En este momento nos situamos en el archivo MCVolumeView.swift.
En el paso anterior, enviamos una notificación llamada updateMeters para notificar a MCVolumeView que actualice el gráfico de forma de onda.
Anular init(frame:CG rect){ super . init(frame:frame)
backgroundColor = UIColor.clear
Content-mode =. ¿Repintar? // El modo de contenido se vuelve a dibujar porque es necesario volver a dibujar la tabla de volúmenes muchas veces.
centro de notificaciones. valor predeterminado. agregar observador(self, selector:# selector(vista de actualización(aviso:)), nombre: NSNotification. Name.init("updateMeters "), objeto: nil)
}
@ vista de actualización de función privada de objc(aviso:Notificación){
soundMeters = aviso.objeto como! [Flotante]
setNeedsDisplay()
}
Al llamar a setNeedsDisplay, se llamará al método drawRect, donde podemos dibujar formas de onda.
NoVoice y maxVolume se utilizan para garantizar el rango de visualización del sonido.
El gráfico de forma de onda se dibuja mediante CGContext y, por supuesto, también se puede dibujar mediante UIBezierPath.
Anular función draw(_ rect:CG rect){ if soundMeters! =cero& amp& ampsoundMeters.count & gt0 { let contexto = UIGraphicsGetCurrentContext()
¿Contexto? . setLineCap(.circle)
¿Contexto? . setLineJoin(.circle)
¿Contexto? . setStrokeColor(ui color . white . CG color)
Establecer noVoice = -46.0 //Este valor significa que todos los sonidos por debajo de -46.0 se consideran silenciosos.
Establezca maxVolume = 55.0 //Este valor representa el sonido máximo como 55.0.
//Dibujar volumen...
¿Contexto? . StrokePath()
}
}
Dibujo de un gráfico de forma de onda en columnas
Calcule la altura de cada columna según maxVolume y noVoice, y mueve el contexto Dibuja el punto donde se encuentra.
También cabe señalar que los puntos de coordenadas en CGContext están invertidos, por lo que se requiere el eje de coordenadas inverso para el cálculo.
Keith. bar:?
¿Contexto? . establecerAnchoDeLínea(3)? para (índice, elemento) en la tabla fonética. Enumeración(){ let bar height = max volume-(double(item)-no voice)//Calcule la altura del medidor de voz que debe mostrarse a través del medidor de voz actual.
¿Contexto? . mover(a:CGPoint(x: índice * 6 + 3, y: 40))
¿Contexto? . addLine(to: CGPoint(x: index * 6 + 3, y: Int(barHeight)))
}
Dibujo de un gráfico de forma de onda lineal
" La "altura" se calcula de la misma manera que una franja, pero cuando se dibuja una forma de onda de franja, la línea se dibuja primero y luego se mueve, mientras que cuando se dibuja una forma de onda de franja, la línea se mueve primero y luego se dibuja.
Keith. Línea:
¿Contexto? .
Establezca el ancho de línea (1,5) para (índice, elemento) en sonómetros. Enumeración(){ let position = volumen máximo-(double(item)-no voice)//Calcule la altura del segmento de línea correspondiente.
¿Contexto? . addLine(to:CG point(x:Double(index * 6+3), y: posición))
¿Contexto? . Move(to: CGPoint(x: Double(index * 6 + 3), y: position))
}
}
Mejorar aún más nuestra imagen de forma de onda .
En muchos casos, la grabación no solo necesita mostrar el gráfico de forma de onda, sino que también requiere que mostremos el tiempo y el progreso de la grabación actual, por lo que podemos agregar una barra de progreso de grabación al gráfico de forma de onda, así que giramos al archivo MCProgressView.swift.
Utiliza UIBezierPath para dibujar con CAShapeLayer.
MaskPath es la máscara de toda la ruta de progreso. Debido a que nuestro HUD de grabación no es un cuadrado normal, es necesario cortarlo con la ruta de progreso de la máscara.
ProgressPath es la ruta de progreso y el progreso se dibuja de izquierda a derecha.
La animación es la animación del dibujo de la ruta de progreso.
configuración de función privada animate(){ let mask path = UIBezierPath(rect redondeado:CG rect . init(x: 0, y: 0, ancho: frame.width, alto: frame.height), esquina radio:HUDCornerRadius)let capa de máscara = CAShapeLayer()
color de fondo de la máscara = color de interfaz de usuario claro
maskLayer.path = maskPath.cgPath
<. p>maskLayer.frame = límites//Ruta de progreso
/*
El centro de la ruta es el centro del HUD y el ancho es la altura del HUD, comenzando desde la izquierda Dibuja hacia la derecha.
*/
let ProgressPath = CGMutablePath()
ruta de progreso. mover(a:punto CG(x:0,y: frame.height / 2) ))
ruta de progreso. addline(a:punto CG(x: marco. ancho, y: marco. altura / 2))
progressLayer = CAShapeLayer()
progressLayer.frame = límites
capa de progreso color de relleno = uicolor.clear.cgcolor//Color de fondo de la capa.
color de trazo de capa de progreso = color de interfaz de usuario (rojo: 0,29, verde: 0,29, azul: 0,29, alfa: 0,90).
cgColor? //Color de dibujo de capa
capa de progreso. límite de línea = kCALineCapButt
ancho de línea de progreso = altura del hud
ruta de capa de progreso = ruta de progreso
. p>progressLayer.mask = maskLayer
animation = cabasic Animation(keyPath:" final del trazo ")
Animation.duration = 60 //Duración máxima de grabación
p>Animación. Función de sincronización = función de sincronización camedia (nombre: kcamediating funcional lineal) // viajando a velocidad constante.
modo de relleno de animación = kCAFillModeForwards
animación.fromValue = 0.0
animación.toValue = 1.0
animación.autoreverses = false
animation.repeatCount = 1
}
Etiqueta
Las anteriores son algunas de mis experiencias y opiniones al dibujar formas de onda de grabación. En la demostración, también agregué sombras y desenfoque gaussiano al HUD de grabación para darle más textura en la pantalla, así que lo omitiré. Aun así, creo que este HUD de grabación todavía tiene algunos defectos. Primero, el acoplamiento con VC es relativamente alto. En segundo lugar, el efecto de dibujar gráficos de formas de onda lineales no es razonable. Si hay una manera mejor, espero que puedas comunicarte conmigo.