Java Tutorial/Development/Audio — различия между версиями

Материал из Java эксперт
Перейти к: навигация, поиск
м (1 версия)
 
(нет различий)

Текущая версия на 15:28, 31 мая 2010

A simple player for sampled sound files.

/*
 *
 * Copyright (c) 1999 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free,
 * license to use, modify and redistribute this software in 
 * source and binary code form, provided that i) this copyright
 * notice and license appear on all copies of the software; and 
 * ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty
 * of any kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS
 * AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE 
 * HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR 
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT
 * WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT
 * OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS
 * OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY
 * TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGES.
 This software is not designed or intended for use in on-line
 control of aircraft, air traffic, aircraft navigation or
 aircraft communications; or in the design, construction,
 operation or maintenance of any nuclear facility. Licensee 
 represents and warrants that it will not use or redistribute 
 the Software for such purposes.
 */
/*  The above copyright statement is included because this 
 * program uses several methods from the JavaSoundDemo
 * distributed by SUN. In some cases, the sound processing methods
 * unmodified or only slightly modified.
 * All other methods copyright Steve Potts, 2002
 */
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.Vector;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MetaEventListener;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiChannel;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Synthesizer;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
/**
 * A simple player for sampled sound files.
 * 
 * 
 * @author Steve Potts
 */
