diff --git a/AudioProcessing/lib/jogg-0.0.7.jar b/AudioProcessing/lib/jogg-0.0.7.jar
new file mode 100644
index 0000000..1cbd1ad
Binary files /dev/null and b/AudioProcessing/lib/jogg-0.0.7.jar differ
diff --git a/AudioProcessing/lib/jorbis-0.0.15.jar b/AudioProcessing/lib/jorbis-0.0.15.jar
new file mode 100644
index 0000000..4cf51f9
Binary files /dev/null and b/AudioProcessing/lib/jorbis-0.0.15.jar differ
diff --git a/AudioProcessing/lib/tritonus_jorbis-0.3.6.jar b/AudioProcessing/lib/tritonus_jorbis-0.3.6.jar
new file mode 100644
index 0000000..45b8fc1
Binary files /dev/null and b/AudioProcessing/lib/tritonus_jorbis-0.3.6.jar differ
diff --git a/AudioProcessing/pom.xml b/AudioProcessing/pom.xml
index a04339e..b864175 100644
--- a/AudioProcessing/pom.xml
+++ b/AudioProcessing/pom.xml
@@ -34,6 +34,27 @@
system
${basedir}/lib/mp3spi1.9.5.jar
+
+ org.tritonus
+ jorbis
+ 0.3.6
+ system
+ ${basedir}/lib/tritonus_jorbis-0.3.6.jar
+
+
+ com.jcraft
+ jogg
+ 0.0.7
+ system
+ ${basedir}/lib/jogg-0.0.7.jar
+
+
+ com.jcraft
+ jorbis
+ 0.0.15
+ system
+ ${basedir}/lib/jorbis-0.0.15.jar
+
org.tritonus
share
diff --git a/AudioProcessing/src/main/java/org/wyrez/audio/decoder/DecoderFactory.java b/AudioProcessing/src/main/java/org/wyrez/audio/decoder/DecoderFactory.java
index e401c60..a023020 100644
--- a/AudioProcessing/src/main/java/org/wyrez/audio/decoder/DecoderFactory.java
+++ b/AudioProcessing/src/main/java/org/wyrez/audio/decoder/DecoderFactory.java
@@ -26,7 +26,7 @@ import java.io.InputStream;
*/
public enum DecoderFactory {
- WAVE, MP3;
+ WAVE, MP3, OGG;
/**
* Creates a decoder for the selected codec.
@@ -36,10 +36,12 @@ public enum DecoderFactory {
*/
public Decoder create(InputStream is) throws Exception {
switch (this) {
- case WAVE:
- return new WaveDecoder(is);
case MP3:
return new MP3Decoder(is);
+ case OGG:
+ return new VorbisDecoder(is);
+ case WAVE:
+ return new WaveDecoder(is);
default: //impossible
return null;
}
@@ -63,6 +65,8 @@ public enum DecoderFactory {
switch (extension.toUpperCase()) {
case "MP3":
return MP3.create(new FileInputStream(file));
+ case "OGG":
+ return OGG.create(new FileInputStream(file));
case "WAV":
case "WAVE":
return WAVE.create(new FileInputStream(file));
diff --git a/AudioProcessing/src/main/java/org/wyrez/audio/decoder/MP3Decoder.java b/AudioProcessing/src/main/java/org/wyrez/audio/decoder/MP3Decoder.java
index 76367e0..6948fa2 100644
--- a/AudioProcessing/src/main/java/org/wyrez/audio/decoder/MP3Decoder.java
+++ b/AudioProcessing/src/main/java/org/wyrez/audio/decoder/MP3Decoder.java
@@ -25,22 +25,11 @@ package org.wyrez.audio.decoder;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.PushbackInputStream;
-import java.util.HashMap;
-import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
-import javax.sound.sampled.UnsupportedAudioFileException;
-import javazoom.jl.decoder.Bitstream;
-import javazoom.jl.decoder.Header;
-import javazoom.spi.mpeg.sampled.file.MpegAudioFileFormat;
-import javazoom.spi.mpeg.sampled.file.MpegAudioFormat;
-import javazoom.spi.mpeg.sampled.file.MpegEncoding;
-import javazoom.spi.mpeg.sampled.file.MpegFileFormatType;
-import org.tritonus.share.TDebug;
+import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader;
import org.tritonus.share.sampled.FloatSampleBuffer;
-import org.tritonus.share.sampled.file.TAudioFileReader;
/**
* A decoder for MP3 files with a maximum of 2 channels.
@@ -64,7 +53,7 @@ public class MP3Decoder implements Decoder {
*/
public MP3Decoder(InputStream stream) throws Exception {
InputStream in = new BufferedInputStream(stream, 1024 * 1024);
- this.in = new MP3AudioFileReader().getAudioInputStream(in);
+ this.in = new MpegAudioFileReader().getAudioInputStream(in);
AudioFormat baseFormat = this.in.getFormat();
this.channels = baseFormat.getChannels();
if (channels > 2) {
@@ -195,171 +184,4 @@ public class MP3Decoder implements Decoder {
public float getSamplingRate() {
return samplingRate;
}
-
- class MP3AudioFileReader extends TAudioFileReader {
-
- public static final int INITAL_READ_LENGTH = 128000;
- private static final int MARK_LIMIT = INITAL_READ_LENGTH + 1;
- private final AudioFormat.Encoding[][] sm_aEncodings = {
- {MpegEncoding.MPEG2L1, MpegEncoding.MPEG2L2, MpegEncoding.MPEG2L3},
- {MpegEncoding.MPEG1L1, MpegEncoding.MPEG1L2, MpegEncoding.MPEG1L3},
- {MpegEncoding.MPEG2DOT5L1, MpegEncoding.MPEG2DOT5L2,
- MpegEncoding.MPEG2DOT5L3},};
-
- protected MP3AudioFileReader() {
- super(MARK_LIMIT, true);
- }
-
- @Override
- protected AudioFileFormat getAudioFileFormat(InputStream inputStream, long mediaLength)
- throws UnsupportedAudioFileException, IOException {
- HashMap aff_properties = new HashMap();
- HashMap af_properties = new HashMap();
- int mLength = (int) mediaLength;
- int size = inputStream.available();
- PushbackInputStream pis = new PushbackInputStream(inputStream, MARK_LIMIT);
- byte head[] = new byte[22];
- pis.read(head);
-
- // Check for WAV, AU, and AIFF, Ogg Vorbis, Flac, MAC file formats.
- // Next check for Shoutcast (supported) and OGG (unsupported) streams.
- if ((head[0] == 'R') && (head[1] == 'I') && (head[2] == 'F')
- && (head[3] == 'F') && (head[8] == 'W') && (head[9] == 'A')
- && (head[10] == 'V') && (head[11] == 'E')) {
- int isPCM = ((head[21] << 8) & 0x0000FF00) | ((head[20]) & 0x00000FF);
- throw new UnsupportedAudioFileException("WAV PCM stream found");
-
- } else if ((head[0] == '.') && (head[1] == 's') && (head[2] == 'n')
- && (head[3] == 'd')) {
- throw new UnsupportedAudioFileException("AU stream found");
- } else if ((head[0] == 'F') && (head[1] == 'O') && (head[2] == 'R')
- && (head[3] == 'M') && (head[8] == 'A') && (head[9] == 'I')
- && (head[10] == 'F') && (head[11] == 'F')) {
- throw new UnsupportedAudioFileException("AIFF stream found");
- } else if (((head[0] == 'M') | (head[0] == 'm'))
- && ((head[1] == 'A') | (head[1] == 'a'))
- && ((head[2] == 'C') | (head[2] == 'c'))) {
- throw new UnsupportedAudioFileException("APE stream found");
- } else if (((head[0] == 'F') | (head[0] == 'f'))
- && ((head[1] == 'L') | (head[1] == 'l'))
- && ((head[2] == 'A') | (head[2] == 'a'))
- && ((head[3] == 'C') | (head[3] == 'c'))) {
- throw new UnsupportedAudioFileException("FLAC stream found");
- } // Shoutcast stream ?
- else if (((head[0] == 'I') | (head[0] == 'i'))
- && ((head[1] == 'C') | (head[1] == 'c'))
- && ((head[2] == 'Y') | (head[2] == 'y'))) {
- pis.unread(head);
- // Load shoutcast meta data.
- } // Ogg stream ?
- else if (((head[0] == 'O') | (head[0] == 'o'))
- && ((head[1] == 'G') | (head[1] == 'g'))
- && ((head[2] == 'G') | (head[2] == 'g'))) {
- throw new UnsupportedAudioFileException("Ogg stream found");
- } // No, so pushback.
- else {
- pis.unread(head);
- }
- // MPEG header info.
- int nVersion = AudioSystem.NOT_SPECIFIED;
- int nLayer = AudioSystem.NOT_SPECIFIED;
- // int nSFIndex = AudioSystem.NOT_SPECIFIED;
- int nMode = AudioSystem.NOT_SPECIFIED;
- int FrameSize = AudioSystem.NOT_SPECIFIED;
- // int nFrameSize = AudioSystem.NOT_SPECIFIED;
- int nFrequency = AudioSystem.NOT_SPECIFIED;
- int nTotalFrames = AudioSystem.NOT_SPECIFIED;
- float FrameRate = AudioSystem.NOT_SPECIFIED;
- int BitRate = AudioSystem.NOT_SPECIFIED;
- int nChannels = AudioSystem.NOT_SPECIFIED;
- int nHeader = AudioSystem.NOT_SPECIFIED;
- int nTotalMS = AudioSystem.NOT_SPECIFIED;
- boolean nVBR = false;
- AudioFormat.Encoding encoding = null;
- try {
- Bitstream m_bitstream = new Bitstream(pis);
- aff_properties.put("mp3.header.pos",
- new Integer(m_bitstream.header_pos()));
- Header m_header = m_bitstream.readFrame();
- // nVersion = 0 => MPEG2-LSF (Including MPEG2.5), nVersion = 1 => MPEG1
- nVersion = m_header.version();
- if (nVersion == 2) {
- aff_properties.put("mp3.version.mpeg", Float.toString(2.5f));
- } else {
- aff_properties.put("mp3.version.mpeg",
- Integer.toString(2 - nVersion));
- }
- // nLayer = 1,2,3
- nLayer = m_header.layer();
- aff_properties.put("mp3.version.layer", Integer.toString(nLayer));
- // nSFIndex = m_header.sample_frequency();
- nMode = m_header.mode();
- aff_properties.put("mp3.mode", new Integer(nMode));
- nChannels = nMode == 3 ? 1 : 2;
- aff_properties.put("mp3.channels", new Integer(nChannels));
- nVBR = m_header.vbr();
- af_properties.put("vbr", new Boolean(nVBR));
- aff_properties.put("mp3.vbr", new Boolean(nVBR));
- aff_properties.put("mp3.vbr.scale", new Integer(m_header.vbr_scale()));
- FrameSize = m_header.calculate_framesize();
- aff_properties.put("mp3.framesize.bytes", new Integer(FrameSize));
- if (FrameSize < 0) {
- throw new UnsupportedAudioFileException("Invalid FrameSize : " + FrameSize);
- }
- nFrequency = m_header.frequency();
- aff_properties.put("mp3.frequency.hz", new Integer(nFrequency));
- FrameRate = (float) ((1.0 / (m_header.ms_per_frame())) * 1000.0);
- aff_properties.put("mp3.framerate.fps", new Float(FrameRate));
- if (FrameRate < 0) {
- throw new UnsupportedAudioFileException("Invalid FrameRate : " + FrameRate);
- }
- if (mLength != AudioSystem.NOT_SPECIFIED) {
- aff_properties.put("mp3.length.bytes", new Integer(mLength));
- nTotalFrames = m_header.max_number_of_frames(mLength);
- aff_properties.put("mp3.length.frames", new Integer(nTotalFrames));
- }
- BitRate = m_header.bitrate();
- af_properties.put("bitrate", new Integer(BitRate));
- aff_properties.put("mp3.bitrate.nominal.bps", new Integer(BitRate));
- nHeader = m_header.getSyncHeader();
- encoding = sm_aEncodings[nVersion][nLayer - 1];
- aff_properties.put("mp3.version.encoding", encoding.toString());
- if (mLength != AudioSystem.NOT_SPECIFIED) {
- nTotalMS = Math.round(m_header.total_ms(mLength));
- aff_properties.put("duration", new Long((long) nTotalMS * 1000L));
- }
- aff_properties.put("mp3.copyright", new Boolean(m_header.copyright()));
- aff_properties.put("mp3.original", new Boolean(m_header.original()));
- aff_properties.put("mp3.crc", new Boolean(m_header.checksums()));
- aff_properties.put("mp3.padding", new Boolean(m_header.padding()));
- InputStream id3v2 = m_bitstream.getRawID3v2();
- if (id3v2 != null) {
- aff_properties.put("mp3.id3tag.v2", id3v2);
- }
- if (TDebug.TraceAudioFileReader) {
- TDebug.out(m_header.toString());
- }
- } catch (Exception e) {
- throw new UnsupportedAudioFileException("not a MPEG stream:"
- + e.getMessage());
- }
- // Deeper checks ?
- int cVersion = (nHeader >> 19) & 0x3;
- if (cVersion == 1) {
- throw new UnsupportedAudioFileException(
- "not a MPEG stream: wrong version");
- }
- int cSFIndex = (nHeader >> 10) & 0x3;
- if (cSFIndex == 3) {
-
- throw new UnsupportedAudioFileException(
- "not a MPEG stream: wrong sampling rate");
- }
-
- AudioFormat format = new MpegAudioFormat(encoding, (float) nFrequency,
- AudioSystem.NOT_SPECIFIED, nChannels, -1, FrameRate, true, af_properties);
- return new MpegAudioFileFormat(MpegFileFormatType.MP3, format,
- nTotalFrames, mLength, aff_properties);
- }
- }
}
diff --git a/AudioProcessing/src/main/java/org/wyrez/audio/decoder/VorbisDecoder.java b/AudioProcessing/src/main/java/org/wyrez/audio/decoder/VorbisDecoder.java
new file mode 100644
index 0000000..18b7009
--- /dev/null
+++ b/AudioProcessing/src/main/java/org/wyrez/audio/decoder/VorbisDecoder.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2013 Darth Affe and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ *
+ * This Code is based on the source provided with a tutorial by
+ * http://www.badlogicgames.com (as of 16.05.2013).
+ * The original source can be found here:
+ * http://code.google.com/p/audio-analysis/source/browse/trunk/src/com/badlogic/audio/io/MP3Decoder.java
+ */
+package org.wyrez.audio.decoder;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import org.tritonus.sampled.file.jorbis.JorbisAudioFileReader;
+import org.tritonus.share.sampled.FloatSampleBuffer;
+
+/**
+ * A decoder for MP3 files with a maximum of 2 channels.
+ *
+ * @author Darth Affe
+ */
+public class VorbisDecoder implements Decoder {
+
+ private AudioInputStream in;
+ private FloatSampleBuffer buffer;
+ private byte[] bytes;
+ private int channels;
+ private float samplingRate;
+
+ /**
+ * Constructor, sets the input stream to read the MP3 file from. Audio files
+ * with more than 2 channels aren't supported!
+ *
+ * @param stream The input stream.
+ * @throws Exception in case the input stream couldn't be read properly
+ */
+ public VorbisDecoder(InputStream stream) throws Exception {
+ InputStream in = new BufferedInputStream(stream, 1024 * 1024);
+ this.in = new JorbisAudioFileReader().getAudioInputStream(in);
+ AudioFormat baseFormat = this.in.getFormat();
+ this.channels = baseFormat.getChannels();
+ if (channels > 2) {
+ throw new IllegalArgumentException("more than 2 channels aren't supported");
+ }
+ this.samplingRate = baseFormat.getSampleRate();
+ AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
+ baseFormat.getSampleRate(), 16,
+ baseFormat.getChannels(),
+ baseFormat.getChannels() * 2,
+ baseFormat.getSampleRate(), false);
+ this.in = AudioSystem.getAudioInputStream(format, this.in);
+ }
+
+ /**
+ * Tries to read in samples.length stereo samples. Returns the number of
+ * samples actually read. Guarantees that samples.length samples are read in
+ * if there was enough data in the stream.
+ *
+ * @param samples The samples array to write the samples to
+ * @return The number of samples actually read
+ */
+ @Override
+ public int readSamplesStereo(float[] samples) {
+ if (buffer == null || buffer.getSampleCount() < samples.length / 2) {
+ buffer = new FloatSampleBuffer(in.getFormat().getChannels(), samples.length / 2, in.getFormat().getSampleRate());
+ bytes = new byte[buffer.getByteArrayBufferSize(in.getFormat())];
+ }
+
+ int read = 0;
+ int readBytes = 0;
+ try {
+ readBytes = in.read(bytes, read, bytes.length - read);
+ } catch (IOException e) {
+ return 0;
+ }
+ if (readBytes == -1) {
+ return 0;
+ }
+
+ read += readBytes;
+ while (readBytes != -1 && read != bytes.length) {
+ try {
+ readBytes = in.read(bytes, read, bytes.length - read);
+ } catch (IOException e) {
+ return 0;
+ }
+ read += readBytes;
+ }
+
+ int frameCount = bytes.length / in.getFormat().getFrameSize();
+ buffer.setSamplesFromBytes(bytes, 0, in.getFormat(), 0, frameCount);
+
+ for (int i = 0, j = 0; i < buffer.getSampleCount(); i++, j += 2) {
+ samples[j] = buffer.getChannel(0)[i];
+ samples[j + 1] = buffer.getChannel(buffer.getChannelCount() == 2 ? 1 : 0)[i];
+ }
+ return buffer.getSampleCount() * 2;
+ }
+
+ /**
+ * Tries to read in samples.length samples, merging stereo to a mono channel
+ * by averaging. Returns the number of samples actually read. Guarantees
+ * that samples.length samples are read in if there was enough data in the
+ * stream.
+ *
+ * @param samples The samples array to write the samples to
+ * @return The number of samples actually read
+ */
+ @Override
+ public int readSamplesMergedMono(float[] samples) {
+ if (buffer == null || buffer.getSampleCount() < samples.length) {
+ buffer = new FloatSampleBuffer(in.getFormat().getChannels(), samples.length, in.getFormat().getSampleRate());
+ bytes = new byte[buffer.getByteArrayBufferSize(in.getFormat())];
+ }
+
+ int read = 0;
+ int readBytes = 0;
+ try {
+ readBytes = in.read(bytes, read, bytes.length - read);
+ } catch (IOException e) {
+ return 0;
+ }
+ if (readBytes == -1) {
+ return 0;
+ }
+
+ read += readBytes;
+ while (readBytes != -1 && read != bytes.length) {
+ try {
+ readBytes = in.read(bytes, read, bytes.length - read);
+ } catch (IOException e) {
+ return 0;
+ }
+ read += readBytes;
+ }
+
+ int frameCount = bytes.length / in.getFormat().getFrameSize();
+ buffer.setSamplesFromBytes(bytes, 0, in.getFormat(), 0, frameCount);
+
+ for (int i = 0; i < buffer.getSampleCount(); i++) {
+ if (buffer.getChannelCount() == 2) {
+ samples[i] = (buffer.getChannel(0)[i] + buffer.getChannel(1)[i]) / 2;
+ } else {
+ samples[i] = buffer.getChannel(0)[i];
+ }
+ }
+ return buffer.getSampleCount();
+ }
+
+ /**
+ * Returns the number of channels in the audio source. (This value can't be
+ * greater than 2)
+ *
+ * @returns The channel count
+ */
+ @Override
+ public int getChannelCount() {
+ return channels;
+ }
+
+ /**
+ * Returns the sampling rate in Hz of the audio source.
+ *
+ * @returns the sampling rate as float
+ */
+ @Override
+ public float getSamplingRate() {
+ return samplingRate;
+ }
+}