2011-01-30 9 views
5
OSStatus MusicPlayerCallback ( 
         void *      inRefCon, 
         AudioUnitRenderActionFlags * ioActionFlags, 
         const AudioTimeStamp *   inTimeStamp, 
         UInt32      inBusNumber, 
         UInt32      inNumberFrames, 
         AudioBufferList *   ioData) { 


MusicPlaybackState *musicPlaybackState = (MusicPlaybackState*) inRefCon; 

double sampleinp; 

double A,omega,sn,cs,alpha,Bandwidth; 

double dbGain; 

double a0,a1,a2,b0,b1,b2; 

dbGain = 1.0; 

A=pow(10.0,dbGain/40.0); 

Bandwidth = 2.0; 

omega=2 * M_PI * 800.0/44100.0; 

sn=sin(omega); 

cs=cos(omega); 

alpha=sn*sinh(((M_LN2/2)*Bandwidth*omega)/sn); 


//Peak Filter Biquad 

b0 =1.0 + alpha * A; 

b1 = (-2.0 * cs); 

b2 = 1.0 - alpha * A; 

a0 = 1.0 + (alpha /A); 

a1 = -2.0 * cs; 

a2 = 1.0 - (alpha /A); 



double b0a0, b1a0, b2a0, a1a0, a2a0; 

double static x1; 

double static x2; 

double static y1; 

double static y2; 


b0a0=b0/a0; 

b1a0=b1/a0; 

b2a0=b2/a0; 

a1a0=a1/a0; 

a2a0=a2/a0; 


for (int i = 0 ; i < ioData->mNumberBuffers; i++){ 


    AudioBuffer buffer = ioData->mBuffers[i]; 
    AudioSampleType *outSample = buffer.mData; 

    for (int j = 0; j < inNumberFrames*2; j++){ 

    sampleinp = *musicPlaybackState->samplePtr++; 

    outSample[j] = b0a0 * sampleinp + 
    b1a0 * x1 + 
    b2a0 * x2 - 
    a1a0 * y1 - 
    a2a0 * y2; 


    x2=x1; 
    x1=sampleinp; 

    y2=y1; 
    y1=outSample[j]; 

    }} 





return noErr; 
} 

Having Clicks/pop problems. Alguien POR FAVOR AYUDE ... No sé lo que estoy haciendo mal. Esto está en Xcode usando C en Objective-C. Intenté hacer el Coeff Global y Static, pero no tuve suerte. El archivo de audio que está usando es .caf. Intenté .wav pero todavía no es bueno ...Peak Filter tiene clics y pops

Gracias, perdón por el grito general de ayuda. Soy nuevo en este sitio. Estoy tratando de agregar un filtro de Pico en mi aplicación, pero cada vez que uso un control deslizante o simplemente dejo la ganancia en 1 recibo pops y clics. Parece que todo está allí y funciona correctamente en cuanto a la celebración de las muestras anteriores, etc. También obtengo algún tipo de fase al cambiar la frecuencia o el ancho de banda. Estoy tan confundido de haber estado estudiando DSP durante algunos meses, creo que es algo con Objective-C y un error de usuario. Parece que se va cuando se cambia la muestra a un SInt32, pero el canal izquierdo desaparece al cambiar la frecuencia.

Dsp.h

typedef struct { 

    void* audioData; 

    UInt32 audioDataByteCount; 

    SInt16 *samplePtr; 

} MusicPlaybackState; 
+1

No me puedo imaginar por qué alguien vota para cerrar esto. – ocodo

+0

@Slomojo: No creo que la pregunta deba cerrarse, pero no está bien planteada tal como está, y puedo ver por qué podría obtener votos cercanos. @Cocell: es posible que desee mejorar la pregunta para evitar más votos cercanos: intente dar más detalles sobre el problema y lo que ha intentado, y conviértalo en una pregunta específica en lugar de un "clamor por ayuda" general. –

+1

@Paul R - Estoy de acuerdo en que la pregunta debe plantearse con mayor eficacia, pero el voto completamente silencioso para cerrar es inapropiado. Es 100% evidente que Cocell es un nuevo usuario de SO y simplemente quiere resolver un problema espinoso. No es posible que alguien con menos de 2k representantes vote por un cierre, por lo que es extremadamente decepcionante cuando esto sucede. Es arbitrario, inútil y francamente grosero, un comentario que solicita más información si es necesario es todo lo que se necesita aquí, no un "IRSE, NO SE PREGUNTA SU PREGUNTA", que es exactamente lo que transmite un voto cercano. – ocodo

Respuesta

4

Según la respuesta de hotpaw2, aquí está la trama de respuesta de su filtro:

from pylab import * 
import scipy.signal as signal 

def biquad_peak(omega, gain_db, bandwidth): 
    sn = sin(omega) 
    cs = cos(omega) 
    alpha = sn * sinh(log(2)/2 * bandwidth * omega/sn) 
    gain_sqrt = 10.0 ** (gain_db/40.0) 

    # feed-forward coefficients 
    b0 = 1.0 + alpha * gain_sqrt 
    b1 = -2.0 * cs 
    b2 = 1.0 - alpha * gain_sqrt 
    # feedback coefficients 
    a0 = 1.0 + (alpha/gain_sqrt) 
    a1 = -2.0 * cs 
    a2 = 1.0 - (alpha/gain_sqrt) 
    # normalize by a0 
    B = array([b0, b1, b2])/a0 
    A = array([a0, a1, a2])/a0 
    return B, A 

