sonidos sonido puros predeterminados musica graficar emitir creacion con algorithm audio

algorithm - puros - sonidos predeterminados matlab



Algoritmo para mezclar el sonido (19)

convierta las muestras a valores de coma flotante que van desde -1.0 a +1.0, luego:

out = (s1 + s2) - (s1 * s2);

Introducirá una gran distorsión cuando | s1 + s2 | aproximación 1.0 (al menos cuando lo intenté al mezclar ondas sinusoidales simples). Leí esta recomendación en varios lugares, pero en mi humilde opinión, es un enfoque inútil.

Lo que ocurre físicamente cuando las ondas se "mezclan" es que sus amplificadores se agregan, al igual que muchos de los carteles aquí sugeridos. Ya sea

  • clip (distorsiona el resultado también) o
  • Resuma sus valores de 16 bits en un número de 32 bits, y luego divida por el número de sus fuentes (eso es lo que sugeriría, ya que es la única forma que conozco de evitar las distorsiones)

Tengo dos flujos de sonido en bruto que necesito agregar juntos. A los fines de esta pregunta, podemos suponer que tienen la misma tasa de bits y la misma profundidad de bits (por ejemplo, muestra de 16 bits, frecuencia de muestreo de 44.1khz).

Obviamente, si los agrego juntos, desbordaré y desbordaré mi espacio de 16 bits. Si los agrego juntos y los divido entre dos, el volumen de cada uno se reduce a la mitad, lo cual no es correcto en cuanto a sonido: si dos personas hablan en una habitación, sus voces no se silencian a la mitad, y un micrófono puede elegirlas ambos sin tocar el limitador.

  • Entonces, ¿cuál es el método correcto para agregar estos sonidos en mi mezclador de software?
  • ¿Estoy equivocado y el método correcto es bajar el volumen de cada uno a la mitad?
  • ¿Debo agregar un compresor / limitador o alguna otra etapa de procesamiento para obtener el volumen y el efecto de mezcla que estoy intentando?

-Adán


"Más tranquilo a la mitad" no es del todo correcto. Debido a la respuesta logarítmica de la oreja, dividir las muestras por la mitad hará que sea 6-db más silencioso, ciertamente notable, pero no desastroso.

Es posible que desee comprometerse multiplicando por 0,75. Eso lo hará 3 dB más silencioso, pero reducirá la posibilidad de desbordamiento y también disminuirá la distorsión cuando ocurra.


Como su perfil dice que trabaja en sistemas integrados, asumiré que las operaciones de punto flotante no siempre son una opción.

> So what''s the correct method to add these sounds together in my software mixer?

Como habrás adivinado, agregar y recortar es la forma correcta de hacerlo si no quieres perder volumen en las fuentes. Con muestras que son int16_t , necesita que la suma sea int32_t , luego limite y convierta nuevamente a int16_t .

> Am I wrong and the correct method is to lower the volume of each by half?

Sí. Reducir a la mitad el volumen es algo subjetivo, pero lo que se puede ver aquí y allá es que la reducción del volumen (volumen) es una disminución de alrededor de 10 dB (dividiendo la potencia por 10, o los valores de muestra por 3.16). Pero quiere decir, obviamente, reducir los valores de muestra a la mitad. Esto es una disminución de 6 dB, una reducción notable, pero no tanto como la mitad del volumen (la tabla de volumen es muy útil).

Con esta reducción de 6 dB, evitará todos los clipping. Pero, ¿qué sucede cuando quieres más canales de entrada? Para cuatro canales, deberá dividir los valores de entrada entre 4, que disminuyen en 12 dB, disminuyendo así la mitad del volumen para cada canal.

> Do I need to add a compressor/limiter or some other processing stage to get the volume and mixing effect I''m trying for?

Desea mezclar, no cortar, y no perder volumen en las señales de entrada. Esto no es posible, no sin algún tipo de distorsión.

Como sugiere Mark Ransom, una solución para evitar el recorte sin perder hasta 6 dB por canal es golpear en algún lugar entre "agregar y recortar" y "promediar".

Eso es para dos fuentes: agregar, dividir por algún lugar entre 1 y 2 (reducir el rango de [-65536, 65534] a algo más pequeño), luego limitar.