public class SimpleSoundPlayer implements Runnable, LineListener, MetaEventListener {
  final int bufSize = 16384;
  Vector sounds = new Vector();
  Thread thread;
  Sequencer sequencer;
  boolean midiEOM, audioEOM;
  Synthesizer synthesizer;
  MidiChannel channels[];
  Object currentSound;
  String currentName;
  double duration;
  int num;
  boolean bump;
  boolean paused = false;
  String errStr;
  public void open() {
    try {
      sequencer = MidiSystem.getSequencer();
      if (sequencer instanceof Synthesizer) {
        synthesizer = (Synthesizer) sequencer;
        channels = synthesizer.getChannels();
      }
    } catch (Exception ex) {
      ex.printStackTrace();
      return;
    }
    sequencer.addMetaEventListener(this);
  }
  public void close() {
    if (sequencer != null) {
      sequencer.close();
    }
  }
  private void addSound(File file) {
    sounds.add(file);
  }
  public boolean loadSound(Object object) {
    duration = 0.0;
    currentName = ((File) object).getName();
    try {
      currentSound = AudioSystem.getAudioInputStream((File) object);
    } catch (Exception e1) {
      try {
        FileInputStream is = new FileInputStream((File) object);
        currentSound = new BufferedInputStream(is, 1024);
      } catch (Exception e3) {
        e3.printStackTrace();
        currentSound = null;
        return false;
      }
      // }
    }
    // user pressed stop or changed tabs while loading
    if (sequencer == null) {
      currentSound = null;
      return false;
    }
    if (currentSound instanceof AudioInputStream) {
      try {
        AudioInputStream stream = (AudioInputStream) currentSound;
        AudioFormat format = stream.getFormat();
        /**
         * we can"t yet open the device for ALAW/ULAW playback, convert
         * ALAW/ULAW to PCM
         */
        if ((format.getEncoding() == AudioFormat.Encoding.ULAW)
            || (format.getEncoding() == AudioFormat.Encoding.ALAW)) {
          AudioFormat tmp = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
              format.getSampleRate(), format.getSampleSizeInBits() * 2, format.getChannels(),
              format.getFrameSize() * 2, format.getFrameRate(), true);
          stream = AudioSystem.getAudioInputStream(tmp, stream);
          format = tmp;
        }
        DataLine.Info info = new DataLine.Info(Clip.class, stream.getFormat(), ((int) stream
            .getFrameLength() * format.getFrameSize()));
        Clip clip = (Clip) AudioSystem.getLine(info);
        clip.addLineListener(this);
        clip.open(stream);
        currentSound = clip;
        // seekSlider.setMaximum((int) stream.getFrameLength());
      } catch (Exception ex) {
        ex.printStackTrace();
        currentSound = null;
        return false;
      }
    } else if (currentSound instanceof Sequence || currentSound instanceof BufferedInputStream) {
      try {
        sequencer.open();
        if (currentSound instanceof Sequence) {
          sequencer.setSequence((Sequence) currentSound);
        } else {
          sequencer.setSequence((BufferedInputStream) currentSound);
        }
      } catch (InvalidMidiDataException imde) {
        System.out.println("Unsupported audio file.");
        currentSound = null;
        return false;
      } catch (Exception ex) {
        ex.printStackTrace();
        currentSound = null;
        return false;
      }
    }
    duration = getDuration();
    return true;
  }
  public void playSound() {
    midiEOM = audioEOM = bump = false;
    if (currentSound instanceof Sequence || currentSound instanceof BufferedInputStream
        && thread != null) {
      sequencer.start();
      while (!midiEOM && thread != null && !bump) {
        try {
          thread.sleep(99);
        } catch (Exception e) {
          break;
        }
      }
      sequencer.stop();
      sequencer.close();
    } else if (currentSound instanceof Clip) {
      Clip clip = (Clip) currentSound;
      clip.start();
      try {
        thread.sleep(99);
      } catch (Exception e) {
      }
      while ((paused || clip.isActive()) && thread != null && !bump) {
        try {
          thread.sleep(99);
        } catch (Exception e) {
          break;
        }
      }
      clip.stop();
      clip.close();
    }
    currentSound = null;
  }
  public double getDuration() {
    double duration = 0.0;
    if (currentSound instanceof Sequence) {
      duration = ((Sequence) currentSound).getMicrosecondLength() / 1000000.0;
    } else if (currentSound instanceof BufferedInputStream) {
      duration = sequencer.getMicrosecondLength() / 1000000.0;
    } else if (currentSound instanceof Clip) {
      Clip clip = (Clip) currentSound;
      duration = clip.getBufferSize()
          / (clip.getFormat().getFrameSize() * clip.getFormat().getFrameRate());
    }
    return duration;
  }
  public void update(LineEvent event) {
    if (event.getType() == LineEvent.Type.STOP && !paused) {
      audioEOM = true;
    }
  }
  public void meta(MetaMessage message) {
    if (message.getType() == 47) { // 47 is end of track
      midiEOM = true;
    }
  }
  private void reportStatus(String msg) {
    if ((errStr = msg) != null) {
      System.out.println(errStr);
    }
  }
  public Thread getThread() {
    return thread;
  }
  public void start() {
    thread = new Thread(this);
    thread.setName("SimpleSamplePlayer");
    thread.start();
  }
  public void stop() {
    if (thread != null) {
      thread.interrupt();
    }
    thread = null;
  }
  public void run() {
    for (; num < sounds.size() && thread != null; num++) {
      if (loadSound(sounds.get(num)) == true) {
        playSound();
      }
      // take a little break between sounds
      try {
        thread.sleep(222);
      } catch (Exception e) {
        break;
      }
    }
    num = 0;
    thread = null;
    currentName = null;
    currentSound = null;
    System.out.println("Press <ctrl-c> to exit");
  }
  public void loadSounds(String name) {
    try {
      File file = new File(name);
      if (file != null && file.isDirectory()) {
        String files[] = file.list();
        for (int i = 0; i < files.length; i++) {
          File leafFile = new File(file.getAbsolutePath(), files[i]);
          addSound(leafFile);
        }
      }
    } catch (Exception e) {
      System.out.println("Exception " + e);
    }
  }
  public static void main(String args[]) {
    // every file in this directory will be played
    String media = "c:/unleashed/ch18/sounds";
    final SimpleSoundPlayer ssp = new SimpleSoundPlayer();
    ssp.open();
    // we first load the sound file names in a vector
    ssp.loadSounds(media);
    // Then we start a thread to play the sounds
    ssp.start();
    // We have to wait for a while so that the process doesn"t
    // terminate, killing the playing thread
    try {
      Thread.sleep(500000);
    } catch (Exception e) {
      System.out.println("Interrupted");
    }
    // close and exit
    ssp.close();
    System.exit(0);
  }
}





