All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.apiclub.captcha.audio.Sample Maven / Gradle / Ivy

The newest version!
package cn.apiclub.captcha.audio;

import java.io.*;

import javax.sound.sampled.*;

/**
 * Class representing a sound sample, typically read in from a file. Note that
 * at this time this class only supports wav files with the following
 * characteristics:
 * 
    *
  • Sample rate: 16KHz
  • *
  • Sample size: 16 bits
  • *
  • Channels: 1
  • *
  • Signed: true
  • *
  • Big Endian: false
  • *
* *

* Data files in other formats will cause an * IllegalArgumentException to be thrown. *

* * @author James Childers * */ public class Sample { public static final AudioFormat SC_AUDIO_FORMAT = new AudioFormat( 16000, // sample rate 16, // sample size in bits 1, // channels true, // signed? false); // big endian?; private final AudioInputStream _audioInputStream; public Sample(InputStream is) { if (is instanceof AudioInputStream) { _audioInputStream = (AudioInputStream) is; return; } try { _audioInputStream = AudioSystem.getAudioInputStream(is); } catch (UnsupportedAudioFileException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } checkFormat(_audioInputStream.getFormat()); } public AudioInputStream getAudioInputStream() { return _audioInputStream; } public AudioFormat getFormat() { return _audioInputStream.getFormat(); } /** * Return the number of samples of all channels * * @return The number of samples for all channels */ public long getSampleCount() { long total = (_audioInputStream.getFrameLength() * getFormat().getFrameSize() * 8) / getFormat().getSampleSizeInBits(); return total / getFormat().getChannels(); } public double[] getInterleavedSamples() { double[] samples = new double[(int) getSampleCount()]; try { getInterleavedSamples(0, getSampleCount(), samples); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return samples; } /** * Get the interleaved decoded samples for all channels, from sample index * begin (included) to sample index end (excluded) * and copy them into samples. end must not exceed * getSampleCount(), and the number of samples must not be so * large that the associated byte array cannot be allocated * * @param begin * @param end * @param samples * @throws IOException * @throws IllegalArgumentException */ public double[] getInterleavedSamples(long begin, long end, double[] samples) throws IOException, IllegalArgumentException { long nbSamples = end - begin; long nbBytes = nbSamples * (getFormat().getSampleSizeInBits() / 8) * getFormat().getChannels(); if (nbBytes > Integer.MAX_VALUE) { throw new IllegalArgumentException( "Too many samples. Try using a smaller wav."); } // allocate a byte buffer byte[] inBuffer = new byte[(int) nbBytes]; // read bytes from audio file _audioInputStream.read(inBuffer, 0, inBuffer.length); // decode bytes into samples. decodeBytes(inBuffer, samples); return samples; } /** * Extract samples of a particular channel from interleavedSamples and copy * them into channelSamples * * @param channel * @param interleavedSamples * @param channelSamples */ public void getChannelSamples(int channel, double[] interleavedSamples, double[] channelSamples) { int nbChannels = getFormat().getChannels(); for (int i = 0; i < channelSamples.length; i++) { channelSamples[i] = interleavedSamples[nbChannels * i + channel]; } } /** * Convenience method. Extract left and right channels for common stereo * files. leftSamples and rightSamples must be of size getSampleCount() * * @param leftSamples * @param rightSamples * @throws IOException */ public void getStereoSamples(double[] leftSamples, double[] rightSamples) throws IOException { long sampleCount = getSampleCount(); double[] interleavedSamples = new double[(int) sampleCount * 2]; getInterleavedSamples(0, sampleCount, interleavedSamples); for (int i = 0; i < leftSamples.length; i++) { leftSamples[i] = interleavedSamples[2 * i]; rightSamples[i] = interleavedSamples[2 * i + 1]; } } // Decode bytes of audioBytes into audioSamples public void decodeBytes(byte[] audioBytes, double[] audioSamples) { int sampleSizeInBytes = getFormat().getSampleSizeInBits() / 8; int[] sampleBytes = new int[sampleSizeInBytes]; int k = 0; // index in audioBytes for (int i = 0; i < audioSamples.length; i++) { // collect sample byte in big-endian order if (getFormat().isBigEndian()) { // bytes start with MSB for (int j = 0; j < sampleSizeInBytes; j++) { sampleBytes[j] = audioBytes[k++]; } } else { // bytes start with LSB for (int j = sampleSizeInBytes - 1; j >= 0; j--) { sampleBytes[j] = audioBytes[k++]; if (sampleBytes[j] != 0) j = j + 0; } } // get integer value from bytes int ival = 0; for (int j = 0; j < sampleSizeInBytes; j++) { ival += sampleBytes[j]; if (j < sampleSizeInBytes - 1) ival <<= 8; } // decode value double ratio = Math.pow(2., getFormat().getSampleSizeInBits() - 1); double val = ((double) ival) / ratio; audioSamples[i] = val; } } /** * Return the interleaved samples as a byte[]. * * @return The interleaved samples */ public final byte[] asByteArray() { return asByteArray(getSampleCount(), getInterleavedSamples()); } /** * Helper method to convert a double[] to a byte[] in a format that can be * used by {@link AudioInputStream}. Typically this will be used with * a {@link Sample} that has been modified from its original. * * @see Yak Shaving * * @return A byte[] representing a sample */ public static final byte[] asByteArray(long sampleCount, double[] sample) { int b_len = (int) sampleCount * (SC_AUDIO_FORMAT.getSampleSizeInBits() / 8); byte[] buffer = new byte[b_len]; int in; for (int i = 0; i < sample.length; i++) { in = (int) (sample[i] * 32767); buffer[2 * i] = (byte) (in & 255); buffer[2 * i + 1] = (byte) (in >> 8); } return buffer; } @Override public String toString() { return "[Sample] samples: " + getSampleCount() + ", format: " + getFormat(); } private static final void checkFormat(AudioFormat af) { if (!af.matches(SC_AUDIO_FORMAT)) { throw new IllegalArgumentException( "Unsupported audio format.\nReceived: " + af.toString() + "\nExpected: " + SC_AUDIO_FORMAT); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy