An example of playing a sound with an echo filter : Sound « Development Class « Java






An example of playing a sound with an echo filter

 
       /*
DEVELOPING GAME IN JAVA 

Caracteristiques

Editeur : NEW RIDERS 
Auteur : BRACKEEN 
Parution : 09 2003 
Pages : 972 
Isbn : 1-59273-005-1 
Reliure : Paperback 
Disponibilite : Disponible a la librairie 
*/
       

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

/**
 * An example of playing a sound with an echo filter.
 * 
 * @see EchoFilter
 * @see SimpleSoundPlayer
 */
public class EchoFilterTest {

  public static void main(String[] args) {

    // load the sound
    SimpleSoundPlayer sound = new SimpleSoundPlayer("../sounds/voice.wav");

    // create the sound stream
    InputStream is = new ByteArrayInputStream(sound.getSamples());

    // create an echo with a 11025-sample buffer
    // (1/4 sec for 44100Hz sound) and a 60% decay
    EchoFilter filter = new EchoFilter(11025, .6f);

    // create the filtered sound stream
    is = new FilteredSoundStream(is, filter);

    // play the sound
    sound.play(is);

    // due to bug in Java Sound, explicitly exit the VM.
    System.exit(0);
  }

}

/**
 * The SimpleSoundPlayer encapsulates a sound that can be opened from the file
 * system and later played.
 */

class SimpleSoundPlayer {

  public static void main(String[] args) {
    // load a sound
    SimpleSoundPlayer sound = new SimpleSoundPlayer("../sounds/voice.wav");

    // create the stream to play
    InputStream stream = new ByteArrayInputStream(sound.getSamples());

    // play the sound
    sound.play(stream);

    // exit
    System.exit(0);
  }

  private AudioFormat format;

  private byte[] samples;

  /**
   * Opens a sound from a file.
   */
  public SimpleSoundPlayer(String filename) {
    try {
      // open the audio input stream
      AudioInputStream stream = AudioSystem.getAudioInputStream(new File(
          filename));

      format = stream.getFormat();

      // get the audio samples
      samples = getSamples(stream);
    } catch (UnsupportedAudioFileException ex) {
      ex.printStackTrace();
    } catch (IOException ex) {
      ex.printStackTrace();
    }
  }

  /**
   * Gets the samples of this sound as a byte array.
   */
  public byte[] getSamples() {
    return samples;
  }

  /**
   * Gets the samples from an AudioInputStream as an array of bytes.
   */
  private byte[] getSamples(AudioInputStream audioStream) {
    // get the number of bytes to read
    int length = (int) (audioStream.getFrameLength() * format
        .getFrameSize());

    // read the entire stream
    byte[] samples = new byte[length];
    DataInputStream is = new DataInputStream(audioStream);
    try {
      is.readFully(samples);
    } catch (IOException ex) {
      ex.printStackTrace();
    }

    // return the samples
    return samples;
  }

  /**
   * Plays a stream. This method blocks (doesn't return) until the sound is
   * finished playing.
   */
  public void play(InputStream source) {

    // use a short, 100ms (1/10th sec) buffer for real-time
    // change to the sound stream
    int bufferSize = format.getFrameSize()
        * Math.round(format.getSampleRate() / 10);
    byte[] buffer = new byte[bufferSize];

    // create a line to play to
    SourceDataLine line;
    try {
      DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
      line = (SourceDataLine) AudioSystem.getLine(info);
      line.open(format, bufferSize);
    } catch (LineUnavailableException ex) {
      ex.printStackTrace();
      return;
    }

    // start the line
    line.start();

    // copy data to the line
    try {
      int numBytesRead = 0;
      while (numBytesRead != -1) {
        numBytesRead = source.read(buffer, 0, buffer.length);
        if (numBytesRead != -1) {
          line.write(buffer, 0, numBytesRead);
        }
      }
    } catch (IOException ex) {
      ex.printStackTrace();
    }

    // wait until all data is played, then close the line
    line.drain();
    line.close();

  }

}