Si a menudo se corta con esta solución y suena demasiado fuerte, entonces es posible que desee suavizar la rodilla límite con un compresor. Esto es un poco más complejo, ya que necesita hacer que el factor de división dependa de la potencia de entrada. Primero pruebe el limitador solo y considere el compresor solo si no está satisfecho con el resultado.


Creo que, siempre que las transmisiones no estén correlacionadas, no deberías tener demasiado de qué preocuparte, deberías ser capaz de salir adelante con la saturación. Si realmente te preocupa la distorsión en los puntos de clip, un limitador suave probablemente funcionaría bien.


Debe agregarlos juntos, pero recorte el resultado al rango permitido para evitar el exceso / defecto.

En el caso de que ocurra el recorte, introducirás distorsión en el audio, pero eso es inevitable. Puede usar su código de recorte para "detectar" esta condición e informar al usuario / operador (equivalente a la luz roja de "clip" en un mezclador ...)

Podría implementar un compresor / limitador más "adecuado", pero sin conocer su aplicación exacta, es difícil decir si valdría la pena.

Si está haciendo un montón de procesamiento de audio, es posible que desee representar sus niveles de audio como valores de punto flotante, y solo volver al espacio de 16 bits al final del proceso. Los sistemas de audio digital de alta gama a menudo funcionan de esta manera.


Encontré una nueva forma de agregar muestras de una manera en la que nunca pueden exceder un rango determinado. La Idea básica es convertir valores en un rango entre -1 a 1 a un rango entre aproximadamente -Infinito a + Infinito, sumar todo e invertir la transformación inicial. Se me ocurrieron las siguientes fórmulas para esto:

Lo probé y funciona, pero para múltiples sonidos fuertes, el audio resultante suena peor que simplemente agregar las muestras juntas y recortar cada valor que es demasiado grande. Usé el siguiente código para probar esto:

#include <math.h> #include <stdio.h> #include <float.h> #include <stddef.h> #include <stdint.h> #include <string.h> #include <stdbool.h> #include <sndfile.h> // fabs wasn''t accurate enough long double ldabs(long double x){ return x < 0 ? -x : x; } // -Inf<input<+Inf, -1<=output<=+1 long double infiniteToFinite( long double sample ){ // if the input value was too big, we''ll just map it to -1 or 1 if( isinf(sample) ) return sample < 0 ? -1. : 1.; long double ret = sample / ( ldabs(sample) + 1 ); // Just in case of calculation errors if( isnan(ret) ) ret = sample < 0 ? -1. : 1.; if( ret < -1. ) ret = -1.; if( ret > 1. ) ret = 1.; return ret; } // -1<=input<=+1, -Inf<output<+Inf long double finiteToInfinite( long double sample ){ // if out of range, clamp to 1 or -1 if( sample > 1. ) sample = 1.; if( sample < -1. ) sample = -1.; long double res = -( sample / ( ldabs(sample) - 1. ) ); // sample was too close to 1 or -1, return largest long double if( isinf(res) ) return sample < 0 ? -LDBL_MAX : LDBL_MAX; return res; } // -1<input<1, -1<=output<=1 | Try to avoid input values too close to 1 or -1 long double addSamples( size_t count, long double sample[] ){ long double sum = 0; while( count-- ){ sum += finiteToInfinite( sample[count] ); if( isinf(sum) ) sum = sum < 0 ? -LDBL_MAX : LDBL_MAX; } return infiniteToFinite( sum ); } #define BUFFER_LEN 256 int main( int argc, char* argv[] ){ if( argc < 3 ){ fprintf(stderr,"Usage: %s output.wav input1.wav [input2.wav...]/n",*argv); return 1; } { SNDFILE *outfile, *infiles[argc-2]; SF_INFO sfinfo; SF_INFO sfinfo_tmp; memset( &sfinfo, 0, sizeof(sfinfo) ); for( int i=0; i<argc-2; i++ ){ memset( &sfinfo_tmp, 0, sizeof(sfinfo_tmp) ); if(!( infiles[i] = sf_open( argv[i+2], SFM_READ, &sfinfo_tmp ) )){ fprintf(stderr,"Could not open file: %s/n",argv[i+2]); puts(sf_strerror(0)); goto cleanup; } printf("Sample rate %d, channel count %d/n",sfinfo_tmp.samplerate,sfinfo_tmp.channels); if( i ){ if( sfinfo_tmp.samplerate != sfinfo.samplerate || sfinfo_tmp.channels != sfinfo.channels ){ fprintf(stderr,"Mismatching sample rate or channel count/n"); goto cleanup; } }else{ sfinfo = sfinfo_tmp; } continue; cleanup: { while(i--) sf_close(infiles[i]); return 2; } } if(!( outfile = sf_open(argv[1], SFM_WRITE, &sfinfo) )){ fprintf(stderr,"Could not open file: %s/n",argv[1]); puts(sf_strerror(0)); for( int i=0; i<argc-2; i++ ) sf_close(infiles[i]); return 3; } double inbuffer[argc-2][BUFFER_LEN]; double outbuffer[BUFFER_LEN]; size_t max_read; do { max_read = 0; memset(outbuffer,0,BUFFER_LEN*sizeof(double)); for( int i=0; i<argc-2; i++ ){ memset( inbuffer[i], 0, BUFFER_LEN*sizeof(double) ); size_t read_count = sf_read_double( infiles[i], inbuffer[i], BUFFER_LEN ); if( read_count > max_read ) max_read = read_count; } long double insamples[argc-2]; for( size_t j=0; j<max_read; j++ ){ for( int i=0; i<argc-2; i++ ) insamples[i] = inbuffer[i][j]; outbuffer[j] = addSamples( argc-2, insamples ); } sf_write_double( outfile, outbuffer, max_read ); } while( max_read ); sf_close(outfile); for( int i=0; i<argc-2; i++ ) sf_close(infiles[i]); } return 0; }


