Java Programming Notes # 2024
- Preface
- Preview
- Discussion and Sample
Code - Run the Program
- Summary
- What’s Next?
- Complete Program Listing
Preface
This series of lessons is designed to teach you how to use the Java
Sound API. The first lesson in the series was entitled Java Sound,
An Introduction. The previous lesson was entitled Java Sound,
Creating, Playing, and Saving Synthetic Sounds.
Two types of audio data
Two different types of audio data are supported by the Java Sound API:
- Sampled audio data
- Musical Instrument Digital Interface (MIDI) data
The two types of audio data are very different. I am concentrating
on sampled audio data at this point in time. I will defer my discussion
of MIDI until later.
Viewing tip
You may find it useful to open another copy of this lesson in a separate
browser window. That will make it easier for you to scroll back and
forth among the different listings and figures while you are reading about
them.
Supplementary material
I recommend that you also study the other lessons in my extensive collection
of online Java tutorials. You will find those lessons published at Gamelan.com. However,
as of the date of this writing, Gamelan doesn’t maintain a consolidated index
of my Java tutorial lessons, and sometimes they are difficult to locate there.
You will find a consolidated index at www.DickBaldwin.com.
Material in earlier lessons
Earlier lessons in this series showed you how to:
- Create, play, and save synthetic sounds, making use of the features
of the java.nio package to help with the byte manipulations. - Use methods of the AudioSystem class to write more robust audio
programs. - Play back audio files, including those that you create using a Java
program, and those that you acquire from other sources. - Capture microphone data into audio files types of your own choosing.
- Capture microphone data into a ByteArrayOutputStream object.
- Use the Sound API to play back previously captured audio data.
- Identify the mixers available on your system.
- Specify a particular mixer for use in the acquisition of audio
data from a microphone. - Understand the use of lines and mixers in the Java Sound API.
This lesson will show you how to perform file conversions among different
audio file types.
Preview
Audio file type is different from audio encoding
Numerous audio file types have been defined in recent years, including
AU files, AIF files, and WAV files. However, when trying to determine
if a particular audio file will be satisfactory for a particular application,
simply knowing the file type isn’t sufficient. You must also know
how the audio data is encoded within the file.
Stated simply, the file type specification indicates how the bytes are
physically arranged within the file. The encoding specification indicates
how the audio information is arranged within the bytes. Not all file
types can accommodate all encodings. However, many file types can
accommodate several different encodings.
As it turns out, file types are the less complex of the two topics.
I will deal with file types in this lesson. I will begin dealing with
encodings in the next lesson.
Information on different file types
Here are descriptions of some of the file types supported by Sun’s Java,
as found at the High-Tech
Dictionary of File Types:
- AU – A sound file format used on Sun Microsystems or other UNIX computers.
- AIF – Audio Interchange File Format or AIFF (filename extension).
A format developed by Apple Computer for storing high-quality sampled
audio and musical instrument information. It can be played on PC and Mac.
(Note that the Sun Java API treats the common filename extension
for this type as AIF.) - WAV – Sound file. (As you can see, the HighTech Dictionary
doesn’t have much to say about this file type. I will add that most
of the sound files that are provided by Microsoft in a typical Windows
installation are WAV files.)
Format descriptions
You can view a technical description of the format of an AU file, including
information about how the bytes are arranged in the file, at Header
file for Audio, .au.
You can view a similar technical description for an AIFF file format
here. Finally,
you can view a technical description of the format of a WAV file at
The Canonical WAVE File Format.
Of course, if you fire up your Google
search engine, you can find many other descriptions of these and other
file formats as well.
General information about sampled sound
You will find some very interesting information about sampled sound
published by Marc Boots-Ebenfield at Sound
Formats. Included on the web site is the following factoid regarding
CD quality music.
“On a Music CD the music is sampled at 44.1 KHz using 16 bit words
or 705,600 bits for each second of sound. At 8 bits to the byte that
would mean that 1 second of CD quality music would occupy 88,200 bytes
or 88 Kb of your floppy disc which holds 1.2 Mb of data. That means
that you could hold 13 seconds of CD quality music on a floppy- (uncompressed)!”
If the above estimate is correct, then about fifteen floppy disks would
be required to contain a typical three-minute song in uncompressed CD
quality format. (That fact will be more important in the future
lessons on encoding than in this lesson.)
A non-technical aside
As another interesting factoid, The American Heritage®
Book of English Usage is not very fond of this usage of the word factoid.
Discussion
and Sample Code
The user interface
The user interface for this program is very simple. This program
is designed to be executed from the command line as follows:
Usage: java AudioFileConvert01 inputFile outputFile
The program named AudioFileConvert01
Before getting into the details of the program code, I will describe
the program and show you some examples produced by running the program.
This program demonstrates the ability to write a Java program to convert
one audio file type to a different audio file type. Run the program
by entering the following at the command line:
java AudioFileConvert01 inputFile
outputFile
Input and output file types
The type of output file that is created depends on the output file name
extension, such as au, wav, or aif.
On the other hand, the type of the input file does not depend on the
input file name or extension. The actual type of the input file is
determined by the program irrespective of the name of the file or the extension
given to that file.
Playback of the output file
You should be able to play the output file with any standard media player
that can handle the file type, or with a program written in Java, such as
the program named AudioPlayer02 that was developed in an earlier lesson.
Operational examples
The following paragraphs show sample screen outputs for different input
and output file types. Note that line breaks were manually inserted
to force the material to fit in this narrow publication format.
Valid input file with invalid file extension
In the first example, shown in Figure 1, a valid input wav file
named ringout was forced to have the invalid extension .txt.
However, the program successfully determined the type of the wav
file on the fly, and the wav file was successfully converted to an
au file.
(You may recognize the primary name of this file as being one of
the sound files commonly included in a standard Windows installation.
I simply made a copy of the file named ringout.wav and changed the
extension before running this experiment.)
java AudioFileConvert01 ringout.txt junk.au Input file: ringout.txt Output file: junk.au Output type: au Output type is supported Input file format: WAVE (.wav) file, byte length: 5212, data format: PCM_UNSIGNED, 11025.0 Hz, 8 bit, mono, audio data Bytes written: 5191 Output file format: AU (.au) file, byte length: 5191, data format: PCM_SIGNED, 11025.0 Hz, 8 bit, mono, audio data, frame length: 5167 Figure 1 |
Encoding information is displayed
You will see the code that produced the output in Figure 1 later when
I discuss the program. As you can see from the output, the code
in this program gets and displays encoding information (PCM_UNSIGNED,
8 bit, mono, etc.) on both the input file and the output file in addition
to the file type. However, this program makes no attempt to purposely
change the encoding. (As I mentioned earlier, I will begin
dealing with encoding in the next lesson.)
Conversion of an AU file to a WAV file
In the example shown in Figure 2, the input file was a stereo au
file produced by a sample program from an earlier lesson. The au
file was successfully converted to a wav file.
java AudioFileConvert01 junk3.au junk.wav Input file: junk3.au Output file: junk.wav Output type: wav Output type is supported Input file format: AU (.au) file, byte length: 64024, data format: PCM_SIGNED, 16000.0 Hz, 16 bit, stereo, big-endian, audio data, frame length: 16000 Bytes written: 64044 Output file format: WAVE (.wav) file, byte length: 64044, data format: PCM_SIGNED, 16000.0 Hz, 16 bit, stereo, little-endian, audio data Figure 2 |
The fact that these files are stereo (two-channel) files is indicated
by the encoding information that is displayed in Figure 2.
Conversion of a WAV file to an AIF file
A standard Windows monaural wav file was successfully converted
to an aif file, as shown in Figure 3
java AudioFileConvert01 ringout.wav junk.aif Input file: ringout.wav Output file: junk.aif Output type: aif Output type is supported Input file format: WAVE (.wav) file, byte length: 5212, data format: PCM_UNSIGNED, 11025.0 Hz, 8 bit, mono, audio data Bytes written: 5221 Output file format: AIFF (.aif) file, byte length: 5221, data format: PCM_SIGNED, 11025.0 Hz, 8 bit, mono, audio data, frame length: 5167 Figure 3 |
An unsupported output file type
In the example shown in Figure 4, the specified output file type, xyz,
is not supported by the Java Sound API (nor by any other system that
I am aware of). Therefore, the program aborted, providing a list
of the output file types that are supported for writing by the system.
java AudioFileConvert01 junk3.au junk.xyz Input file: junk3.au Output file: junk.xyz Output type: xyz Output type not supported. Supported audio file types: au aif wav Figure 4 |
Note that the Java implementation on my system at the time of this writing
only supports file types au, aif, and wav.
An unsupported input file type
In the example shown in Figure 5, the input file claimed by virtue
of its name and extension to be a wav file. However, it was
not a valid audio file. Rather, it was simply a text file that I renamed
to cause it to impersonate a wav file. This caused the program
to throw an UnsupportedAudioFileException and abort.
Once again, the program determined the type of the input file by examining
the contents of the file, and not by examining the file’s name or extension.
java AudioFileConvert01 invalidFile.wav junk.au Input file: invalidFile.wav Output file: junk.au Output type: au Output type is supported javax.sound.sampled. UnsupportedAudioFileException: could not get audio input stream from input stream at javax.sound.sampled.AudioSystem. getAudioInputStream(AudioSystem.java:756) at AudioFileConvert01. main(AudioFileConvert01.java:84) Figure 5 |
Getting usage information
In Figure 6, the program was run with no command-line arguments, causing
the program to provide usage information and abort.
java AudioFileConvert01 Usage: java AudioFileConvert01 inputFile outputFile Figure 6 |
This program was tested using SDK 1.4.1 under WinXP
The class named AudioFileConvert01
The controlling class for the program begins in Listing 1. As usual,
I will discuss the program in fragments. You can view a listing of
the entire program in Listing 11 near the end of the lesson.
The program is relatively straightforward consisting of the main
method and the following static methods (these methods were declared
static so that they can be invoked from inside the main method):
- getTargetTypesSupported – returns a list of the audio file
types that can be written by the system. - getTargetType – returns the type of a specified output file
based on the filename extension. - showFileType – Examines a File object representing a
physical audio file and displays information about the file.
The main method
Listing 1 contains the beginning of the main method. The
code in Listing 1 examines the number of command-line arguments entered
by the user, and displays usage information if the user didn’t enter any
arguments.
public class AudioFileConvert01{ |
In addition, the code in Listing 1 displays the input and output file
names provided by the user when those file names are entered as command-line
arguments.
Get and test output file type
The output file type is determined by the filename extension provided
by the user. The code in Listing 2 isolates the filename extension
as type String and displays the extension on the screen.
String outputTypeStr = |
More importantly, the code in Listing 2 invokes the getTargetType
method, passing the filename extension as a String parameter to that
method.
The getTargetType method
The getTargetType method checks to see if the system is capable
of writing the file type indicated by the extension. If so, it returns
an AudioFileFormat.Type object matching that extension. If
not, it returns null.
At this point, I am going to put the main method on hold and discuss
the method named getTargetType.
The AudioFileFormat.Type class
Listing 3 contains the entire method named getTargetType.
private static AudioFileFormat.Type |
The first thing to note about the code in Listing 3 is that the
getTargetType method returns a reference to an object
of type AudioFileFormat.Type.
(In case you are unfamiliar with the notation where there is a
period in a class name, this indicates that the Type class is an
inner class of the class named AudioFileFormat. If you are
unfamiliar with inner classes, see the tutorial lessons on that topic on
my web site.)
What does Sun have to say?
Here is what Sun has to say about this class:
“An instance of the Type class represents one of the standard
types of audio files. Static instances are provided for the common types.”
Static instances are provided for the following types:
- AIFC
- AIFF
- AU
- SND
- WAVE
It is interesting to note that even though five different audio file
types are identified as the common types in this class, only three
of those types are currently supported for writing on my machine running
SDK 1.4.1 under WinXP.
An array of AudioFileFormat.Type object references
The code in Listing 3 invokes the method named getAudioFileTypes,
which is a static method of the AudioSystem class. This
method returns a list containing “the file types for which file writing
support is provided by the system.” This list is stored in an
array of type AudioFileFormat.Type.
(Listing 3 contains a statement with a call to the println
method that has been commented out. When this statement is enabled
on my system, it reports that the length of the array is three, indicating
that only three file types are currently supported for writing on my System.
You will see the names of those three types later.)
The getExtension method
The AudioFileFormat.Type class provides a method named getExtension,
which returns “the common file name extension” for an object of the
type. The code in Listing 3 uses a for loop to search the array
of AudioFileFormat.Type objects looking for a match to the file name
extension received as an incoming parameter by the getTargetType
method.
If a match is found, the AudioFileFormat.Type object corresponding
to that match is returned by the getTargetType method. Otherwise,
null is returned by the method.
Testing the return value
Returning our attention to the code in the main method, the code
in Listing 4 tests to determine if a null value was returned
by the getTargetType method. If not, the program displays the
message:
Output type is supported
//Continue with main method |
If a null value was returned by the getTargetType method,
the program displays the following message and then invokes the method named
getTargetTypesSupported to display a list of the file types that
are supported for writing by the system.
Output type not supported.
The getTargetTypesSupported method
The purpose of the method named getTargetTypesSupported is to
get and display a list of the file types supported for writing by the system.
Once again, I’m going to put the main method on hold while I discuss
the method named getTargetTypesSupported, shown in Listing 5.
private static void getTargetTypesSupported(){ |
Get and display common filename extensions
The code in Listing 5 shouldn’t require much in the way of an explanation.
This code is very similar to the code in Listing 3. In Listing 5,
however, after getting an array of AudioFileFormat.Type objects representing
the file types supported for writing by the system, the code simply gets
and displays the common filename extension for each of those types.
For the example discussed previously (see Figure 4) where I purposely
told the program to write an unsupported output file type (xyz), the
code in Listings 4 and 5 produced the output shown in Figure 7.
Output type not supported. Supported audio file types: au aif wav Figure 7 |
(Note that the list of supported file types in Figure 7 includes
only three of the five types identified by static instances of the
AudioFileFormat.type class.)
The input file type
Returning once again to the main method, the code in Listing 6
begins dealing with the input file.
(Note that the determination of the input file type does not depend
on the file name or extension. Rather, the program determines the
type of the input file by extracting information about the file from the
information contained in the file itself.)
Get an AudioInputStream object
The code in Listing 6 begins by getting a File object that represents
the input file.
//Continue with main method |
Then the code in Listing 6 uses that File object to get an
AudioInputStream object that can be used to read the audio data in the
input file.
I have discussed code involving AudioInputStream objects in several
previous lessons. Therefore, I won’t bore you by discussing it again
here.
Display file type information
The code in Listing 7 invokes the showFileType method for the
purpose of displaying information about the input file type.
System.out.println("Input file format:"); |
The showFileType method
Once again, I’m going to put the main method on hold while I discuss
the method named showFileType, shown in Listing 8.
private static void showFileType(File file){ |
There isn’t much to the showFileType method. It simply invokes
the method named getAudioFileFormat, which is a static method
of the AudioSystem class, passing the File object that represents
the input file as a parameter to the method.
The getAudioFileFormat method
Here is what Sun has to say about the getAudioFileFormat method.
“Obtains the audio file format of the specified File. The File must
point to valid audio file data.”
This method returns an object of type AudioFileFormat, whose reference
is passed to the println method for display.
The AudioFileFormat class
Here is what Sun has to say about an object of this class:
“An instance of the AudioFileFormat class describes an audio
file, including the file type, the file’s length in bytes, the length in
sample frames of the audio data contained in the file, and the format of
the audio data.”
As is frequently the case, this class has an overridden toString
method, which facilitates displaying information about the contents of the
object.
The screen output for a supported input file
type
Figure 8 shows the screen output produced by Listings 7 and 8 for a supported
audio input file of type WAV:
Input file format: WAVE (.wav) file, byte length: 5212, data format: PCM_UNSIGNED, 11025.0 Hz, 8 bit, mono, audio data Figure 8 |
Note that this output contains the number of channels and the sampling
frequency, which is not mentioned in the quotation from sun in the previous
section.
The screen output for an unsupported input file
type
Figure 9 shows the screen output produced by Listing 6 when an attempt
was made to get an AudioInputStream object on a file that was not
a valid audio file. (It was a text file of the type produced by
the Windows NotePad program.)
javax.sound.sampled. UnsupportedAudioFileException: could not get audio input stream from input stream at javax.sound.sampled.AudioSystem. getAudioInputStream(AudioSystem.java:756) at AudioFileConvert01. main(AudioFileConvert01.java:84) Figure 9 |
In this case, the program didn’t even make it far enough to invoke the
showFileType method for the purpose of displaying information about
the file. Rather, it threw an UnsupportedAudioFileException
when the attempt was made to get an AudioInputStream object on
the input file.
The bottom line on file conversion
Returning once more to the main method, the code in Listing 9
illustrates the bottom line on audio file conversion in Java.
(Note that I deleted the try and catch from Listing 9 in order to
simplify the presentation. You can view that code in Listing 11
near the end of the lesson.)
//Continue with main method |
The write method of the AudioSystem class
As it turns out, doing audio file conversion using the Java Sound API
is relatively simple, as long as you aren’t trying to change encodings in
the process. (As mentioned earlier, I will begin discussing encodings
in the next lesson.)
(Much of the code in this program was provided to help you to understand
what is going on. A version of the program named AudioFileConvert02,
with most of the unnecessary code deleted, is shown in Listing 12 near the
end of the lesson.)
The basics of file conversion
All that is really necessary to do a file conversion using the Java Sound
API is:
- Get the names of the input and output files.
- Get an object of the class AudioFileFormat.Type, which defines
the type of the output file. - Get an AudioInputStream object on the input file.
- Invoke the method named write shown in Listing 9 passing the
above information as parameters to the write method.
This will cause the input file to be read, and will cause the data from
the input file to be written into the output file in the specified format.
The write method
Here is what Sun has to say about the write method used in Listing
9, which is a static method of the AudioSystem class:
“Writes a stream of bytes representing an audio file of the specified
file type to the external file provided”
Can be more general
In reality, this code could be made much more general than it is in this
program. For example, the AudioInputStream object doesn’t have
to be based on a file. The AudioInputStream object could be
based on a TargetDataLine object, or on any InputStream object
capable of supplying audio data according to a known AudioFormat.
Similarly, another overloaded version of the write method allows
you to replace the File object in the third parameter with any OutputStream
object capable of accepting a stream of audio data in a specified format.
The number of bytes written into the output
file
The write method returns the number of bytes actually written.
This value is displayed on the screen by the last statement in Listing
9.
Information about the output file format
The code in Listing 10 displays information about the output file format.
System.out.println("Output file format:"); |
Figure 10 shows a sample of the output produced by Listing 10 for one
of the example cases discussed earlier in this lesson:
Output file format: WAVE (.wav) file, byte length: 64044, data format: PCM_SIGNED, 16000.0 Hz, 16 bit, stereo, little-endian, audio data Figure 10 |
Run the Program
At this point, you may find it useful to compile and run the programs
shown in Listings 11 and 12 near the end of the lesson. Operating
instructions were provided earlier in the section entitled The
user interface.
If you use a media player, such as the Windows Media Player, to play
back your file, be sure to release the old file from the media player before
attempting to create a new file with the same name and extension.
Otherwise, the program will not be able to create the new file, and a runtime
error will occur.
Also be aware that these programs were tested using SDK version 1.4.1.
Therefore, I can’t be certain that they will compile and run correctly
with earlier versions of Java.
Summary
In this lesson, I showed you how to convert audio data from one audio
file type to another. The essential steps involved in making
such a conversion are:
- Get the names of the input and output files.
- Get an object of the class AudioFileFormat.Type, which defines
the type of the output file. - Get an AudioInputStream object on the input file.
- Invoke the method named write shown in Listing 9 passing
the above information as parameters to the write method.
I also explained that this program could be made much more general either
by basing the AudioInputStream object on an InputStream
object other than a file, or by causing the output to be an OutputStream
other than a file.
You should be able to play the output file produced by this program with
any standard media player that can handle the file type, or with a program
written in Java, such as the program named AudioPlayer02 that was developed
in an earlier lesson.
What’s Next?
In the next lesson, I will show you how to use mu-law encoding and decoding
to compress and restore 16-bit linear PCM samples.
Complete Program Listing
Complete listings of the two programs discussed in this lesson are
shown in Listing 11 and Listing 12.
/*File AudioFileConvert01.java |
/*File AudioFileConvert02.java |
Copyright 2003, Richard G. Baldwin. Reproduction in whole or in part
in any form or medium without express written permission from Richard Baldwin
is prohibited.
About the author
Richard Baldwin is a college
professor (at Austin Community College in Austin, TX) and private consultant
whose primary focus is a combination of Java, C#, and XML. In addition to
the many platform and/or language independent benefits of Java and C# applications,
he believes that a combination of Java, C#, and XML will become the primary
driving force in the delivery of structured information on the Web.
Richard has participated in numerous consulting projects and he frequently
provides onsite training at the high-tech companies located in and around
Austin, Texas. He is the author of Baldwin’s Programming Tutorials, which has gained a worldwide
following among experienced and aspiring programmers. He has also published
articles in JavaPro magazine.
Richard holds an MSEE degree from Southern Methodist University and
has many years of experience in the application of computer technology to
real-world problems.
-end-