Capturing Audio with Java Sound API

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
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.SourceDataLine;
import javax.sound.sampled.TargetDataLine;
public class Main {
  public static void main(String args[]) throws Exception {
    final ByteArrayOutputStream out = new ByteArrayOutputStream();
    float sampleRate = 8000;
    int sampleSizeInBits = 8;
    int channels = 1;
    boolean signed = true;
    boolean bigEndian = true;
    final AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits, channels, signed,
        bigEndian);
    DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
    final TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
    line.open(format);
    line.start();
    Runnable runner = new Runnable() {
      int bufferSize = (int) format.getSampleRate() * format.getFrameSize();
      byte buffer[] = new byte[bufferSize];
      public void run() {
        try {
          int count = line.read(buffer, 0, buffer.length);
          if (count > 0) {
            out.write(buffer, 0, count);
          }
          out.close();
        } catch (IOException e) {
          System.err.println("I/O problems: " + e);
          System.exit(-1);
        }
      }
    };
    Thread captureThread = new Thread(runner);
    captureThread.start();
    byte audio[] = out.toByteArray();
    InputStream input = new ByteArrayInputStream(audio);
    final SourceDataLine line1 = (SourceDataLine) AudioSystem.getLine(info);
    final AudioInputStream ais = new AudioInputStream(input, format, audio.length
        / format.getFrameSize());
    line1.open(format);
    line1.start();
    runner = new Runnable() {
      int bufferSize = (int) format.getSampleRate() * format.getFrameSize();
      byte buffer[] = new byte[bufferSize];
      public void run() {
        try {
          int count;
          while ((count = ais.read(buffer, 0, buffer.length)) != -1) {
            if (count > 0) {
              line1.write(buffer, 0, count);
            }
          }
          line1.drain();
          line1.close();
        } catch (IOException e) {
          System.err.println("I/O problems: " + e);
          System.exit(-3);
        }
      }
    };
    Thread playThread = new Thread(runner);
    playThread.start();
  }
}





Determining the Duration of a Sampled Audio File

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
public class Main {
  public static void main(String[] argv) throws Exception {
    DataLine.Info info = null;
    Clip clip = (Clip) AudioSystem.getLine(info);
    double durationInSecs = clip.getBufferSize()
        / (clip.getFormat().getFrameSize() * clip.getFormat().getFrameRate());
  }
}





Determining the Encoding of a Sampled Audio File

import java.io.File;
import java.net.URL;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
public class Main {
  public static void main(String[] argv) throws Exception {
    AudioInputStream stream = AudioSystem.getAudioInputStream(new File(
        "audiofile"));
  }
}





Determining the File Format of a Sampled Audio File

import java.io.File;
import java.net.URL;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioSystem;
public class Main {
  public static void main(String[] argv) throws Exception {
    AudioFileFormat fformat = AudioSystem.getAudioFileFormat(new File(
        "audiofile"));
    fformat = AudioSystem.getAudioFileFormat(new URL(
        "http://hostname/audiofile"));
    if (fformat.getType() == AudioFileFormat.Type.AIFC) {
    } else if (fformat.getType() == AudioFileFormat.Type.AIFF) {
    } else if (fformat.getType() == AudioFileFormat.Type.AU) {
    } else if (fformat.getType() == AudioFileFormat.Type.WAVE) {
    }
  }
}





Determining the Position of a Sampled Audio Player

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
public class Main {
  public static void main(String[] argv) throws Exception {
    DataLine.Info info = null;
    Clip clip = (Clip) AudioSystem.getLine(info);
    double timeInSeconds = clip.getMicrosecondPosition() / 1000000.0d;
  }
}





Determining When a Sampled Audio Player Has Finished Playing

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
public class Main {
  public static void main(String[] argv) throws Exception {
    DataLine.Info info = null;
    Clip clip = (Clip) AudioSystem.getLine(info);
    clip.addLineListener(new LineListener() {
      public void update(LineEvent evt) {
        if (evt.getType() == LineEvent.Type.STOP) {
        }
      }
    });
  }
}





Float Control Component

import javax.sound.sampled.FloatControl;
public class Main {
  FloatControl control;
  public Main(FloatControl c) {
    control = c;
    control.setValue(3);
  }
}





Load image and sound from Jar file

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.Line;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Main extends JFrame {
  JButton button;
  ImageIcon buttonIcon;
  Clip buhClip;
  public Main() throws Exception {
    URL imageURL = getClass().getClassLoader().getResource("images/k.jpeg");
    buttonIcon = new ImageIcon(imageURL);
    button = new JButton("Click to Buh!", buttonIcon);
    button.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        if (buhClip != null) {
          buhClip.setFramePosition(0);
          buhClip.start();
        } else
          System.out.println("Couldn"t load sound");
      }
    });
    getContentPane().add(button);
    URL soundURL = getClass().getClassLoader().getResource("sounds/b.aiff");
    Line.Info linfo = new Line.Info(Clip.class);
    Line line = AudioSystem.getLine(linfo);
    buhClip = (Clip) line;
    AudioInputStream ais = AudioSystem.getAudioInputStream(soundURL);
    buhClip.open(ais);
  }
  public static final void main(String[] args) throws Exception {
    JFrame frame = new Main();
    frame.pack();
    frame.setVisible(true);
  }
}





