Ho una raccolta di file WAV brevi che vorrei elaborare in Java utilizzando vari algoritmi di elaborazione del segnale digitale. Ho bisogno di ottenere una matrice di campioni con valore int per questo scopo, codificata alla frequenza di fotogrammi di 11025 Hz.Conversione immediata della velocità di campionamento durante la lettura di un file WAV in un array di campioni con Java
I file di origine hanno diverse frequenze di campionamento, tra cui 11025 Hz e 44100 Hz. Ecco il codice che sto cercando di usare per leggerli:
// 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
Il problema è, che il codice non gestisce diverse frequenze di campionamento in modo corretto. Quindi per il frame rate di 44100 Hz ottengo quattro volte il numero di campioni rispetto al frame rate di 11025 Hz. Vorrei che l'array campione risultante usasse la frequenza fotogrammi di 11025 Hz, indipendentemente dalla frequenza dei fotogrammi del file sorgente. Ho provato a forzare Java per convertire il frame rate per me quando la lettura del AudioInputStream, ma ottengo un'eccezione simile al seguente:
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)
ho letto il tutorial di API Java Audio: http://java.sun.com/docs/books/tutorial/sound/converters.html. Sembra che l'API Java Sound non supporti questo tipo di conversione del mio sistema operativo (Windows 7). E vorrei evitare dipendenze da qualsiasi libreria esterna. C'è un modo per fare la conversione della frequenza di campionamento per conto mio?
Come faccio a calcolare la frequenza di taglio? E perché questo passaggio è necessario? – pako
Il filtraggio è necessario a causa dell'effetto nyquist. In breve: se il SR è 11025 Hz e il tuo ingresso aveva un tono 5.572,5 hz in essa, che sarebbe stato riprodotto come tono di 60 Hz. involucro di Nyquist è totalmente non-armonica (traduzione: suona veramente brutto e cattivo). È necessario filtrare tutti gli input sopra la metà del nuovo sr per eliminare il rumore di nyquist. –
e "filtra tutti gli input sopra la metà del tuo nuovo sr" Voglio dire assicurati che ci sia contenuto zero al di sopra di quella frequenza - e la quantità di filtri e dove li tagli può variare in base al tuo materiale sorgente - ascolta il risultato, sarà ovvio dal rumore aggiunto se il tuo filtro ha bisogno di essere più ripido o ha bisogno di una frequenza di taglio più bassa. –