omega = 2 * pi * 800.0/44100.0 
gain_db = 1.0 
bandwidth = 2.0 

B, A = biquad_peak(omega, gain_db, bandwidth) 
w, H = signal.freqz(B, A) 
f = w/pi * 22050.0 
plot(f, abs(H), 'r') 
gain = 10.0 ** (gain_db/20.0) 
print "Gain:", gain 
plot(f, gain*ones(len(f)), 'b--'); grid() 

biquad peak filter response

La ganancia de pico se establece en 1,1220184543 (es decir, 1 dB). Se puede ver cómo el filtro hace que la mayor parte de la gama audible para tener una ganancia mayor que 1.

Edición 2: Si se trata de un ecualizador ajustable, entonces le toca al usuario para ajustar la ganancia que evita la distorsión. Además, dudo que el problema extremo que describes sea causado por una leve ganancia de 1 dB en una banda estrecha para una pista de audio típica. Creo que es porque tu audio tiene datos estéreo intercalados. Cada uno de estos canales debe filtrarse por separado. Me he tomado una grieta en la modificación de su bucle anidado para lograr esto:

a0 = 1.0 + alpha/A; 
a1 = -2.0 * cs/a0;  
a2 = (1.0 - alpha/A)/a0; 
b0 = (1.0 + alpha * A)/a0; 
b1 = -2.0 * cs/a0; 
b2 = (1.0 - alpha * A)/a0; 

double static x11, x12, x21, x22; 
double static y11, y12, y21, y22; 
double x0, y0; 

for (int i = 0; i < ioData->mNumberBuffers; i++) { 

    AudioBuffer buffer = ioData->mBuffers[i]; 
    AudioSampleType *outSample = buffer.mData; 

    for (int j = 0; j < inNumberFrames*2; j++) { 

     /* x0 is in the range of SInt16: -32768 to 32767 */ 

     x0 = *musicPlaybackState->samplePtr++; 

     y0 = b0 * x0 + 
      b1 * x11 + 
      b2 * x12 - 
      a1 * y11 - 
      a2 * y12; 

     outSample[j] = fmax(fmin(y0, 32767.0), -32768.0); 

     x12 = x11; 
     x11 = x0; 
     y12 = y11; 
     y11 = y0 
     j++;   

     x0 = *musicPlaybackState->samplePtr++; 

     y0 = b0 * x0 + 
       b1 * x21 + 
       b2 * x22 - 
       a1 * y21 - 
       a2 * y22; 

     outSample[j] = fmax(fmin(y0, 32767.0), -32768.0); 

     x22 = x21; 
     x21 = x0;   
     y22 = y21; 
     y21 = y0; 
    } 
} 
+0

Tenga en cuenta que incluso si garantiza que la ganancia es <= 1.0 en todas las frecuencias, aún puede obtener picos de salida que son más grandes que sus picos de entrada. –

+0

Entonces, ¿cómo impulsaría una frecuencia de 10000 kHz, por ejemplo, alcanzando un máximo de 12dB sin clics y saltos si dice que tiene que ser inferior a 1dB? – Cocell

+0

@eryksun No solo usar eso para dar un ejemplo. Sin embargo, me estaba preguntando qué pasaría si quisiera aumentar 12dB @ una cierta frecuencia, ¿eso causaría el mismo problema? Aprecio tu ayuda. – Cocell

1

parece que estás usando la receta de libro de cocina biquad RBJ.

Un filtro de pico Biquad con una ganancia promedio de 1.0 tiene una ganancia superior a 1.0 en ciertas frecuencias. Si no quiere clipping, debe usar una ganancia de menos de 1.0, o usar un atenuador o AGC en la entrada para que el aumento de frecuencia de pico nunca llegue a un nivel que recorte.

Es un problema sin un AGC, ya que algunos clientes esperan un filtro pico o intensificador de graves para hacer las cosas más ruidosas, y hay que atenuar el nivel promedio para reducir completamente la saturación en la frecuencia de pico.

+0

Ok, intentaré agregar un AGC. ¿Entonces básicamente estás diciendo que la razón por la que está emitiendo los sonidos es porque la ganancia a diferentes frecuencias es más de 1.0 en Magnitud, no dB, como mencionó eryksun? – Cocell

2

una cuestión importante es que el estado del filtro debe ser almacenado dentro del estado refcon (por lo menos, que es el mejor lugar obvio en los casos típicos).

Sin eso, su filtro se reconstruye e inicializa en cada invocación de la devolución de llamada, lo que significa que el estado no se conservará correctamente y tendrá problemas técnicos en los límites de cada devolución de llamada que no sea la primera.

1

Además de las excelentes respuestas que ya se han dado, voy a añadir una palabra general de consejos - usted debe factorizar y desacople su rutina de filtro de la devolución de llamada (es decir, que sea una función separada sin dependencias en su código iOS). De esta forma, puede ponerlo en un arnés de prueba y depurarlo más fácilmente (en un contexto no en tiempo real), separado de cualquier problema específico de iOS que pueda complicar las cosas.

+0

Gracias, lo tengo así en mi segunda versión y el mismo problema. Simplemente lo puse todo junto para que sea más fácil ayudar. – Cocell

+0

@Cocell: OK: cuando tenga la rutina implementada por separado, escriba un arnés de prueba que pueda generar una señal de entrada, p.onda sinusoidal a la amplitud y frecuencia dadas, y luego volcar la salida en un formato que se puede trazar, hace que la depuración, etc., sea mucho más fácil. –