package com.felix.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
/**
* Some methods concerning audio file handling.
*
* @author felix
*
*/
public class AudioUtil {
/**
* Calculate a new f0-value in Hertz given a start f0 value, a time span and
* a gradient.
*
* @param freq
* The start value in Hertz.
* @param time
* The time span.
* @param gradient
* The gradient, interpreted as semi-tones per second (ST/S)
* @return The new F0-value.
*/
public static double gradient2Hz(int freq, int time, double gradient) {
final double _12_LN2 = 17.31234;
double _exp;
double semiTone = (time * 0.001) * gradient;
_exp = semiTone / _12_LN2;
return Math.exp(_exp) * freq;
}
/**
* Audio format (8000 Hz, 16 bit, mono, little endian, pcm coding).
*/
public final static AudioFormat FORMAT_PCM_8KHZ = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED, 8000,
// Samplerate
16, // quantization
1, // mono
2, 8000, false // byteorder: little endian
);
/**
* Audio format (8000 Hz, 8 bit alaw, mono, little endian).
*/
public final static AudioFormat FORMAT_ALAW = new AudioFormat(
AudioFormat.Encoding.ALAW, 8000,
// Samplerate
8, // quantization
1, // mono
1, 8000, false // byteorder: little endian
);
/**
* Audio format (16000 Hz, 16 bit, mono, little endian, pcm coding).
*/
public final static AudioFormat FORMAT_PCM_16KHZ = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED, 16000,
// Samplerate
16, // quantization
1, // mono
2, 16000, false // byteorder: little endian
);
/**
* Audio format (22000 Hz, 16 bit, mono, little endian, pcm coding).
*/
public final static AudioFormat FORMAT_PCM_22KHZ = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED, 22050,
// Samplerate
16, // quantization
1, // mono
2, 22050, false // byteorder: little endian
);
/**
* Function converts a short array to a byte array
*
* @param shortData
* The short array.
* @return The byte array.
*/
public static byte[] shortToByte(short[] shortData, boolean littleEndian) {
byte[] data = new byte[shortData.length * 2];
int size = shortData.length;
if (littleEndian) {
for (int i = 0; i < size; i++) {
data[i * 2] = (byte) shortData[i];
data[i * 2 + 1] = (byte) (shortData[i] >> 8);
}
} else {
// big Endian
for (int i = 0; i < size; i++) {
data[i * 2] = (byte) (shortData[i] >> 8);
data[i * 2 + 1] = (byte) shortData[i];
}
}
return data;
}
/**
* Function converts a byte array to a short array.
*
* @param byteData
* The byte array.
* @param writeLittleEndian
* If true data is handled as little endian, else as big endian
* @return The short array.
*/
public static short[] byteToShort(byte[] byteData, boolean writeLittleEndian) {
short[] data = new short[byteData.length / 2];
int size = data.length;
byte lb, hb;
if (writeLittleEndian) {
for (int i = 0; i < size; i++) {
lb = byteData[i * 2];
hb = byteData[i * 2 + 1];
data[i] = (short) (((short) hb << 8) | lb & 0xff);
}
} else {
for (int i = 0; i < size; i++) {
lb = byteData[i * 2];
hb = byteData[i * 2 + 1];
data[i] = (short) (((short) lb << 8) | hb & 0xff);
}
}
return data;
}
/**
* Dump the first 1024 byte of an byte-array. Approximation to remove a
* Riff-wave header.
*
* @param data
* @return data - first 1024 byte or empty array if was shorter than 1024
* byte.
*/
public static byte[] dumpFirst1024Byte(byte[] data) {
byte[] ret = new byte[0];
if (data.length >= 1024) {
ret = new byte[data.length - 1024];
System.arraycopy(data, 1024, ret, 0, data.length - 1024);
}
return ret;
}
/**
* Convert a bytearray of sound data from (mono, 8bit a-law, 8kHz, little
* Endian) to (mono, 16 bit PCM, 8kHz, little Endian)
*
* @param data
* source-array
* @return destination array
* @throws Exception
*/
public static byte[] convertFrom8bitALawTo16bitPCM(byte[] data)
throws Exception {
byte[] ret = null;
AudioFormat sourceformat = new AudioFormat(AudioFormat.Encoding.ALAW,
8000,
// Samplerate
8, // quantization
1, // mono
2, 8000, false // byteorder: little endian
);
AudioFormat targetformat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED, 8000,
// Samplerate
16, // quantization
1, // mono
2, 8000, false // byteorder: little endian
);
AudioInputStream ais = new AudioInputStream(new ByteArrayInputStream(
data), sourceformat, data.length);
ais = AudioSystem.getAudioInputStream(targetformat, ais);
ret = getBytesFromInputStream(ais);
// AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new
// File("D:\\Work\\SymEmoTester\\RecServer\\recordings\\testsample.raw"));
return ret;
}
/**
* Convert a bytearray of sound data from (mono, 8bit mu-law, 8kHz, little
* Endian) to (mono, 16 bit PCM, 8kHz, little Endian)
*
* @param data
* source-array
* @return destination array
* @throws Exception
*/
public static byte[] convertFrom8bitMuLawTo16bitPCM(byte[] data)
throws Exception {
byte[] ret = null;
AudioFormat sourceformat = new AudioFormat(AudioFormat.Encoding.ULAW,
8000,
// Samplerate
8, // quantization
1, // mono
2, 8000, false // byteorder: little endian
);
AudioFormat targetformat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED, 8000,
// Samplerate
16, // quantization
1, // mono
2, 8000, false // byteorder: little endian
);
AudioInputStream ais = new AudioInputStream(new ByteArrayInputStream(
data), sourceformat, data.length);
ais = AudioSystem.getAudioInputStream(targetformat, ais);
ret = getBytesFromInputStream(ais);
// AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new
// File("D:\\Work\\SymEmoTester\\RecServer\\recordings\\testsample.raw"));
return ret;
}
/**
* Write a byte array with a wav header to a file.
*
* @param data
* The byte array.
* @param format
* The audioformat.
* @param fn
* The filename.
* @throws Exception
*/
public static void writeAudioToWavFile(byte[] data, AudioFormat format,
String fn) throws Exception {
AudioInputStream ais = new AudioInputStream(new ByteArrayInputStream(
data), format, data.length);
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File(fn));
}
/***************************************************************************
* Get bytes array from InputStream.
*
*/
public static byte[] getBytesFromInputStream(InputStream is)
throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while (true) {
byte[] buffer = new byte[100];
int noOfBytes = is.read(buffer);
if (noOfBytes == -1) {
break;
} else {
bos.write(buffer, 0, noOfBytes);
}
}
bos.flush();
bos.close();
return bos.toByteArray();
}
}