2012-08-23 11 views
6

Intento mezclar 2 transmisiones de audio PCM lineales de 16 bits y parece que no puedo superar los problemas de ruido. Creo que provienen del desbordamiento cuando se mezclan muestras.Mezcla de flujos de PCM lineales de 16 bits y evitar el recorte/desbordamiento

He siguiente función ...

short int mix_sample(short int sample1, short int sample2) 
{ 
    return #mixing_algorithm#; 
} 

... y aquí es lo que he tratado como # # mixing_algorithm

sample1/2 + sample2/2 
2*(sample1 + sample2) - 2*(sample1*sample2) - 65535 
(sample1 + sample2) - sample1*sample2 
(sample1 + sample2) - sample1*sample2 - 65535 
(sample1 + sample2) - ((sample1*sample2) >> 0x10) // same as divide by 65535 

Algunos de ellos han producido mejores resultados que otros, pero incluso el el mejor resultado contenía bastante ruido.

¿Alguna idea de cómo resolverlo?

+0

puede escribir el algoritmo completo, no puedo ver ninguna asignación !! – perilbrain

+0

Cuando divide la muestra 1 y la muestra 2 por 2, obtiene un rango de error de 1. –

Respuesta

7

aquí es una aplicación descriptiva:

short int mix_sample(short int sample1, short int sample2) { 
    const int32_t result(static_cast<int32_t>(sample1) + static_cast<int32_t>(sample2)); 
    typedef std::numeric_limits<short int> Range; 
    if (Range::max() < result) 
     return Range::max(); 
    else if (Range::min() > result) 
     return Range::min(); 
    else 
     return result; 
} 

a mezclar, es simplemente sumar y clip!

para evitar el recorte de artefactos, querrá usar saturación o un limitador. idealmente, tendrá un pequeño buffer int32_t con una pequeña cantidad de anticipación. esto introducirá la latencia.

más común que limitar en todas partes, es dejar unos cuantos bits de 'headroom' en su señal.

+0

Esta solución funcionó bien. ¡Gracias! – Ragnar

+0

@Ragnar genial, de nada :) – justin

+1

La única forma "correcta" de evitar el recorte es dividir por dos. Aquí hay un código ilustrativo en la sección "Distorsión y Ruido": http://blog.bjornroche.com/2013/05/the-abcs-of-pcm-uncompressed-digital.html –

0

Creo que deberían ser funciones que mapean [MIN_SHORT, MAX_SHORT] -> [MIN_SHORT, MAX_SHORT] y claramente no son (además del primero), por lo que se producen desbordamientos.

Si la proposición de desenrollado no funcionará también puede probar:

((long int)(sample1) + sample2)/2 
+0

Al agregar las señales es correcto; con simple * normalización * para mantener el rango, una señal afectará a la otra indeseablemente. Por ejemplo, si 'sample1' es siempre cero (silencioso), querrá * solo *' sample2', pero obtendrá 'sample2/2', es decir, la salida será más silenciosa. – Clifford

+0

Sí, tienes toda la razón. Pero resuelve el problema de desbordamiento y recorte. La mejor solución en mi humilde opinión sería escalar las señales en función de su valor, como 'w (s1, s2) * s1 + (1-w (s1, s2)) * s2' donde' w (s1, s2) 'es alguna función donde 'w (s1,0) = 1',' w (0, s2) = 0' y '0

-2

Dado que usted está en el dominio del tiempo, la información de frecuencia está en la diferencia entre muestras sucesivas, cuando divide por dos, daña esa información. Es por eso que agregar y recortar funciona mejor. El recorte agregará, por supuesto, un ruido de muy alta frecuencia que probablemente se filtre.

+0

Espero que el ruido que escucha el OP sea causado por el ajuste de valores, en lugar de algo tan sutil como un solo bit de resolución perdida – Will

9

La mejor solución que he encontrado es given by Viktor Toth. Se ofrece una solución para los 8 bits PCM sin firmar, y el cambio que para 16 bits con signo PCM, produce esto:

int a = 111; // first sample (-32768..32767) 
int b = 222; // second sample 
int m; // mixed result will go here 

// Make both samples unsigned (0..65535) 
a += 32768; 
b += 32768; 

// Pick the equation 
if ((a < 32768) || (b < 32768)) { 
    // Viktor's first equation when both sources are "quiet" 
    // (i.e. less than middle of the dynamic range) 
    m = a * b/32768; 
} else { 
    // Viktor's second equation when one or both sources are loud 
    m = 2 * (a + b) - (a * b)/32768 - 65536; 
} 

// Output is unsigned (0..65536) so convert back to signed (-32768..32767) 
if (m == 65536) m = 65535; 
m -= 32768; 

Utilizando este algoritmo significa que casi no hay necesidad de recortar la salida, ya que es sólo un valor corto de estar dentro del alcance. A diferencia del promedio directo, el volumen de una fuente no se reduce incluso cuando la otra fuente está en silencio.

+0

¿Qué quiere decir con "silencioso"? - eso normalmente sería malo * baja magnitud * (* cerca de * la mitad), pero aquí parece que significa * negativo * (debajo del medio), mientras que la ecuación "fuerte" se ejecuta cuando * uno o ambos son positivos * (antes de cambiar, es decir, agregar una polarización de CC)). Además de eso * el volumen * es una percepción de la * señal *, no una muestra individual - un sonido "fuerte" tendrá muestras en todo el rango. – Clifford

+0

@Clifford: El centro está en el medio del rango disponible, por lo que si los valores están entre 0 y 65535, entonces el centro es 32767. Se explica mejor en el enlace a la página de Viktor Toth. – Malvineous

+0

Me doy cuenta de que, mi pregunta era retórica, los términos "silencioso" y "alto" son imprecisos y engañosos en este contexto. – Clifford

1

Esto es lo que hice en mi reciente proyecto de sintetizador.

int* unfiltered = (int *)malloc(lengthOfLongPcmInShorts*4); 
int i; 
for(i = 0; i < lengthOfShortPcmInShorts; i++){ 
    unfiltered[i] = shortPcm[i] + longPcm[i]; 
} 
for(; i < lengthOfLongPcmInShorts; i++){ 
    unfiltered[i] = longPcm[i]; 
} 

int max = 0; 
for(int i = 0; i < lengthOfLongPcmInShorts; i++){ 
    int val = unfiltered[i]; 
    if(abs(val) > max) 
     max = val; 
} 

short int *newPcm = (short int *)malloc(lengthOfLongPcmInShorts*2); 
for(int i = 0; i < lengthOfLongPcmInShorts; i++){ 
    newPcm[i] = (unfilted[i]/max) * MAX_SHRT; 
} 

Agregué todos los datos de PCM en una matriz de enteros, de modo que obtuve todos los datos sin filtrar.

Después de hacer eso busqué el valor máximo absoluto en la matriz de enteros.

Finalmente, tomé la matriz de enteros y la puse en una matriz int corta tomando cada elemento dividiendo por ese valor máximo y luego multiplicando por el valor int máximo corto.

De esta forma se obtiene la cantidad mínima de "altura libre" necesaria para ajustarse a los datos.

Es posible que pueda hacer algunas estadísticas sobre la matriz de enteros e integrar algunos clipping, pero para lo que necesitaba la cantidad mínima de margen era lo suficientemente buena para mí.

Cuestiones relacionadas