Gracias a todos por compartir sus ideas, recientemente también estoy haciendo un trabajo relacionado con la mezcla de sonido. También he hecho algo de experimentación sobre este tema, puede ayudarlos chicos :).

Tenga en cuenta que estoy usando la frecuencia de muestreo de 8Khz y el sonido de muestra de 16 bit (SInt16) en ios Remote AudioUnit.

A lo largo de mis experimentos, el mejor resultado que encontré fue algo diferente de toda esta respuesta, pero el básico es el mismo (como sugiere Roddy )

" Debe agregarlos juntos, pero recortar el resultado al rango permitido para evitar el exceso / defecto ".

Pero, ¿cuál debería ser la mejor forma de agregar sin desbordamiento / subdesbordamiento?

Idea clave :: Usted tiene dos ondas de sonido, digamos A y B, y la onda resultante C será la superposition de dos ondas A y B. La muestra en un rango de bits limitado puede hacer que se desborde. Entonces ahora podemos calcular el límite máximo cruzado en el cruce de límite máximo y mínimo en la parte inferior de la forma de onda de superposición. Ahora restaremos la cruz del límite máximo de la parte superior a la parte superior de la forma de onda de superposición y agregaremos el límite mínimo de reducción transversal a la parte inferior de la forma de onda de superposición. VOILA ... has terminado.

Pasos:

  1. Primero recorra el bucle de datos una vez para obtener el valor máximo de la cruz del límite superior y el valor mínimo de la cruz del límite inferior.
  2. Realice otro recorrido a los datos de audio, reste el valor máximo de la porción de datos de audio positiva y agregue el valor mínimo a la parte negativa de los datos de audio.

el siguiente código mostraría la implementación.

