Usar AudioTrack de Android para combinar bytes de muestras de sonido produce ruido

Estoy construyendo una aplicación Android bastante simple (sdk revisión 14: ICS) que permite a los usuarios elegir dos clips de audio a la vez (todos son formato RIFF / WAV, little-endian, firmado PCM-16 bit codificación) y combinarlos en Diferentes formas de crear nuevos sonidos. El método más básico que estoy usando para esta combinación es el siguiente:

//...sound samples are read in to memory as raw byte arrays elsewhere //...offset is currently set to 45 so as to skip the 44 byte header of basic //RIFF/WAV files ... //Actual combination method public byte[] makeChimeraAll(int offset){ for(int i=offset;i<bigData.length;i++){ if(i < littleData.length){ bigData[i] = (byte) (bigData[i] + littleData[i]); } else{ //leave bigData alone } } return bigData; } 

La matriz de bytes devueltos se puede reproducir a través de la clase AudioTrack así:

 .... hMain.setBigData(hMain.getAudioTransmutation().getBigData()); //set the shared bigData // to the bigData in AudioTransmutation object hMain.getAudioProc().playWavFromByteArray(hMain.getBigData(), 22050 + (22050* (freqSeekSB.getProgress()/100)), 1024); //a SeekBar allows the user to adjust the freq //ranging from 22050 hz to 44100 hz .... public void playWavFromByteArray(byte[] audio,int sampleRate, int bufferSize){ int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT); AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM); int i = 0; at.play(); at.write(audio, 0, audio.length); at.stop(); at.release(); for(i=0;i<audio.length;i++){ Log.d("me","the byte value at audio index " + i + " is " + audio[i]); } } 

El resultado de una combinación y reproducción usando el código anterior está cerca de lo que quiero (ambas muestras son aún discernibles en el sonido hibridizado resultante), pero también hay un montón de grietas, pops y otros ruidos.

Por lo tanto, tres preguntas: En primer lugar, estoy usando AudioTrack correctamente? En segundo lugar, ¿dónde se explica la endianness en la configuración de AudioTrack? Los sonidos juegan muy bien por sí mismos y sonido casi como lo que yo esperaría cuando se combinan así que la naturaleza little-endian del formato RIFF / WAV parece comunicarse en algún lugar, pero no estoy seguro de dónde. Finalmente, ¿cuál es el intervalo de valores de bytes que debería esperar ver para la codificación de PCM de 16 bits firmada? Esperaría ver valores de -32768 a 32767 en logcat de la invocación Log.d (…), pero en su lugar los resultados tienden a estar dentro del rango de -100 a 100 (con algunos outliers más allá de eso). ¿Pueden los valores de bytes combinados más allá del rango de 16 bits representar el ruido?

Gracias, CCJ

ACTUALIZACIÓN: gracias principal a Bjorne Roche y William the Coderer! Ahora leo en los datos de audio a corto [] estructuras, endianness de la DataInputStream se cuenta con el EndianInputStream de William (http://stackoverflow.com/questions/8028094/java-datainputstream-replacement-for-endianness) y el Método de combinación se ha cambiado a esto:

 //Audio Chimera methods! public short[] makeChimeraAll(int offset){ //bigData and littleData are each short arrays, populated elsewhere int intBucket = 0; for(int i=offset;i<bigData.length;i++){ if(i < littleData.length){ intBucket = bigData[i] + littleData[i]; if(intBucket > SIGNED_SHORT_MAX){ intBucket = SIGNED_SHORT_MAX; } else if (intBucket < SIGNED_SHORT_MIN){ intBucket = SIGNED_SHORT_MIN; } bigData[i] = (short) intBucket; } else{ //leave bigData alone } } return bigData; } 

La calidad de salida de audio híbrido con estas mejoras es impresionante!

No estoy familiarizado con el audio de Android, así que no puedo contestar todas sus preguntas, pero puedo decirte cuál es el problema fundamental: la adición de datos de audio byte por byte no funcionará. Dado que funciona bien, y de mirar su código, y el hecho de que es más común, voy a suponer que tiene datos de 16 bits PCM. Sin embargo, en todas partes, se trata de bytes. Los bytes no son apropiados para procesar audio (a menos que el audio pase a ser de 8 bits)

Los bytes son aprox +/- 128. Usted dice "Esperaría ver valores que van desde -32768 a 32767 en logcat de la invocación Log.d (…), pero en su lugar los resultados tienden a estar dentro del rango de – 100 a 100 (con algunos outliers más allá de eso) "Bueno, ¿cómo podrías ir a ese rango cuando estás imprimiendo valores desde una matriz de bytes? El tipo de datos correcto para datos firmados de 16 bits es corto, no byte. Si está imprimiendo valores cortos, verá el rango que esperaba.

Debes convertir tus bytes en shorts y sumar los shorts. Esto se encargará de gran parte del ruido misceláneo que está escuchando. Puesto que usted está leyendo el archivo, sin embargo, ¿por qué molestarse en la conversión? Por qué no leerlo del archivo como un corto usando algo como esto http://docs.oracle.com/javase/1.4.2/docs/api/java/io/DataInputStream.html#readShort ()

El siguiente problema es que usted debe tratar con valores fuera de rango, en lugar de dejarlos "envolver". La solución más simple es simplemente hacer la suma como números enteros, "clip" en el rango corto, y luego almacenar la salida cortada. Esto se deshará de sus clics y pops.

En psuedo-code, todo el proceso se verá así:

 file1 = Open file 1 file2 = Open file 2 output = Open output for writing numSampleFrames1 = file1.readHeader() numSampleFrames2 = file2.readHeader() numSampleFrames = min( numSampleFrames1, numSampleFrames2 ) output.createHeader( numSampleFrames ) for( int i=0; i<numSampleFrames * channels; ++i ) { //read data from file 1 int a = file1.readShort(); //read data from file 2, and add it to data we read from file 1 a += file2.readShort(); //clip into range if( a > Short.MAX_VALUE ) a = Short.MAX_VALUE; if( a < Short.MIN_VALUE ) a = Short.MIN_VALUE; //write it to the output output.writeShort( (Short) a ); } 

Obtendrá una pequeña distorsión del paso de "recorte", pero no hay forma sencilla de evitarlo, y el recorte es MUCHO mejor que envolverse. (Que dice, a menos que sus pistas son muy "caliente", y pesado en las frecuencias bajas, la distorsión no debe ser demasiado notable.Si es un problema, puede hacer otras cosas: multiplicar un por 0,5 por ejemplo y saltar El recorte, pero luego su salida será mucho más tranquilo, que, en un teléfono, probablemente no es lo que quieres).

  • Codificar wav a AAC en Android
  • Cómo reproducir un archivo de onda comprimido en Flash Mobile
  • Guardar la entrada de audio del motor de reconocimiento de voz de Android Stock
  • Utilizar AudioTrack en Android para reproducir un archivo WAV
  • Cómo convertir el archivo WAV / OGG a archivo FLAC en Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.