// https://github.com/s4l4x/audio-analysis/blob/master/src/com/badlogic/audio/io/WaveDecoder.java /** * A simple class that can read in the PCM data from a * Wav file, converting the data to signed 32-bit floats * in the range [-1,1], merging stereo channels to a mono * channel for processing. This only supports 16-bit signed * stereo and mono Wav files with a sampling rate of 44100. * * @author mzechner * */ sclass WAVDecoder /*implements com.badlogic.audio.io.Decoder*/ implements AutoCloseable { /** the input stream we read from **/ EndianDataInputStream in; /** number of channels **/ private final int channels; /** sample rate in Herz**/ private final float sampleRate; bool ignoreSampleRate = true; *(InputStream stream) ctex { in = new EndianDataInputStream( new BufferedInputStream( stream, 1024*1024) ); if( !in.read4ByteString().equals( "RIFF" ) ) throw new IllegalArgumentException( "not a wav" ); in.readIntLittleEndian(); if( !in.read4ByteString().equals( "WAVE" ) ) throw new IllegalArgumentException( "expected WAVE tag" ); if( !in.read4ByteString().equals( "fmt " ) ) throw new IllegalArgumentException( "expected fmt tag" ); if( in.readIntLittleEndian() != 16 ) throw new IllegalArgumentException( "expected wave chunk size to be 16" ); int format; if ((format = in.readShortLittleEndian()) != 1) throw new IllegalArgumentException( "expected format to be 1, got: " + format); channels = in.readShortLittleEndian(); print("Channels: " + channels); sampleRate = in.readIntLittleEndian(); if (sampleRate != 44100) if (ignoreSampleRate) print("Sample rate: " + sampleRate); else fail("Not 44100 sampling rate: " + sampleRate); in.readIntLittleEndian(); in.readShortLittleEndian(); int fmt = in.readShortLittleEndian(); if( fmt != 16 ) fail("Only 16-bit signed format supported:" + fmt); S tag; while (!(tag = in.read4ByteString()).equals("data")) { print("Skipping tag " + tag); //fail( "expected data tag, got: " + tag); int len = in.readIntLittleEndian(); for i to len: in.read(); } in.readIntLittleEndian(); } /** * Tries to read in samples.length samples, merging stereo to a mono * channel by averaging and converting non float formats to float 32-bit. * Returns the number of samples actually read. Guarantees that samples.length * samples are read in if there was enough data in the stream. * * @param samples The samples array to write the samples to * @return The number of samples actually read. */ public int readMonoSamples(short[] samples) { int readSamples = 0; for (int i = 0; i < samples.length; i++) { double sample = 0; try { for j to channels: sample += in.readShortLittleEndian(); sample /= channels; samples[i] = (short) iround(max(-32768, min(32767, sample))); readSamples++; } catch (Exception ex) { break; } // ouch } ret readSamples; } public int readStereoSamples(short[] samples) { int readSamples = 0; for (int i = 0; i < samples.length; i += 2) { double sample = 0; try { short left = in.readShortLittleEndian(); short right; if (channels > 1) right = in.readShortLittleEndian(); else right = left; samples[i] = left; samples[i+1] = right; readSamples += 2; } catch (Exception ex) { break; } // ouch } ret readSamples; } public void close() ctex { in.close(); } }