Loading and Playing Sampled Audio

import java.io.File;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
public class Main {
  public static void main(String[] argv) throws Exception {
    AudioInputStream stream = AudioSystem.getAudioInputStream(new File(
        "audiofile"));
    // From URL
    // stream = AudioSystem.getAudioInputStream(new URL(
    // "http://hostname/audiofile"));
    AudioFormat format = stream.getFormat();
    if (format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) {
      format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format
          .getSampleRate(), format.getSampleSizeInBits() * 2, format
          .getChannels(), format.getFrameSize() * 2, format.getFrameRate(),
          true); // big endian
      stream = AudioSystem.getAudioInputStream(format, stream);
    }
    DataLine.Info info = new DataLine.Info(Clip.class, stream.getFormat(),
        ((int) stream.getFrameLength() * format.getFrameSize()));
    Clip clip = (Clip) AudioSystem.getLine(info);
    clip.open(stream);
    clip.start();
  }
}





Make your own Java Media Player to play media files

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.media.*;
public class MediaPlayerDemo extends JFrame {
  public static void main(String args[]) {
    Player player;
    File file = new File("yourFile");
    player = Manager.createPlayer(file.toURI().toURL());
//    player.addControllerListener(new EventHandler());
    player.start(); // start player
    
    player.close();
    Component visual = player.getVisualComponent();
    Component control = player.getControlPanelComponent();
  }
}





Play an audio file from a JAR file

import java.io.InputStream;
import sun.audio.AudioPlayer;
import sun.audio.AudioStream;
public class Main {
  public static void main(String args[]) throws Throwable {
    InputStream in = Main.class.getResourceAsStream(args[0]);
    AudioStream as = new AudioStream(in);
    AudioPlayer.player.start(as);
    Thread.sleep(5000);
  }
}





Playing Streaming Sampled Audio

import java.io.File;
import java.net.URL;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
public class Main {
  public static void main(String[] argv) throws Exception {
    AudioInputStream stream = AudioSystem.getAudioInputStream(new File(
        "audiofile"));
//    stream = AudioSystem.getAudioInputStream(new URL(
  //      "http://hostname/audiofile"));
    AudioFormat format = stream.getFormat();
    if (format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) {
      format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format
          .getSampleRate(), format.getSampleSizeInBits() * 2, format
          .getChannels(), format.getFrameSize() * 2, format.getFrameRate(),
          true); // big endian
      stream = AudioSystem.getAudioInputStream(format, stream);
    }
    SourceDataLine.Info info = new DataLine.Info(SourceDataLine.class, stream
        .getFormat(), ((int) stream.getFrameLength() * format.getFrameSize()));
    SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
    line.open(stream.getFormat());
    line.start();
    int numRead = 0;
    byte[] buf = new byte[line.getBufferSize()];
    while ((numRead = stream.read(buf, 0, buf.length)) >= 0) {
      int offset = 0;
      while (offset < numRead) {
        offset += line.write(buf, offset, numRead - offset);
      }
    }
    line.drain();
    line.stop();
  }
}





Setting the Volume of a Sampled Audio Player

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.BooleanControl;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
public class Main {
  public static void main(String[] argv) throws Exception {
    DataLine.Info info = null;
    Clip clip = (Clip) AudioSystem.getLine(info);
    FloatControl gainControl = (FloatControl) clip
        .getControl(FloatControl.Type.MASTER_GAIN);
    double gain = .5D; // number between 0 and 1 (loudest)
    float dB = (float) (Math.log(gain) / Math.log(10.0) * 20.0);
    gainControl.setValue(dB);
    BooleanControl muteControl = (BooleanControl) clip
        .getControl(BooleanControl.Type.MUTE);
    muteControl.setValue(true);
    muteControl.setValue(false);
  }
}





This is a simple program to record sounds and play them back

/*
 *
 * Copyright (c) 1999 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free,
 * license to use, modify and redistribute this software in 
 * source and binary code form, provided that i) this copyright
 * notice and license appear on all copies of the software; and 
 * ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty
 * of any kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS
 * AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE 
 * HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR 
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT
 * WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT
 * OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS
 * OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY
 * TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGES.
 This software is not designed or intended for use in on-line
 control of aircraft, air traffic, aircraft navigation or
 aircraft communications; or in the design, construction,
 operation or maintenance of any nuclear facility. Licensee 
 represents and warrants that it will not use or redistribute 
 the Software for such purposes.
 */
