2010-02-16 11 views
7

Tengo una colección de archivos WAV cortos que me gustaría procesar en Java usando varios algoritmos de procesamiento de señales digitales. Necesito obtener una matriz de muestras con valores int para este propósito, codificadas a la velocidad de cuadro de 11025 Hz.Convertir la frecuencia de muestreo sobre la marcha al leer un archivo WAV en una matriz de muestras con Java

Los archivos de origen tienen varias frecuencias de muestreo diferentes, que incluyen 11025 Hz y 44100 Hz. Aquí está el código que estoy tratando de utilizar para leerlos:

// read the WAV file 
FileInputStream fileInputStream = new FileInputStream(new File("test.wav")); 
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(fileInputStream); 

// copy the AudioInputStream to a byte array called buffer 
ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
byte[] data = new byte[4096]; 
int tempBytesRead = 0; 
int byteCounter = 0; 
while ((tempBytesRead = audioInputStream.read(data, 0, data.length)) != -1) { 
    bos.write(data, 0, tempBytesRead); 
      byteCounter += tempBytesRead; 
} 
bos.close(); 
byte[] buffer = bos.toByteArray(); 

AudioFileFormat audioFileFormat = new AudioFileFormat(AudioFileFormat.Type.WAVE, audioInputStream.getFormat(), (int)audioInputStream.getFrameLength()); 

// get the resulting sample array 
int[] samples = new int[audioFileFormat.getFrameLength()]; 
for (int i = 0; i < samples.length; i++) { 
    samples[i] = getSampleValue(i); // the getSampleValue method reads the sample values from the "buffer" array, handling different encoding types like PCM unsigned/signed, mono/stereo, 8 bit/16 bit 
} 

// RESULT: the "samples" array 

El problema es que el código no maneja adecuadamente diferentes frecuencias de muestreo. Por lo tanto, para la velocidad de cuadro de 44100 Hz, recibo cuatro veces más muestras que para la velocidad de cuadro de 11025 Hz. Me gustaría que la matriz de muestra resultante utilizara la velocidad de cuadro de 11025 Hz, independientemente de la velocidad de cuadro del archivo de origen. Traté de forzar Java para convertir la velocidad de fotogramas para mí al leer el AudioInputStream, pero me da una excepción similar a la siguiente:

java.lang.IllegalArgumentException: Unsupported conversion: PCM_SIGNED 11025.0 Hz, 16 bit, mono, 2 bytes/frame, 44100.0 frames/second, little-endian from PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian 
    at javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:955) 

leí la API de Java tutorial de sonido: http://java.sun.com/docs/books/tutorial/sound/converters.html. Parece que Java Sound API no admite este tipo de conversión de mi sistema operativo (Windows 7). Y me gustaría evitar dependencias en cualquier biblioteca externa. ¿Hay alguna manera de hacer la conversión de tasa de muestreo por mi cuenta?

Respuesta

6

Para frecuencias de muestreo> 11025 Hz, necesita reducir la resolución, que es un proceso de dos etapas. Primero necesita un filtro de paso bajo para satisfacer el criterio de Nyquist, y luego puede diezmar, p. para datos de frecuencia de muestreo de 44.1 kHz, necesitaría un filtro de paso bajo con una frecuencia de corte de 5.5 kHz y luego puede tirar 3 de cada 4 muestras para una proporción de muestreo de 4: 1. Necesitará un filtro diferente para cada relación de reducción de muestreo que desee.

+0

¿Cómo calculo la frecuencia de corte? ¿Y por qué es este paso necesario? – pako

+2

El filtrado es neccisario debido al efecto nyquist. En resumen: si su sr es 11025 hz y su entrada tiene un tono de 5572.5 hz, se podría reproducir como un tono de 60 hz. Nyquist wrap es totalmente no armónico (traducción: suena realmente feo y malo). Es necesario filtrar todas las entradas por encima de la mitad de su nuevo sr para eliminar el ruido nyquist. –

+2

y por "filtrar todas las entradas por encima de la mitad de su nueva sr" Me refiero a asegurarse de que no haya contenido por encima de esa frecuencia, y la cantidad de filtrado y donde la cortó puede variar en función de su material fuente; escuche el resultado, será obvio por el ruido agregado si su filtro necesita ser más empinado o necesita una frecuencia de corte más baja. –

5

Creo que la respuesta aceptada responde a otra pregunta: resuelve el mismo problema (bajando la resolución del audio) pero de otra manera (en lugar de usar la API de sonido java). Tenía lo mismo y me metí en él.

La forma correcta (o forma java API de sonido) para hacer esto es de hecho (como se sugiere en http://docs.oracle.com/javase/tutorial/sound/converters.html)

AudioFormat outDataFormat = new AudioFormat((float) 8000.0, (int) 8, (int) 1, true, false); 
AudioInputStream lowResAIS = AudioSystem.getAudioInputStream(outDataFormat, inFileAIS); 

problema es que Java estándar no se distribuye con remuestreo (o incluso la conversión estéreo-mono) código (o al menos no en esa parte del código - vea http://www.jsresources.org/faq_audio.html#convert_sample_rate).

Las páginas jsresources también apuntan a las respuestas: basta con instalar 2 complementos. Más fácil es instalar estos plugins en el directorio de extensiones, en OSX Lion esto va a hacer el truco (siempre que tenga wget):

wget http://www.tritonus.org/tritonus_share-0.3.6.jar -O /Library/Java/Extensions/tritonus_share-0.3.6.jar 
wget http://www.tritonus.org/tritonus_remaining-0.3.6.jar -O /Library/Java/Extensions/tritonus_remaining-0.3.6.jar 

Después de añadir estos 2 archivos jar, todo funcionaba (sólo una advertencia adicional: si desea cambiar tanto el número de canales como la frecuencia de muestreo, aún no se admite como un paso).

Cuestiones relacionadas