2011-01-31 29 views
19

Estoy escribiendo un editor de forma de onda de audio en Cocoa con una amplia gama de opciones de zoom. En su parte más ancha, muestra una forma de onda para una canción completa (~ 10 millones de muestras a la vista). En su parte más estrecha, muestra una representación precisa de píxeles de la onda de sonido (~ 1 000 muestras en una vista). Quiero poder hacer una transición suave entre estos niveles de zoom. Algunos editores comerciales como Ableton Live parecen hacer esto de una manera muy económica.Método eficiente para trazar una línea con millones de puntos

Mi implementación actual satisface mi rango de zoom deseado, pero es ineficaz y entrecortado. El diseño está inspirado en gran medida por este excelente artículo en la elaboración de formas de onda con cuarzo:

http://supermegaultragroovy.com/blog/2009/10/06/drawing-waveforms/

puedo crear múltiples de CGMutablePathRef para el archivo de audio en varios niveles de reducción. Cuando estoy zoom todo el camino, uso la ruta que se ha reducido a un punto por x-mil muestras. Cuando estoy enfocando todo el camino hacia adentro, uso esa ruta que contiene un punto para cada muestra. Escalo un camino horizontalmente cuando estoy entre los niveles de reducción. Esto lo hace funcional, pero sigue siendo bastante caro y aparecen artefactos cuando se realiza la transición entre los niveles de reducción.

Un pensamiento sobre cómo puedo hacer esto menos costoso es eliminar el anti-aliasing. La forma de onda en mi editor es anti-alias mientras que la de Ableton no lo está (vea la comparación a continuación). enter image description here enter image description here

no veo una manera de desactivar el anti-aliasing para CGMutablePathRef de. ¿Hay una alternativa no anti-aliased a CGMutablePathRef en el mundo de Cocoa? Si no, ¿alguien sabe de algunas clases de OpenGL o código de muestra que podría ponerme en curso para dibujar mi gran línea de manera más eficiente?

Actualización 21/01/2014: Ahora hay una gran biblioteca que hace exactamente lo que estaba buscando: https://github.com/syedhali/EZAudio

Respuesta

6

yo uso CGContextMoveToPoint + + CGContextAddLineToPoint CGContextStrokePath en mi aplicación. un punto por cada punto en pantalla para dibujar utilizando un buffer de respaldo precalculado para la vista general. el buffer contiene los puntos exactos para dibujar, y usa una representación interpolada de la señal (basada en el zoom/escala). aunque podría ser más rápido y verse mejor si se procesara en un buffer de imagen, nunca tuve una queja. puede calc y renderizar todo esto desde un hilo secundario, si lo configura correctamente.

anti-aliasing pertenece al contexto de gráficos.

CGFloat (la entrada nativa de CGPaths) es excesiva para una visión general, como una representación intermedia, y para calcular la visión general de la forma de onda. 16 bits deberían ser adecuados. por supuesto, tendrás que convertir a CGFloat cuando pases a llamadas CG.

necesita un perfil para saber dónde pasa su tiempo: concéntrese en las piezas que requieren más tiempo. Además, asegúrate de que solo dibujas lo que debes, cuando debes y evita las superposiciones/animaciones donde sea posible. si necesita superposiciones, es mejor renderizarlas en una imagen/buffer y actualizarlas según sea necesario. a veces ayuda a dividir la pantalla en múltiples superficies de dibujo cuando la superficie es grande.

semi-OT: el uso de ableton s + h valores esto puede ser un poco más rápido, pero ... lo prefiero como una opción. si su implementación utiliza interpolación lineal (que puede, en función de su apariencia), considere un enfoque más intuitivo. la interpolación lineal es un truco, y realmente no es lo que el usuario esperaría si está desarrollando una aplicación profesional.

+0

¡Gracias por la respuesta detallada! Parece que has estado aquí también. De hecho, estoy dibujando la forma de onda con más frecuencia de la que podría necesitar. Consideraré sustituir un re-draw completo con una superposición. Con respecto a Ableton usando los valores de s + h, ¿cuáles son esos? Está en lo cierto al suponer que mi implementación usa interpolación lineal. Parece que las líneas cuadradas de Ableton podrían ser más eficientes para dibujar, pero no estoy seguro de cómo voy a hacer eso. – tassock

+0

@tassock de nada. por 's + h', quise decir los valores 'sample and hold' de la señal. esto solo dibuja los pasos de forma de onda exactamente como están representados en el dominio de tiempo. es mejor (imo) interpolar y construir la representación de la señal. s + h está bien, pero debería ser una opción, con una representación interpolada como el valor predeterminado. cuando digo interpolación, me refiero a un enfoque que es más representativo de una señal analógica que s + h o interpolación lineal. para eso, es probable que requiera que equilibre el rendimiento con precisión. un sinc sería bueno, (cont) – justin

+0

pero es probable que salga con una spline de orden superior (como un ejemplo). interpolar/reconstruir la forma de onda correctamente puede agregar mucha CPU a su implementación actual. – justin

2

En relación con la cuestión particular de anti-aliasing. En Quartz, el anti-aliasing se aplica al contexto en el momento del dibujo. El CGPathRef es agnóstico para el contexto del dibujo. Por lo tanto, el mismo CGPathRef se puede representar en un contexto antialias o en un contexto no antialias. Por ejemplo, para desactivar el antialiasing durante las animaciones:

CGContextRef context = UIGraphicsGetCurrentContext(); 
GMutablePathRef fill_path = CGPathCreateMutable(); 
// Fill the path with the wave 
... 

CGContextAddPath(context, fill_path); 
if ([self animating]) 
    CGContextSetAllowsAntialiasing(context, NO); 
else 
    CGContextSetAllowsAntialiasing(context, YES); 
// Do the drawing 
CGContextDrawPath(context, kCGPathStroke); 
+0

Ah, gracias por señalar la configuración de suavizado de contexto. Desafortunadamente, no parece haber conducido a un aumento significativo en el rendimiento. Aparentemente tengo demasiados procesos ineficientes en mi implementación actual. – tassock

Cuestiones relacionadas