2010-02-16 13 views
7

Mam zbiór krótkich plików WAV, które chciałbym przetwarzać w Javie przy użyciu różnych algorytmów cyfrowego przetwarzania sygnałów. Muszę uzyskać w tym celu zestaw próbek o wartości int, zakodowanych z częstotliwością klatek na sekundę 11025 Hz.Konwersja częstotliwości próbkowania w locie podczas odczytu pliku WAV do tablicy próbek przy użyciu Javy

Pliki źródłowe mają kilka różnych częstotliwości próbkowania, w tym 11025 Hz i 44100 Hz. Oto kod, którego próbuję użyć, aby je odczytać:

// 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 

Problem polega na tym, że kod nie obsługuje poprawnie różnych częstotliwości próbkowania. Tak więc dla częstotliwości klatek 44100 Hz otrzymuję cztery razy więcej próbek niż dla częstotliwości ramki 11025 Hz. Chciałbym, aby wynikowa tablica wykorzystała częstotliwość ramek 11025 Hz, bez względu na szybkość klatek pliku źródłowego. Próbowałem zmusić Java do konwersji klatek dla mnie podczas czytania AudioInputStream, ale pojawia się wyjątek podobny do następującego:

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) 

Czytałem tutorial Java API dźwięku: http://java.sun.com/docs/books/tutorial/sound/converters.html. Wygląda na to, że Java Sound API nie obsługuje tego rodzaju konwersji mojego systemu operacyjnego (Windows 7). I chciałbym uniknąć zależności od zewnętrznych bibliotek. Czy jest jakiś sposób, aby zrobić konwersję częstotliwości próbkowania na własną rękę?

Odpowiedz

6

Dla częstotliwości próbkowania> 11025 Hz należy przeprowadzić próbę w dół, co jest procesem dwustopniowym. Najpierw musisz filtr dolnoprzepustowy, aby spełnić kryterium Nyquista, a następnie możesz zdziesiątkować, np. dla danych o częstotliwości próbkowania 44,1 kHz, których potrzebujesz do filtra dolnoprzepustowego z częstotliwością odcięcia 5,5 kHz, a następnie możesz wyrzucić 3 na każdą z 4 próbek dla współczynnika próbkowania 4: 1. Będziesz potrzebował innego filtru dla każdego współczynnika zmniejszania próbkowania, który chcesz obsłużyć.

+0

Jak obliczyć częstotliwość odcięcia? I dlaczego ten krok jest konieczny? – pako

+2

Filtrowanie jest konieczne ze względu na efekt NIquist. W skrócie: jeśli twój sr jest 11025 hz, a twój sygnał wejściowy miał ton 552,5.5 hz, byłby odtworzony jako dźwięk 60 hz. Nyquist wrap jest całkowicie nieharmonijny (tłumaczenie: brzmi naprawdę brzydko i źle). Musisz odfiltrować wszystkie dane wejściowe powyżej połowy nowego sr, aby wyeliminować hałas nyquista. –

+2

i przez "filtrowanie wszystkich danych wejściowych powyżej połowy nowego sr", tzn. Upewnij się, że jest zero treści powyżej tej częstotliwości - a ilość filtrowania i miejsca, w którym je odciąłeś, może się różnić w zależności od materiału źródłowego - słuchaj wyniku, będzie to oczywiste po dodaniu szumu, jeśli filtr musi być bardziej stromy lub wymaga niższej częstotliwości granicznej. –

5

Uważam, że zaakceptowana odpowiedź stanowi odpowiedź na inne pytanie - rozwiązuje ten sam problem (zmniejszając częstotliwość próbkowania dźwięku), ale w inny sposób (ręcznie zamiast korzystać z interfejsu API dźwięku Java). Miałem to samo i wkopałem się w to.

Prawidłowy sposób (lub java dźwięku API sposób), aby to zrobić, jest rzeczywiście (jak zasugerowano w 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); 

Problem jest to, że średnia Java nie jest dostarczany z resampling (lub nawet konwersja stereo-mono) (lub przynajmniej nie w tej części kodu - patrz: http://www.jsresources.org/faq_audio.html#convert_sample_rate).

Strony jsresources wskazują również na odpowiedzi: wystarczy zainstalować 2 wtyczki. Najłatwiej jest zainstalowanie tych wtyczek w katalogu rozszerzeń, na OSX Lion to załatwi (o ile masz 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 

Po dodaniu te 2 pliki jar, wszystko działało (tylko jeden dodatkowy Ostrzeżenie: Jeśli chcesz zmienić zarówno liczbę kanałów, jak i częstotliwość próbkowania, nadal nie jest obsługiwana jako jeden krok).

Powiązane problemy