/*
* Mp3Encoder.java
*
* This file is part of jsresources.org
*/
/*
* Copyright (c) 2000 by Florian Bomers
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
|<--- this code is formatted to fit into 80 columns --->|
*/
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
/** <titleabbrev>Mp3Encoder</titleabbrev>
<title>Encoding an audio file to mp3</title>
<formalpara><title>Purpose</title>
<para>Encodes one or more
PCM audio files, writes the results as mp3 files.</para>
</formalpara>
<formalpara>
<title>Usage</title>
<para>
<cmdsynopsis>
<command>java Mp3Encoder</command>
<arg><option>-q <replaceable>quality</replaceable></option></arg>
<arg><option>-b <replaceable>bitrate</replaceable></option></arg>
<arg><option>-V</option></arg>
<arg><option>-v</option></arg>
<arg><option>-s</option></arg>
<arg><option>-e</option></arg>
<arg><option>-t</option></arg>
<arg rep="repeat" choice="plain"><replaceable class="parameter">pcmfile</replaceable></arg>
</cmdsynopsis>
</para>
</formalpara>
<formalpara><title>Parameters</title>
<variablelist>
<varlistentry>
<term><option>-q <replaceable>quality</replaceable></option></term>
<listitem><para>Quality of output mp3 file. In VBR mode, this affects
the size of the mp3 file. (Default middle)
One of: lowest, low, middle, high, highest.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-b <replaceable>bitrate</replaceable></option></term>
<listitem><para>Bitrate in KBit/s. Useless in VBR mode. (Default 128)
One of: 32 40 48 56 64 80 96 112 128 160 192 224 256 320 (MPEG1)
Or: 8 16 24 32 40 48 56 64 80 96 112 128 144 160 (MPEG2 and MPEG2.5).</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-V</option></term>
<listitem><para>VBR (variable bit rate) mode.
Slower, but potentially better
quality. (Default off)</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-v</option></term>
<listitem><para>Be verbose.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-s</option></term>
<listitem><para>Be silent.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-e</option></term>
<listitem><para>Debugging: Dump stack trace of exceptions.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-t</option></term>
<listitem><para>Debugging: trace execution of converters.</para></listitem>
</varlistentry>
<varlistentry>
<term><option><replaceable class="parameter">pcmfile</replaceable></option></term>
<listitem><para>the name(s) of PCM input file(s).
The output file(s) will be named after the input file(s)
with the extension changed to
<filename>.mp3</filename>.</para></listitem>
</varlistentry>
</variablelist>
</formalpara>
<formalpara><title>Bugs, limitations</title>
<para>
To work cleanly, this program requires JDK 1.5.0 or the latest version of Tritonus.
You have to download and install the
<ulink url="http://sourceforge.net/projects/lame/">LAME</ulink>
mp3 encoder and the
<ulink url="http://www.tritonus.org/plugins.html">Tritonus
mp3enc plug-in</ulink>.</para>
</formalpara>
<para>Too many options...</para>
<formalpara><title>Source code</title>
<para>
<ulink url="Mp3Encoder.java.html">Mp3Encoder.java</ulink>,
<ulink url="http://sourceforge.net/projects/lame/">LAME</ulink>,
<ulink url="http://www.tritonus.org/">Tritonus</ulink>
</para>
</formalpara>
*/
public class Mp3Encoder {
private static boolean DEBUG = false;
private static boolean dumpExceptions=false;
private static boolean traceConverters=false;
private static boolean quiet=false;
private static final AudioFormat.Encoding MPEG1L3 = new AudioFormat.Encoding("MPEG1L3");
private static final AudioFileFormat.Type MP3 = new AudioFileFormat.Type("MP3", "mp3");
private static AudioInputStream getInStream(String filename)
throws IOException {
File file = new File(filename);
AudioInputStream ais = null;
try {
ais = AudioSystem.getAudioInputStream(file);
} catch (Exception e) {
if (dumpExceptions) {
e.printStackTrace();
} else if (!quiet) {
System.out.println("Error: " + e.getMessage());
}
}
if (ais == null) {
throw new IOException("Cannot open \"" + filename + "\"");
}
return ais;
}
public static String stripExtension(String filename) {
int ind = filename.lastIndexOf(".");
if (ind == -1
|| ind == filename.length()
|| filename.lastIndexOf(File.separator) > ind) {
// when dot is at last position,
// or a slash is after the dot, there isn't an extension
return filename;
}
return filename.substring(0, ind);
}
/* first version. Remains here for documentation how to
* get a stream with complete description of the target format.
*/
public static AudioInputStream getConvertedStream2(
AudioInputStream sourceStream,
AudioFormat.Encoding targetEncoding)
throws Exception {
AudioFormat sourceFormat = sourceStream.getFormat();
if (!quiet) {
System.out.println("Input format: " + sourceFormat);
}
// build the output format
AudioFormat targetFormat = new AudioFormat(
targetEncoding,
sourceFormat.getSampleRate(),
AudioSystem.NOT_SPECIFIED,
sourceFormat.getChannels(),
AudioSystem.NOT_SPECIFIED,
AudioSystem.NOT_SPECIFIED,
false); // endianness doesn't matter
// construct a converted stream
AudioInputStream targetStream = null;
if (!AudioSystem.isConversionSupported(targetFormat, sourceFormat)) {
if (DEBUG && !quiet) {
System.out.println("Direct conversion not possible.");
System.out.println("Trying with intermediate PCM format.");
}
AudioFormat intermediateFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
sourceFormat.getSampleRate(),
16,
sourceFormat.getChannels(),
2 * sourceFormat.getChannels(), // frameSize
sourceFormat.getSampleRate(),
false);
if (AudioSystem.isConversionSupported(intermediateFormat, sourceFormat)) {
// intermediate conversion is supported
sourceStream = AudioSystem.getAudioInputStream(intermediateFormat, sourceStream);
}
}
targetStream = AudioSystem.getAudioInputStream(targetFormat, sourceStream);
if (targetStream == null) {
throw new Exception("conversion not supported");
}
if (!quiet) {
if (DEBUG) {
System.out.println("Got converted AudioInputStream: " + targetStream.getClass().getName());
}
System.out.println("Output format: " + targetStream.getFormat());
}
return targetStream;
}
public static AudioInputStream getConvertedStream(
AudioInputStream sourceStream,
AudioFormat.Encoding targetEncoding)
throws Exception {
AudioFormat sourceFormat = sourceStream.getFormat();
if (!quiet) {
System.out.println("Input format: " + sourceFormat);
}
// construct a converted stream
AudioInputStream targetStream = null;
if (!AudioSystem.isConversionSupported(targetEncoding, sourceFormat)) {
if (DEBUG && !quiet) {
System.out.println("Direct conversion not possible.");
System.out.println("Trying with intermediate PCM format.");
}
AudioFormat intermediateFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
sourceFormat.getSampleRate(),
16,
sourceFormat.getChannels(),
2 * sourceFormat.getChannels(), // frameSize
sourceFormat.getSampleRate(),
false);
if (AudioSystem.isConversionSupported(intermediateFormat, sourceFormat)) {
// intermediate conversion is supported
sourceStream = AudioSystem.getAudioInputStream(intermediateFormat, sourceStream);
}
}
targetStream = AudioSystem.getAudioInputStream(targetEncoding, sourceStream);
if (targetStream == null) {
throw new Exception("conversion not supported");
}
if (!quiet) {
if (DEBUG) {
System.out.println("Got converted AudioInputStream: " + targetStream.getClass().getName());
}
System.out.println("Output format: " + targetStream.getFormat());
}
return targetStream;
}
public static int writeFile(String inFilename) {
int writtenBytes = -1;
try {
AudioFileFormat.Type targetType = MP3;
AudioInputStream ais = getInStream(inFilename);
ais = getConvertedStream(ais, MPEG1L3);
// construct the target filename
String outFilename = stripExtension(inFilename) + "." + targetType.getExtension();
// write the file
if (!quiet) {
System.out.println("Writing " + outFilename + "...");
}
writtenBytes = AudioSystem.write(ais, targetType, new File(outFilename));
if (DEBUG && !quiet) {
System.out.println("Effective parameters of output file:");
try {
String version=System.getProperty("tritonus.lame.encoder.version", "");
if (version!="") {
System.out.println(" Version = "+version);
}
System.out.println(" Quality = "+System.getProperty
("tritonus.lame.effective.quality", "<none>"));
System.out.println(" Bitrate = "+System.getProperty
("tritonus.lame.effective.bitrate", "<none>"));
System.out.println(" Channel Mode = "+System.getProperty
("tritonus.lame.effective.chmode", "<none>"));
System.out.println(" VBR mode = "+System.getProperty
("tritonus.lame.effective.vbr", "<none>"));
System.out.println(" Sample rate = "+System.getProperty
("tritonus.lame.effective.samplerate", "<none>"));
System.out.println(" Encoding = "+System.getProperty
("tritonus.lame.effective.encoding", "<none>"));
} catch (Throwable t1) {}
}
} catch (Throwable t) {
if (dumpExceptions) {
t.printStackTrace();
} else if (!quiet) {
System.out.println("Error: " + t.getMessage());
}
}
return writtenBytes;
}
// returns the first index in args where the files start
public static int parseArgs(String[] args) {
if (args.length == 0) {
usage();
}
// parse options
try {
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (arg.equals("--help")) {
usage();
}
if (arg.length() > 3 || arg.length() < 2 || !arg.startsWith("-")) {
return i;
}
char cArg = arg.charAt(1);
// options without parameter
if (cArg == 'v') {
DEBUG=true;
continue;
} else if (cArg == 'e') {
dumpExceptions=true;
continue;
} else if (cArg == 't') {
org.tritonus.share.TDebug.TraceAudioConverter=true;
continue;
} else if (cArg == 's') {
quiet=true;
continue;
} else if (cArg == 'V') {
try {
System.setProperty("tritonus.lame.vbr", "true");
} catch (Throwable t1) {}
continue;
} else if (cArg == 'h') {
usage();
}
// options with parameter
if (args.length < i + 2) {
throw new Exception("Missing parameter or unrecognized option "+arg+".");
}
String param = args[i + 1];
i++;
switch (cArg) {
case 'q':
try {
System.setProperty("tritonus.lame.quality", param);
} catch (Throwable t2) {}
break;
case 'b':
try {
System.setProperty("tritonus.lame.bitrate", param);
} catch (Throwable t3) {}
break;
default:
throw new Exception("Unrecognized option "+arg+".");
}
}
throw new Exception("No input file(s) are given.");
} catch (Exception e) {
System.err.println(e.getMessage());
System.exit(1);
}
return 0; // statement not reached
}
public static void main(String[] args) {
//try {
// System.out.println("Librarypath=" + System.getProperty("java.library.path", ""));
//} catch (Throwable t) {}
int firstFileIndex = parseArgs(args);
int inputFiles = 0;
int success = 0;
long totalTime = System.currentTimeMillis();
for (int i = firstFileIndex; i < args.length; i++) {
long time = System.currentTimeMillis();
int bytes = writeFile(args[i]);
time = System.currentTimeMillis()-time;
inputFiles++;
if (bytes >= 0) {
if (bytes > 0) {
success++;
}
if (!quiet) {
System.out.println("Wrote " + bytes + " bytes in "
+ (time / 60000) + "m " + ((time/1000) % 60) + "s "
+ (time % 1000) + "ms ("
+ (time/1000) + "s).");
}
}
}
totalTime = System.currentTimeMillis() - totalTime;
if ((DEBUG && quiet) || !quiet) {
// this IS displayed in silent DEBUG mode
System.out.println("From " + inputFiles + " input file" + (inputFiles == 1 ? "" : "s") + ", "
+ success + " file" + (success == 1 ? " was" : "s were") + " converted successfully in "
+ (totalTime / 60000) + "m " + ((totalTime/1000) % 60) + "s ("
+ (totalTime/1000) + "s).");
}
System.exit(0);
}
/** Display a message of how to call this program.
*/
public static void usage() {
System.out.println("Mp3Encoder - convert audio files to mp3 (layer III of MPEG 1, MPEG 2 or MPEG 2.5");
System.out.println("java Mp3Encoder <options> <source file> [<source file>...]");
System.out.println("The output file(s) will be named like the source file(s) but");
System.out.println("with mp3 file extension.");
System.out.println("");
System.out.println("You need LAME 3.88 or later. Get it from http://sourceforge.net/projects/lame/");
System.out.println("");
System.out.println("<options> may be a combination of the following:");
System.out.println("-q <quality> Quality of output mp3 file. In VBR mode, this affects");
System.out.println(" the size of the mp3 file. (Default middle)");
System.out.println(" One of: lowest, low, middle, high, highest");
System.out.println("-b <bitrate> Bitrate in KBit/s. Useless in VBR mode. (Default 128)");
System.out.println(" One of: 32 40 48 56 64 80 96 112 128 160 192 224 256 320 (MPEG1)");
System.out.println(" Or: 8 16 24 32 40 48 56 64 80 96 112 128 144 160 (MPEG2 and MPEG2.5");
System.out.println("-V VBR (variable bit rate) mode. Slower, but potentially better");
System.out.println(" quality. (Default off)");
System.out.println("-v Be verbose.");
System.out.println("-s Be silent.");
System.out.println("-e Debugging: Dump stack trace of exceptions.");
System.out.println("-t Debugging: trace execution of converters.");
System.out.println("-h | --help Show this message.");
System.exit(1);
}
}
/*** Mp3Encoder.java ***/