/**
 * The EchoFilter class is a SoundFilter that emulates an echo.
 * 
 * @see FilteredSoundStream
 */

class EchoFilter extends SoundFilter {

  private short[] delayBuffer;

  private int delayBufferPos;

  private float decay;

  /**
   * Creates an EchoFilter with the specified number of delay samples and the
   * specified decay rate.
   * <p>
   * The number of delay samples specifies how long before the echo is
   * initially heard. For a 1 second echo with mono, 44100Hz sound, use 44100
   * delay samples.
   * <p>
   * The decay value is how much the echo has decayed from the source. A decay
   * value of .5 means the echo heard is half as loud as the source.
   */
  public EchoFilter(int numDelaySamples, float decay) {
    delayBuffer = new short[numDelaySamples];
    this.decay = decay;
  }

  /**
   * Gets the remaining size, in bytes, of samples that this filter can echo
   * after the sound is done playing. Ensures that the sound will have decayed
   * to below 1% of maximum volume (amplitude).
   */
  public int getRemainingSize() {
    float finalDecay = 0.01f;
    // derived from Math.pow(decay,x) <= finalDecay
    int numRemainingBuffers = (int) Math.ceil(Math.log(finalDecay)
        / Math.log(decay));
    int bufferSize = delayBuffer.length * 2;

    return bufferSize * numRemainingBuffers;
  }

  /**
   * Clears this EchoFilter's internal delay buffer.
   */
  public void reset() {
    for (int i = 0; i < delayBuffer.length; i++) {
      delayBuffer[i] = 0;
    }
    delayBufferPos = 0;
  }

  /**
   * Filters the sound samples to add an echo. The samples played are added to
   * the sound in the delay buffer multipied by the decay rate. The result is
   * then stored in the delay buffer, so multiple echoes are heard.
   */
  public void filter(byte[] samples, int offset, int length) {

    for (int i = offset; i < offset + length; i += 2) {
      // update the sample
      short oldSample = getSample(samples, i);
      short newSample = (short) (oldSample + decay
          * delayBuffer[delayBufferPos]);
      setSample(samples, i, newSample);

      // update the delay buffer
      delayBuffer[delayBufferPos] = newSample;
      delayBufferPos++;
      if (delayBufferPos == delayBuffer.length) {
        delayBufferPos = 0;
      }
    }
  }

}

/**
 * The FilteredSoundStream class is a FilterInputStream that applies a
 * SoundFilter to the underlying input stream.
 * 
 * @see SoundFilter
 */

class FilteredSoundStream extends FilterInputStream {

  private static final int REMAINING_SIZE_UNKNOWN = -1;

  private SoundFilter soundFilter;

  private int remainingSize;

  /**
   * Creates a new FilteredSoundStream object with the specified InputStream
   * and SoundFilter.
   */
  public FilteredSoundStream(InputStream in, SoundFilter soundFilter) {
    super(in);
    this.soundFilter = soundFilter;
    remainingSize = REMAINING_SIZE_UNKNOWN;
  }

  /**
   * Overrides the FilterInputStream method to apply this filter whenever
   * bytes are read
   */
  public int read(byte[] samples, int offset, int length) throws IOException {
    // read and filter the sound samples in the stream
    int bytesRead = super.read(samples, offset, length);
    if (bytesRead > 0) {
      soundFilter.filter(samples, offset, bytesRead);
      return bytesRead;
    }

    // if there are no remaining bytes in the sound stream,
    // check if the filter has any remaining bytes ("echoes").
    if (remainingSize == REMAINING_SIZE_UNKNOWN) {
      remainingSize = soundFilter.getRemainingSize();
      // round down to nearest multiple of 4
      // (typical frame size)
      remainingSize = remainingSize / 4 * 4;
    }
    if (remainingSize > 0) {
      length = Math.min(length, remainingSize);

      // clear the buffer
      for (int i = offset; i < offset + length; i++) {
        samples[i] = 0;
      }

      // filter the remaining bytes
      soundFilter.filter(samples, offset, length);
      remainingSize -= length;

      // return
      return length;
    } else {
      // end of stream
      return -1;
    }
  }

}

