I am using Java sound to read in sound from the mic and transform it using fft. The issue I am having is that when I examine the byte array after the call to soundline.read() returns, it only contains 0,1, and -1. I am thoroughly confused. Below is my code:
private void setupSound() {
Vector<AudioFormat> formats = getSupportedFormats(TargetDataLine.class);
try {
float sampleRate = 44100;
int sampleSizeInBits = 16;
int channels = 1;
int frameSize = 2;
boolean signed = false;
boolean bigEndian = false;
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, sampleRate, sampleSizeInBits, channels, frameSize, sampleRate, bigEndian);
soundLine = (TargetDataLine) AudioSystem.getTargetDataLine(format);
soundLine.open(format);
soundLine.start();
} catch (LineUnavailableException ex) {
System.out.println(ex);
}
}
private byte[] readSoundSample() {
byte[] buffer = new byte[44100];
int len = soundLine.read(buffer, 0, buffer.length);
return buffer;
}
Related
I am using Java Sound API to record audio through a microphone. But why am I getting false as an output for the below snippet of code?
AudioFormat getAudioFormat() {
float sampleRate = 8000;
int sampleSizeInBits = 16;
int channels = 1; //1 for mono, 2 for stereo
boolean signed = true;
boolean bigEndian = true;
AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits,
channels, signed, bigEndian);
return format;
}
void myTest() {
AudioFormat format = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
System.out.println(AudioSystem.isLineSupported(info));
}
public static void main(String[] args) {
new JavaApplication20().myTest();
}
Thanks in advance.
I'd like to develop a simple java music player to accelerate and play music using this Sonic Algorithm github/Sonic.java. And here's the main class: github/Main.java. The Main.java simply calls Sonic.java and then it can play the music. Even though it works well when running a WAV file, but what I want is to write a new WAV file from the accelerated input stream.
I've tried to write bytes to a ByteArrayOutputStream in the do-while loop of Main.java, and transformed them into a local WAV file, while the generated music gets cut off and obviously there have some lost data during this process.
public class App {
private static void runSonic(
AudioInputStream audioStream,
SourceDataLine line,
float speed,
float pitch,
float rate,
float volume,
boolean emulateChordPitch,
int quality,
int sampleRate,
int numChannels) throws IOException
{
Sonic sonic = new Sonic(sampleRate, numChannels);
int bufferSize = line.getBufferSize();
byte inBuffer[] = new byte[bufferSize];
byte outBuffer[] = new byte[bufferSize];
int numRead,numWritten;
AudioFormat af = audioStream.getFormat();
ByteArrayOutputStream output = new ByteArrayOutputStream();
sonic.setSpeed(speed);
sonic.setPitch(pitch);
sonic.setRate(rate);
sonic.setVolume(volume);
sonic.setChordPitch(emulateChordPitch);
sonic.setQuality(quality);
int count = 0;
do {
numRead = audioStream.read(inBuffer, 0, bufferSize);
if(numRead <= 0) {
sonic.flushStream();
} else {
sonic.writeBytesToStream(inBuffer, numRead);
}
do {
numWritten = sonic.readBytesFromStream(outBuffer, bufferSize);
if(numWritten > 0) {
line.write(outBuffer, 0, numWritten);
output.write(outBuffer);
}
} while(numWritten > 0);
} while(numRead > 0);
byte fileBuffer[] = output.toByteArray();
ByteArrayInputStream bais1 = new ByteArrayInputStream(fileBuffer);
AudioInputStream aisAccelerated1 =
new AudioInputStream(bais1, af, fileBuffer.length);
try {
AudioSystem.write(aisAccelerated1, AudioFileFormat.Type.WAVE, new
File("newFile.wav")
);
}
catch(Exception e) {
e.printStackTrace();
}
}
public static void main(
String[] argv) throws UnsupportedAudioFileException, IOException, LineUnavailableException
{
float speed = 1.5f;
float pitch = 1.5f;
float rate = 1.0f;
float volume = 1.0f;
boolean emulateChordPitch = false;
int quality = 0;
String fileName = "file.wav";
AudioInputStream stream = AudioSystem.getAudioInputStream(new File(fileName));
AudioFormat format = stream.getFormat();
int sampleRate = (int)format.getSampleRate();
int numChannels = format.getChannels();
SourceDataLine.Info info = new DataLine.Info(SourceDataLine.class, format,
((int)stream.getFrameLength()*format.getFrameSize()));
SourceDataLine line = (SourceDataLine)AudioSystem.getLine(info);
line.open(stream.getFormat());
line.start();
runSonic(stream, line, speed, pitch, rate, volume, emulateChordPitch, quality,
sampleRate, numChannels);
line.drain();
line.stop();
}
}
Who can tell me what's going on here? I think all bytes stored in outBuffer has been writted into the output stream in this way.
You can find the whole class using the links above.
output.write(outBuffer);
The problem is here. It should be
output.write(outBuffer, 0, numWritten);
You are writing garbage to the output.
I am a newbie in programming and I want to learn more.
I want to record sound from my microphone in real-time. Below is my code for recording.
while (true) {
int numBytesRead = line.read(data, 0, data.length);
out.write(data, 0, numBytesRead);
}
I tried to enter some codes there and I got to play some chunks of data but after a few seconds, the recording delays for about 3 seconds. Also, when I tried to talk, it plays backs in loop what I tried to say
while (true) {
int numBytesRead = line.read(data, 0, data.length);
out.write(data, 0, numBytesRead);
try {
byte audio[] = out.toByteArray();
InputStream input = new ByteArrayInputStream(audio);
final SourceDataLine line1 = (SourceDataLine) AudioSystem.getLine(info1);
final AudioInputStream ais = new AudioInputStream(input, format, audio.length / format.getFrameSize());
int bufferSize = (int) format.getSampleRate() * format.getFrameSize();
line1.open(format);
line1.start();
byte buffer[] = new byte[bufferSize];
try {
while (true) {
numBytesRead = ais.read(buffer, 0, buffer.length);
if (numBytesRead == -1) break;
line1.write(buffer, 0, numBytesRead);
}
} catch (IOException e) {
System.err.println("I/O problems: " + e);
System.exit(-3);
}
}
Could somebody help me with my project.
thank you for your answer sir. but i tried adding this line to my code and the playback worked
while (numBytesRemaining>0){
numBytesRemaining-=line1.write(data,0,numBytesRemaining);
}
thank you for your help sir
why don't you use Clip for reading the recorded sound.
wavdata = out.toByteArray();
AudioInputStream ais = new AudioInputStream(new ByteArrayInputStream(wavdata), WAVFormat(), wavdata.length / WAVFormat().getFrameSize());
format = ais.getFormat();
info = new DataLine.Info(Clip.class, format);
Clip clip = (Clip) AudioSystem.getLine(info);
clip.open(ais);
//this is for playing
clip.start();
//this is for stopping or pause use it on the pause or stop button.
//clip.stop();
and this is the WAVFormat()
private AudioFormat WAVFormat() {
int channels = 2;
Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
float sampleRate = rateconstant;
int frameSize = framesize;
float frameRate = rateconstant;
int sampleSizeInBits = 16;
boolean bigEndian = false;
return new AudioFormat(encoding, sampleRate, sampleSizeInBits, channels, frameSize, frameRate, bigEndian);
}
hope it helps
How can I detect silence when recording operation is started in Java? What is PCM data? How can I calculate PCM data in Java?
I found the solution :
package bemukan.voiceRecognition.speechToText;
import javax.sound.sampled.*;
import java.io.*;
public class RecordAudio {
private File audioFile;
protected boolean running;
private ByteArrayOutputStream out;
private AudioInputStream inputStream;
final static float MAX_8_BITS_SIGNED = Byte.MAX_VALUE;
final static float MAX_8_BITS_UNSIGNED = 0xff;
final static float MAX_16_BITS_SIGNED = Short.MAX_VALUE;
final static float MAX_16_BITS_UNSIGNED = 0xffff;
private AudioFormat format;
private float level;
private int frameSize;
public RecordAudio(){
getFormat();
}
private AudioFormat getFormat() {
File file = new File("src/Facebook/1.wav");
AudioInputStream stream;
try {
stream = AudioSystem.getAudioInputStream(file);
format=stream.getFormat();
frameSize=stream.getFormat().getFrameSize();
return stream.getFormat();
} catch (UnsupportedAudioFileException e) {
} catch (IOException e) {
}
return null;
}
public void stopAudio() {
running = false;
}
public void recordAudio() {
try {
final AudioFormat format = getFormat();
DataLine.Info info = new DataLine.Info(
TargetDataLine.class, format);
final TargetDataLine line = (TargetDataLine)
AudioSystem.getLine(info);
line.open(format);
line.start();
Runnable runner = new Runnable() {
int bufferSize = (int) format.getSampleRate()
* format.getFrameSize();
byte buffer[] = new byte[bufferSize];
public void run() {
int readPoint = 0;
out = new ByteArrayOutputStream();
running = true;
int sum=0;
while (running) {
int count =
line.read(buffer, 0, buffer.length);
calculateLevel(buffer,0,0);
System.out.println(level);
if (count > 0) {
out.write(buffer, 0, count);
}
}
line.stop();
}
};
Thread captureThread = new Thread(runner);
captureThread.start();
} catch (LineUnavailableException e) {
System.err.println("Line unavailable: " + e);
System.exit(-2);
}
}
public File getAudioFile() {
byte[] audio = out.toByteArray();
InputStream input = new ByteArrayInputStream(audio);
try {
final AudioFormat format = getFormat();
final AudioInputStream ais =
new AudioInputStream(input, format,
audio.length / format.getFrameSize());
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File("temp.wav"));
input.close();
System.out.println("New file created!");
} catch (IOException e) {
System.out.println(e.getMessage());
}
return new File("temp.wav");
}
private void calculateLevel (byte[] buffer,
int readPoint,
int leftOver) {
int max = 0;
boolean use16Bit = (format.getSampleSizeInBits() == 16);
boolean signed = (format.getEncoding() ==
AudioFormat.Encoding.PCM_SIGNED);
boolean bigEndian = (format.isBigEndian());
if (use16Bit) {
for (int i=readPoint; i<buffer.length-leftOver; i+=2) {
int value = 0;
// deal with endianness
int hiByte = (bigEndian ? buffer[i] : buffer[i+1]);
int loByte = (bigEndian ? buffer[i+1] : buffer [i]);
if (signed) {
short shortVal = (short) hiByte;
shortVal = (short) ((shortVal << 8) | (byte) loByte);
value = shortVal;
} else {
value = (hiByte << 8) | loByte;
}
max = Math.max(max, value);
} // for
} else {
// 8 bit - no endianness issues, just sign
for (int i=readPoint; i<buffer.length-leftOver; i++) {
int value = 0;
if (signed) {
value = buffer [i];
} else {
short shortVal = 0;
shortVal = (short) (shortVal | buffer [i]);
value = shortVal;
}
max = Math.max (max, value);
} // for
} // 8 bit
// express max as float of 0.0 to 1.0 of max value
// of 8 or 16 bits (signed or unsigned)
if (signed) {
if (use16Bit) { level = (float) max / MAX_16_BITS_SIGNED; }
else { level = (float) max / MAX_8_BITS_SIGNED; }
} else {
if (use16Bit) { level = (float) max / MAX_16_BITS_UNSIGNED; }
else { level = (float) max / MAX_8_BITS_UNSIGNED; }
}
} // calculateLevel
}
How can I detect silence when recording operation is started in Java?
Calculate the dB or RMS value for a group of sound frames and decide at what level it is considered to be 'silence'.
What is PCM data?
Data that is in Pulse-code modulation format.
How can I calculate PCM data in Java?
I do not understand that question. But guessing it has something to do with the speech-recognition tag, I have some bad news. This might theoretically be done using the Java Speech API. But there are apparently no 'speech to text' implementations available for the API (only 'text to speech').
I have to calculate rms for speech-recognition project. But I do not know how can I calculate in Java.
For a single channel that is represented by signal sizes in a double ranging from -1 to 1, you might use this method.
/** Computes the RMS volume of a group of signal sizes ranging from -1 to 1. */
public double volumeRMS(double[] raw) {
double sum = 0d;
if (raw.length==0) {
return sum;
} else {
for (int ii=0; ii<raw.length; ii++) {
sum += raw[ii];
}
}
double average = sum/raw.length;
double sumMeanSquare = 0d;
for (int ii=0; ii<raw.length; ii++) {
sumMeanSquare += Math.pow(raw[ii]-average,2d);
}
double averageMeanSquare = sumMeanSquare/raw.length;
double rootMeanSquare = Math.sqrt(averageMeanSquare);
return rootMeanSquare;
}
There is a byte buffer to save input values from the line, and what I should have to do with this buffer?
If using the volumeRMS(double[]) method, convert the byte values to an array of double values ranging from -1 to 1. ;)
You need to catch the value like a number silence is zero or near
Please adapt your code to your requirement!!!
In this case a variable named UMBRAL (Threshold in spanish)...
Suppose that you have access to WAV file like bytes ByteHeader...
private Integer Byte2PosIntBig(byte Byte24, byte Byte16, byte Byte08, byte Byte00) {
return new Integer (
((Byte24) << 24)|
((Byte16 & 0xFF) << 16)|
((Byte08 & 0xFF) << 8)|
((Byte00 & 0xFF) << 0));
}
Before ....
RandomAccessFile RAFSource = new RandomAccessFile("your old file wav", "r");
Begins here...
int PSData = 44;
byte[] Bytes = new byte[4];
byte[] ByteHeader = new byte[44];
RAFSource.seek(0);
RAFSource.read(ByteHeader);
int WavSize = Byte2PosIntBig(ByteHeader[43],ByteHeader[42],ByteHeader[41],ByteHeader[40]);
int NumBits = Byte2PosIntBig(ByteHeader[35],ByteHeader[34]);
int NumByte = NumBits/8;
for (int i = PSData;i < PSData+WavSize;i+=NumByte) {
int WavSample = 0;
int WavResultI =0;
int WavResultO = 0;
if (NumByte == 2) {
RAFSource.seek(i);
Bytes[0] = RAFSource.readByte();
Bytes[1] = RAFSource.readByte();
WavSample = (int)(((Bytes[1]) << 8)|((Bytes[0] & 0xFF) << 0));
if (Math.abs(WavSample) < UMBRAL) {
//SILENCE DETECTED!!!
}
} else {
RAFSource.seek(i);
WavSample = (short)(RAFSource.readByte() & 0xFF);
short sSamT = (short)WavSample;
sSamT += 128;
double dSamD = (double)sSamT*Multiplier;
if ((double)sSamT < UMBRAL) {
//SILENCE DETECTED!!!
}
}
I have a client and server application.
The server requests an audio stream and the client handles well.
The client proceeds to setup an AudioFormat(Note: settings are the same on both ends) and TargetDataLine. It Then writes the data to a Socket output stream using a ByteArrayOutput Stream.
The server receives the Data and reads it in a threaded method. During each buffer read it it saves to a AudioInputStream which is passed to a playSound method which is threaded and synchronized to proceed to play the sound.
When i make the playSound method non threaded it works well but slightly glitchy.
Also i know having the play sound non threaded can cause sound frames to jam up
Any help is well appreciated, and any ways I can make this audio stream more efficient and fast is also welcomed.
Client:
private void captureAudio() throws CommandException {
Socket session = new Socket(host_, port_);
try {
final AudioFormat format = getFormat();
DataLine.Info info = new DataLine.Info(
TargetDataLine.class, format);
final TargetDataLine line = (TargetDataLine)
AudioSystem.getLine(info);
line.open(format);
line.start();
int bufferSize = (int)format.getSampleRate() * format.getFrameSize();
byte buffer[] = new byte[bufferSize];
running = true;
try {
while (running) {
int count = line.read(buffer, 0, buffer.length);
if (count > 0) {
BufferedOutputStream out_ = null;
out_ = new BufferedOutputStream(socket_.getOutputStream());
out_.write(buffer, 0, count);
out_.flush();
}
}
out_.close();
line.close();
} catch (IOException e) {
throw new CommandException("I/O problems: " + e,Command.TRANSFER_ERROR);
}
} catch (LineUnavailableException e) {
throw new CommandException("Line unavailable: " + e,Command.ERROR);
}
else {
throw new CommandException("Unable to Connect to Server",Command.CONNECTION_ERROR);
}
}
private AudioFormat getFormat() {
float sampleRate = 16000;
int sampleSizeInBits = 16;
int channels = 2;
boolean signed = true;
boolean bigEndian = true;
return new AudioFormat(sampleRate,sampleSizeInBits, channels, signed, bigEndian);
}
Server:
public void readSocket(final Socket socket) {
new Thread() {
#Override
public void run() {
InputStream input;
try {
input = socket.getInputStream();
final AudioFormat format = getFormat();
int bufferSize = (int)format.getSampleRate() * format.getFrameSize();
byte buffer[] = new byte[bufferSize];
int bytesRead;
while (((bytesRead = input.read(buffer, 0, bufferSize)) != -1 ) ) {
if (bytesRead > 0) {
play(new AudioInputStream(input, format, buffer.length / format.getFrameSize()));
}
}
socket.close();
} catch (Exception ex) {
}
}
}.start();
}
private AudioFormat getFormat() {
float sampleRate = 16000;
int sampleSizeInBits = 16;
int channels = 2;
boolean signed = true;
boolean bigEndian = true;
return new AudioFormat(sampleRate,
sampleSizeInBits, channels, signed, bigEndian);
}
private synchronized void play(final AudioInputStream ais) {
new Thread() {
#Override
public void run() {
try {
final AudioFormat format = getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
SourceDataLine line = (SourceDataLine)AudioSystem.getLine(info);
line.open(format);
line.start();
int bufferSize = (int) format.getSampleRate()
* format.getFrameSize();
byte buffer[] = new byte[bufferSize];
int count;
while ((count = ais.read(buffer, 0, buffer.length)) != -1) {
if (count > 0) {
line.write(buffer, 0, count);
}
}
line.drain();
line.close();
ais.close();
} catch (LineUnavailableException ex) {
} catch (IOException ex) {
}
}
}.start();
}