/*  The above copyright statement is included because this 
 * program uses several methods from the JavaSoundDemo
 * distributed by SUN. In some cases, the sound processing methods
 * unmodified or only slightly modified.
 * All other methods copyright Steve Potts, 2002
 */
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
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.TargetDataLine;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.border.SoftBevelBorder;
/**
 * SimpleSoundCapture Example. This is a simple program to record sounds and
 * play them back. It uses some methods from the CapturePlayback program in the
 * JavaSoundDemo. For licensizing reasons the disclaimer above is included.
 * 
 * @author Steve Potts
 */
public class SimpleSoundCapture extends JPanel implements ActionListener {
  final int bufSize = 16384;
  Capture capture = new Capture();
  Playback playback = new Playback();
  AudioInputStream audioInputStream;
  JButton playB, captB;
  JTextField textField;
  String errStr;
  double duration, seconds;
  File file;
  public SimpleSoundCapture() {
    setLayout(new BorderLayout());
    EmptyBorder eb = new EmptyBorder(5, 5, 5, 5);
    SoftBevelBorder sbb = new SoftBevelBorder(SoftBevelBorder.LOWERED);
    setBorder(new EmptyBorder(5, 5, 5, 5));
    JPanel p1 = new JPanel();
    p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
    JPanel p2 = new JPanel();
    p2.setBorder(sbb);
    p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));
    JPanel buttonsPanel = new JPanel();
    buttonsPanel.setBorder(new EmptyBorder(10, 0, 5, 0));
    playB = addButton("Play", buttonsPanel, false);
    captB = addButton("Record", buttonsPanel, true);
    p2.add(buttonsPanel);
    p1.add(p2);
    add(p1);
  }
  public void open() {
  }
  public void close() {
    if (playback.thread != null) {
      playB.doClick(0);
    }
    if (capture.thread != null) {
      captB.doClick(0);
    }
  }
  private JButton addButton(String name, JPanel p, boolean state) {
    JButton b = new JButton(name);
    b.addActionListener(this);
    b.setEnabled(state);
    p.add(b);
    return b;
  }
  public void actionPerformed(ActionEvent e) {
    Object obj = e.getSource();
    if (obj.equals(playB)) {
      if (playB.getText().startsWith("Play")) {
        playback.start();
        captB.setEnabled(false);
        playB.setText("Stop");
      } else {
        playback.stop();
        captB.setEnabled(true);
        playB.setText("Play");
      }
    } else if (obj.equals(captB)) {
      if (captB.getText().startsWith("Record")) {
        capture.start();
        playB.setEnabled(false);
        captB.setText("Stop");
      } else {
        capture.stop();
        playB.setEnabled(true);
      }
    }
  }
  /**
   * Write data to the OutputChannel.
   */
  public class Playback implements Runnable {
    SourceDataLine line;
    Thread thread;
    public void start() {
      errStr = null;
      thread = new Thread(this);
      thread.setName("Playback");
      thread.start();
    }
    public void stop() {
      thread = null;
    }
    private void shutDown(String message) {
      if ((errStr = message) != null) {
        System.err.println(errStr);
      }
      if (thread != null) {
        thread = null;
        captB.setEnabled(true);
        playB.setText("Play");
      }
    }
    public void run() {
      // make sure we have something to play
      if (audioInputStream == null) {
        shutDown("No loaded audio to play back");
        return;
      }
      // reset to the beginnning of the stream
      try {
        audioInputStream.reset();
      } catch (Exception e) {
        shutDown("Unable to reset the stream\n" + e);
        return;
      }
      // get an AudioInputStream of the desired format for playback
      AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
      float rate = 44100.0f;
      int channels = 2;
      int frameSize = 4;
      int sampleSize = 16;
      boolean bigEndian = true;
      AudioFormat format = new AudioFormat(encoding, rate, sampleSize, channels, (sampleSize / 8)
          * channels, rate, bigEndian);
      AudioInputStream playbackInputStream = AudioSystem.getAudioInputStream(format,
          audioInputStream);
      if (playbackInputStream == null) {
        shutDown("Unable to convert stream of format " + audioInputStream + " to format " + format);
        return;
      }
      // define the required attributes for our line,
      // and make sure a compatible line is supported.
      DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
      if (!AudioSystem.isLineSupported(info)) {
        shutDown("Line matching " + info + " not supported.");
        return;
      }
      // get and open the source data line for playback.
      try {
        line = (SourceDataLine) AudioSystem.getLine(info);
        line.open(format, bufSize);
      } catch (LineUnavailableException ex) {
        shutDown("Unable to open the line: " + ex);
        return;
      }
      // play back the captured audio data
      int frameSizeInBytes = format.getFrameSize();
      int bufferLengthInFrames = line.getBufferSize() / 8;
      int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
      byte[] data = new byte[bufferLengthInBytes];
      int numBytesRead = 0;
      // start the source data line
      line.start();
      while (thread != null) {
        try {
          if ((numBytesRead = playbackInputStream.read(data)) == -1) {
            break;
          }
          int numBytesRemaining = numBytesRead;
          while (numBytesRemaining > 0) {
            numBytesRemaining -= line.write(data, 0, numBytesRemaining);
          }
        } catch (Exception e) {
          shutDown("Error during playback: " + e);
          break;
        }
      }
      // we reached the end of the stream.
      // let the data play out, then
      // stop and close the line.
      if (thread != null) {
        line.drain();
      }
      line.stop();
      line.close();
      line = null;
      shutDown(null);
    }
  } // End class Playback
  /**
   * Reads data from the input channel and writes to the output stream
   */
  class Capture implements Runnable {
    TargetDataLine line;
    Thread thread;
    public void start() {
      errStr = null;
      thread = new Thread(this);
      thread.setName("Capture");
      thread.start();
    }
    public void stop() {
      thread = null;
    }
    private void shutDown(String message) {
      if ((errStr = message) != null && thread != null) {
        thread = null;
        playB.setEnabled(true);
        captB.setText("Record");
        System.err.println(errStr);
      }
    }
    public void run() {
      duration = 0;
      audioInputStream = null;
      // define the required attributes for our line,
      // and make sure a compatible line is supported.
      AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
      float rate = 44100.0f;
      int channels = 2;
      int frameSize = 4;
      int sampleSize = 16;
      boolean bigEndian = true;
      AudioFormat format = new AudioFormat(encoding, rate, sampleSize, channels, (sampleSize / 8)
          * channels, rate, bigEndian);
      DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
      if (!AudioSystem.isLineSupported(info)) {
        shutDown("Line matching " + info + " not supported.");
        return;
      }
      // get and open the target data line for capture.
      try {
        line = (TargetDataLine) AudioSystem.getLine(info);
        line.open(format, line.getBufferSize());
      } catch (LineUnavailableException ex) {
        shutDown("Unable to open the line: " + ex);
        return;
      } catch (SecurityException ex) {
        shutDown(ex.toString());
        //JavaSound.showInfoDialog();
        return;
      } catch (Exception ex) {
        shutDown(ex.toString());
        return;
      }
      // play back the captured audio data
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      int frameSizeInBytes = format.getFrameSize();
      int bufferLengthInFrames = line.getBufferSize() / 8;
      int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
      byte[] data = new byte[bufferLengthInBytes];
      int numBytesRead;
      line.start();
      while (thread != null) {
        if ((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) {
          break;
        }
        out.write(data, 0, numBytesRead);
      }
      // we reached the end of the stream.
      // stop and close the line.
      line.stop();
      line.close();
      line = null;
      // stop and close the output stream
      try {
        out.flush();
        out.close();
      } catch (IOException ex) {
        ex.printStackTrace();
      }
      // load bytes into the audio input stream for playback
      byte audioBytes[] = out.toByteArray();
      ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);
      audioInputStream = new AudioInputStream(bais, format, audioBytes.length / frameSizeInBytes);
      long milliseconds = (long) ((audioInputStream.getFrameLength() * 1000) / format
          .getFrameRate());
      duration = milliseconds / 1000.0;
      try {
        audioInputStream.reset();
      } catch (Exception ex) {
        ex.printStackTrace();
        return;
      }
    }
  } // End class Capture
  public static void main(String s[]) {
    SimpleSoundCapture ssc = new SimpleSoundCapture();
    ssc.open();
    JFrame f = new JFrame("Capture/Playback");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.getContentPane().add("Center", ssc);
    f.pack();
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    int w = 360;
    int h = 170;
    f.setLocation(screenSize.width / 2 - w / 2, screenSize.height / 2 - h / 2);
    f.setSize(w, h);
    f.show();
  }
}