/**
 * A abstract class designed to filter sound samples. Since SoundFilters may use
 * internal buffering of samples, a new SoundFilter object should be created for
 * every sound played. However, SoundFilters can be reused after they are
 * finished by called the reset() method.
 * <p>
 * Assumes all samples are 16-bit, signed, little-endian format.
 * 
 * @see FilteredSoundStream
 */

abstract class SoundFilter {

  /**
   * Resets this SoundFilter. Does nothing by default.
   */
  public void reset() {
    // do nothing
  }

  /**
   * Gets the remaining size, in bytes, that this filter plays after the sound
   * is finished. An example would be an echo that plays longer than it's
   * original sound. This method returns 0 by default.
   */
  public int getRemainingSize() {
    return 0;
  }

  /**
   * Filters an array of samples. Samples should be in 16-bit, signed,
   * little-endian format.
   */
  public void filter(byte[] samples) {
    filter(samples, 0, samples.length);
  }

  /**
   * Filters an array of samples. Samples should be in 16-bit, signed,
   * little-endian format. This method should be implemented by subclasses.
   */
  public abstract void filter(byte[] samples, int offset, int length);

  /**
   * Convenience method for getting a 16-bit sample from a byte array. Samples
   * should be in 16-bit, signed, little-endian format.
   */
  public static short getSample(byte[] buffer, int position) {
    return (short) (((buffer[position + 1] & 0xff) << 8) | (buffer[position] & 0xff));
  }

  /**
   * Convenience method for setting a 16-bit sample in a byte array. Samples
   * should be in 16-bit, signed, little-endian format.
   */
  public static void setSample(byte[] buffer, int position, short sample) {
    buffer[position] = (byte) (sample & 0xff);
    buffer[position + 1] = (byte) ((sample >> 8) & 0xff);
  }

}       
           
         
  








Related examples in the same category

1.Play sound
2.Duke Speaks
3.Duke Speaks Test
4.Sound Applet
5.Sound player
6.Simple program to try out the new Sound stuff in JDK1.2
7.Sound Application Sound Application
8.An example of loading and playing a sound using a ClipAn example of loading and playing a sound using a Clip
9.The Filter3dTest class demonstrates the Filter3d functionality
10.Sound Manager TestSound Manager Test
11.An example that plays a Midi sequence
12.Determining When a Sampled Audio Player Has Finished Playing
13.Setting the Volume of a Sampled Audio Player
14.Determining the Position of a Sampled Audio Player
15.Load audio file From URL
16.Playing Streaming Sampled Audio
17.Determining the File Format of a Sampled Audio File
18.Loading and Playing Sampled Audio
19.Determining the Position of a Midi Sequencer
20.Continuously Playing a Sampled Audio File
21.Load image and sound from Jar file
22.Determine the duration of a Midi audio file
23.Playing Streaming Midi Audio
24.Capturing Audio with Java Sound API
25.A simple player for sampled sound files.
26.Load and play Midi audio
27.Play a streaming Midi audio
28.Determining When a Midi Audio Player Has Finished Playing
29.Float Control Component
30.This is a simple program to record sounds and play them back
31.Determining the Duration of a Midi Audio File
32.Loading and Playing Midi Audio
33.Determining the File Format of a Midi Audio File
34.Play an audio file from a JAR file
35.Setting the Volume of Playing Midi Audio
36.Make your own Java Media Player to play media files
37.Determining the Encoding of a Sampled Audio File
38.Determining the Duration of a Sampled Audio File
39.audio sound: implements java.applet.AudioClip