Sound-Recording Hardware
Bear in mind that the quality of the recorded sound is dictated by the cost of the hardware. To record sound, you need at least a microphone. You also can use internal speakers, but for better results you might try a set of external speakers. My own configuration uses a Skype phone into which I speak during recording. Because this device also includes a listening capability, I can use it to listen to the playback. If you already use Skype, you’re ready to start making recordings with the Java Sound API.
If you’re in any doubt about your Skype setup, just use the test Skype call facility to verify your settings. (The latter is a button option available in the Skype client program.) Assuming that your hardware is configured correctly, you should be able to record and capture some audio. Given that you’re using a Skype phone, the recording is most likely going to be your own voice!
Just to show you that it’s easy to record sound programmatically, Listing 1 illustrates a complete Java class for audio recording by using the Java Sound API.
Listing 1 An audio capture class.
public class AudioCapture extends Thread { private TargetDataLine dataLine; private AudioFileFormat.Type audioFileType; private AudioInputStream incomingStream; private File generatedFile; public AudioCapture(TargetDataLine line, AudioFileFormat.Type requiredFileType, File file){ dataLine = line; incomingStream = new AudioInputStream(line); audioFileType = requiredFileType; generatedFile = file;} public void startCapture(){ dataLine.start(); super.start();} public void stopCapture(){ dataLine.stop(); dataLine.close();} public void run(){ try{ AudioSystem.write( incomingStream, audioFileType, generatedFile);} catch (IOException e){ e.printStackTrace();} } public static void main(String[] args){ String strFilename = "captureFile.wav"; File outputFile = new File(strFilename); AudioFormat audioFormat = new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, 22050.0F, 16, 2, 4, 22050.0F, false); DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat); TargetDataLine targetDataLine = null; try{ targetDataLine = (TargetDataLine) AudioSystem.getLine(info); targetDataLine.open(audioFormat);} catch (LineUnavailableException e){ System.out.println("Unable to acquire an audio recording line"); e.printStackTrace(); System.exit(1);} System.out.println("AudioFormat settings: " + audioFormat.toString()); AudioFileFormat.Type targetType = AudioFileFormat.Type.WAVE; AudioCapture recorder = new AudioCapture( targetDataLine, targetType, outputFile); recorder.startCapture(); System.out.println("Starting the recording now..."); System.out.println("Please press to stop the recording."); try{ System.in.read();} catch (IOException e){ e.printStackTrace();} recorder.stopCapture(); System.out.println("Capture stopped.");} }
Compile this code with the following command:
javac AudioCapture.java
and run it with this command:
java AudioCapture
The following lines are displayed, prompting you to record some sound:
AudioFormat settings: PCM_SIGNED 22050.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian Starting the recording now... Please press <Enter> to stop the recording.
As soon as you press Enter, the recording stops. For simplicity in getting up and running, I’ve hardcoded a sound file called captureFile.wav (included in the source.zip file for this article). [1]
After running the program and making your recording, you should see the captureFile.wav file appear in the execution folder.
Brief Description of the Code
The program in Listing 1 uses the following interfaces and classes:
- TargetDataLine. An instance of TargetDataLine is a type of DataLine from which audio data can be read. In my case, the data line gets its sound data from the microphone of my Skype phone. Technically, the device is implemented as a mixer that writes to the target data line (refer to Figure 1 for an illustration of the mixer).
- AudioFileFormat. An instance of AudioFileFormat describes an audio file. This description includes the file type, the file length in bytes, the length in sample frames of the audio data in the file, and finally the format of the incoming audio data.
- AudioInputStream. An instance of AudioInputStream is an input stream with a specified audio format and length. The length is expressed in sample frames, not bytes. Several methods are provided for reading either a specified or an unspecified number of bytes from the stream. To help with recording, the audio input stream keeps track of the last byte that was read. It is also possible to skip over an arbitrary number of bytes to get to a later position for reading.
- File. An instance of the File class is used to store the recorded audio data.
- AudioSystem. Finally, an instance of the AudioSystem class provides the entry point to the sampled-audio system resources, so that you can query and access the mixers installed on the system. The AudioSystem class includes a number of methods for converting audio data between various formats, and for translating between audio files and streams. It also provides a method for obtaining a line directly from the AudioSystem without dealing explicitly with mixers. You can see where this class is used in the following line from Listing 1:
targetDataLine = (TargetDataLine) AudioSystem.getLine(info);
Now, how do you play the captured audio?
It’s Playback Time
It’s simple to play the captured audio—just double-click the file captureFile.wav. If you’re running Windows, this action should launch a media player and you should hear your recording played through your Skype phone (or whatever hardware you use). That’s it—very simple.