static unsigned long upSideDownValue = 0; static unsigned long downSideUpValue = 0; #define SINT16_MIN -32768 #define SINT16_MAX 32767 SInt16* mixTwoVoice (SInt16* RecordedVoiceData, SInt16* RealTimeData, SInt16 *OutputData, unsigned int dataLength){ unsigned long tempDownUpSideValue = 0; unsigned long tempUpSideDownValue = 0; //calibrate maker loop for(unsigned int i=0;i<dataLength ; i++) { SInt32 summedValue = RecordedVoiceData[i] + RealTimeData[i]; if(SINT16_MIN < summedValue && summedValue < SINT16_MAX) { //the value is within range -- good boy } else { //nasty calibration needed unsigned long tempCalibrateValue; tempCalibrateValue = ABS(summedValue) - SINT16_MIN; // here an optimization comes ;) if(summedValue < 0) { //check the downside -- to calibrate if(tempDownUpSideValue < tempCalibrateValue) tempDownUpSideValue = tempCalibrateValue; } else { //check the upside ---- to calibrate if(tempUpSideDownValue < tempCalibrateValue) tempUpSideDownValue = tempCalibrateValue; } } } //here we need some function which will gradually set the value downSideUpValue = tempUpSideDownValue; upSideDownValue = tempUpSideDownValue; //real mixer loop for(unsigned int i=0;i<dataLength;i++) { SInt32 summedValue = RecordedVoiceData[i] + RealTimeData[i]; if(summedValue < 0) { OutputData[i] = summedValue + downSideUpValue; } else if(summedValue > 0) { OutputData[i] = summedValue - upSideDownValue; } else { OutputData[i] = summedValue; } } return OutputData; }

funciona bien para mí, luego tengo intención de cambiar gradualmente el valor de upSideDownValue y downSideUpValue para obtener un resultado más suave.


Hay un artículo sobre mezclar here . Me interesaría saber qué piensan los demás acerca de esto.


Hice lo siguiente:

MAX_VAL = Full 8 or 16 or whatever value dst_val = your base audio sample src_val = sample to add to base Res = (((MAX_VAL - dst_val) * src_val) / MAX_VAL) + dst_val

Multiplique el margen superior izquierdo de src por el valor de destino normalizado MAX_VAL y añádalo. Nunca se recortará, nunca será menos ruidoso y sonará absolutamente natural.

Ejemplo:

250.5882 = (((255 - 180) * 240) / 255) + 180

Y esto suena bien :)


La mayoría de las aplicaciones de mezcla de audio harán su mezcla con números de punto flotante (32 bits es lo suficientemente bueno como para mezclar una pequeña cantidad de flujos). Traduzca las muestras de 16 bits en números de punto flotante con el rango -1.0 a 1.0 representando la escala completa en el mundo de 16 bits. Luego, sume las muestras juntas; ahora tiene mucho margen de maniobra. Finalmente, si termina con cualquier muestra cuyo valor exceda la escala completa, puede atenuar toda la señal o usar limitación estricta (valores de recorte a 1.0).

Esto proporcionará resultados de sonido mucho mejores que el agregado de muestras de 16 bits y el desbordamiento. Aquí hay un ejemplo de código muy simple que muestra cómo puede sumar dos muestras de 16 bits juntas:

short sample1 = ...; short sample2 = ...; float samplef1 = sample1 / 32768.0f; float samplef2 = sample2 / 32768.0f; float mixed = samplef1 + sample2f; // reduce the volume a bit: mixed *= 0.8; // hard clipping if (mixed > 1.0f) mixed = 1.0f; if (mixed < -1.0f) mixed = -1.0f; short outputSample = (short)(mixed * 32768.0f)


Lo hice de esta manera una vez: utilicé flotadores (muestras entre -1 y 1), y inicié una variable "autoGain" con un valor de 1. Luego, agregaría todas las muestras juntas (también podría haber más de 2). Entonces multiplicaría la señal saliente con autoGain. Si el valor absoluto de la suma de las señales antes de la multiplicación fuera superior a 1, asignaría 1 / este valor de suma. Esto efectivamente haría que el autogain sea más pequeño que 1 digamos 0.7 y sería equivalente a que un operador baje rápidamente el volumen principal tan pronto como vea que el sonido en general se está poniendo demasiado fuerte. Luego, durante un período de tiempo ajustable, aumentaría la ganancia automática hasta que finalmente regrese a "1" (nuestro operador se ha recuperado de la descarga y está subiendo lentamente el volumen :-)).


No puedo creer que nadie sepa la respuesta correcta. Todos están lo suficientemente cerca, pero aún así, una filosofía pura. El más cercano, es decir, el mejor fue: (s1 + s2) - (s1 * s2). Es un enfoque excelente, especialmente para MCU.

Entonces, el algoritmo va:

  1. Averigua el volumen en el que quieres que esté el sonido de salida. Puede ser el promedio o el máximo de una de las señales.
    factor = average(s1) Asume que ambas señales ya están correctas , sin desbordar el 32767.0
  2. Normaliza ambas señales con este factor:
    s1 = (s1/max(s1))*factor
    s2 = (s2/max(s2))*factor
  3. Agréguelos y normalice el resultado con el mismo factor
    output = ((s1+s2)/max(s1+s2))*factor

Tenga en cuenta que después del paso 1. en realidad no necesita volver a números enteros, puede trabajar con flotantes en un intervalo de -1.0 a 1.0 y aplicar el retorno a enteros al final con el factor de potencia elegido previamente. Espero no haberme equivocado ahora, porque estoy apurado.


Preferiría hacer un comentario sobre una de las dos respuestas mejor clasificadas, pero debido a mi escasa reputación (supongo) no puedo.

La respuesta "marcada": sume y el clip es correcto, pero no si desea evitar el recorte.

La respuesta con el enlace comienza con un algoritmo vudú viable para dos señales positivas en [0,1], pero luego aplica un álgebra muy defectuosa para derivar un algoritmo completamente incorrecto para los valores firmados y los valores de 8 bits. El algoritmo tampoco escala a tres o más entradas (el producto de las señales disminuirá mientras que la suma aumenta).

Entonces, convierta las señales de entrada en flotantes, escalelas a [0,1] (p. Ej., Se convertiría en un valor de 16 bits con signo).
float v = ( s + 32767.0 ) / 65536.0 (close enough...))
y luego sumarlos.

Para escalar las señales de entrada, probablemente debas hacer un trabajo real en lugar de multiplicar o restar un valor vudú. Sugeriría mantener un volumen promedio continuo y luego, si comienza a derivar alto (por encima de 0,25 decir) o bajo (por debajo de 0,01 decir) comenzar a aplicar un valor de escala basado en el volumen. Esto se convierte esencialmente en una implementación de nivel automática, y escala con cualquier cantidad de entradas. Lo mejor de todo es que en la mayoría de los casos no interferirá con tu señal.


Si necesita hacer esto bien, sugeriría buscar implementaciones de software de código abierto, al menos para la teoría.

Algunos enlaces:

Audacity

GStreamer

En realidad, probablemente deberías estar usando una biblioteca.


También puede comprarse algo de margen con un algoritmo como y = 1.1x - 0.2x ^ 3 para la curva, y con un tope en la parte superior e inferior. Lo usé en Hexaphone cuando el jugador está tocando múltiples notas juntas (hasta 6).

float waveshape_distort( float in ) { if(in <= -1.25f) { return -0.984375; } else if(in >= 1.25f) { return 0.984375; } else { return 1.1f * in - 0.2f * in * in * in; } }

No es a prueba de balas, pero le permitirá alcanzar un nivel de 1.25 y suaviza el clip a una curva agradable. Produce distorsión armónica, que suena mejor que recorte y puede ser deseable en algunas circunstancias.


Tienes razón sobre agregarlos juntos. Siempre puede escanear la suma de los dos archivos en busca de puntos máximos, y escalar todo el archivo si alcanzan algún tipo de umbral (o si el promedio del mismo y sus puntos circundantes alcanzan un umbral)


Yo diría que simplemente agrégalos juntos. Si está desbordando su espacio de PCM de 16 bits, entonces los sonidos que está usando ya son increíblemente altos para empezar y debería atenuarlos. Si eso los hiciera demasiado suaves, busque otra forma de aumentar la salida de volumen general, como una configuración de sistema operativo o girar la perilla de los altavoces.


convierta las muestras a valores de coma flotante que van desde -1.0 a +1.0, luego:

out = (s1 + s2) - (s1 * s2);


// #include <algorithm> // short ileft, nleft; ... // short iright, nright; ... // Mix float hiL = ileft + nleft; float hiR = iright + nright; // Clipping short left = std::max(-32768.0f, std::min(hiL, 32767.0f)); short right = std::max(-32768.0f, std::min(hiR, 32767.0f));