I'm trying audio recording with java. And the quality is not good at all. There is a continuous noise, even though it is completely quite here in the room. Any chance to remove/filter the noise?
I've discovered the same issue on cheap android phone and some recording app. Looks like it is general issue with audio recording
package test;
import javax.sound.sampled.*;
import java.io.*;
public class Tmp {
AudioFileFormat.Type fileType = AudioFileFormat.Type.WAVE;
AudioFormat getAudioFormat() {
float sampleRate = 44100;
int sampleSizeInBits = 16;
int channels = 1;
boolean signed = true;
boolean bigEndian = true;
AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits,
channels, signed, bigEndian);
return format;
}
void start(String n) {
TargetDataLine line;
File f = new File(n);
try {
AudioFormat format = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format);
line.start();
AudioInputStream ais = new AudioInputStream(line);
AudioSystem.write(ais, fileType, f);
} catch (LineUnavailableException | IOException ex) {
System.out.println(ex);
}
}
}
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 have an array filled with the javax.sound.sampled.Line.Info objects of all currently attatched microphones
Info[] sourceInfos = AudioSystem.getSourceLineInfo(Port.Info.MICROPHONE);
Using them i can get the lines of all microphones
for (Info sourceInfo : sourceInfos) {
Line sourceLine = AudioSystem.getLine(sourceInfo);
// record sound from those lines
}
Same goes for the speaker
Info[] sourceInfos = AudioSystem.getSourceLineInfo(Port.Info.SPEAKER);
for (Info sourceInfo : sourceInfos) {
Line sourceLine = AudioSystem.getLine(sourceInfo);
// play sound on those lines
}
Now i just need to figure out how to play sound on a Line and how to record sound from a Line. This is where i got stuck and couldn't find a solution for.
So just to have it said, the question is, how can i read/write to a line?
Thanks
Baschdi
You can try this example to capture and play audio. It is based on the samples provided in the Java Sound API docs.
Here are the resources you may refer to:
Accessing Audio System Resources
Capturing audio.
Playing audio.
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;
public class Audio {
boolean stopCapture = false;
ByteArrayOutputStream byteArrayOutputStream;
AudioFormat audioFormat;
TargetDataLine targetDataLine;
AudioInputStream audioInputStream;
SourceDataLine sourceDataLine;
byte tempBuffer[] = new byte[500];
public static void main(String[] args) {
Audio audio = new Audio();
audio.captureAudio();
}
private AudioFormat getAudioFormat() {
float sampleRate = 8000.0F;
int sampleSizeInBits = 16;
int channels = 1;
boolean signed = true;
boolean bigEndian = true;
return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
}
private void captureAudio() {
try {
/* ~~~~~ UPDATE THIS PART OF CODE ~~~~~*/
Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo(); //get available mixers
System.out.println("Available mixers:");
for (int cnt = 0; cnt < mixerInfo.length; cnt++) {
System.out.println(mixerInfo[cnt].getName());
}
audioFormat = getAudioFormat(); //get the audio format
DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
Mixer mixer = AudioSystem.getMixer(mixerInfo[3]); //getting the mixer for capture device
/* ~~~~~ UPDATE THIS PART OF CODE ~~~~~*/
targetDataLine = (TargetDataLine) mixer.getLine(dataLineInfo);
targetDataLine.open(audioFormat);
targetDataLine.start();
DataLine.Info dataLineInfo1 = new DataLine.Info(SourceDataLine.class, audioFormat);
sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo1);
sourceDataLine.open(audioFormat);
sourceDataLine.start();
Thread captureAndPlayThread = new captureAndPlayThread(); //thread to capture and play audio
captureAndPlayThread.start();
} catch (LineUnavailableException e) {
System.out.println(e);
System.exit(0);
}
}
class captureAndPlayThread extends Thread {
#Override
public void run() {
byteArrayOutputStream = new ByteArrayOutputStream();
stopCapture = false;
try {
int readCount;
while (!stopCapture) {
readCount = targetDataLine.read(tempBuffer, 0, tempBuffer.length); //capture sound into tempBuffer
if (readCount > 0) {
byteArrayOutputStream.write(tempBuffer, 0, readCount);
sourceDataLine.write(tempBuffer, 0, 500); //playing audio available in tempBuffer
}
}
byteArrayOutputStream.close();
} catch (IOException e) {
System.out.println(e);
System.exit(0);
}
}
}
}
`
Edit: Please update the previous code with this code. The following code snippet selects a mixer only if it supports microphone i.e, TargetDataLine. Similarly you can do for speakers i.e, SourceDataLine.
Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo(); //get available mixers
System.out.println("Available mixers:");
Mixer mixer = null;
for (int cnt = 0; cnt < mixerInfo.length; cnt++) {
System.out.println(cnt + " " + mixerInfo[cnt].getName());
mixer = AudioSystem.getMixer(mixerInfo[cnt]);
Line.Info[] lineInfos = mixer.getTargetLineInfo();
if (lineInfos.length >= 1 && lineInfos[0].getLineClass().equals(TargetDataLine.class)) {
System.out.println(cnt + " Mic is supported!");
break;
}
}
audioFormat = getAudioFormat(); //get the audio format
DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
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;
}
Everything works fine until I try to put what I receive on pc into a wav file.
I think its a problem in the saving to wav file part. Tried almost everything, AudioSystem.write etc,nothing seems to work.
If anyone can help I would really appreciate it.This is the code:
class Server {
AudioInputStream audioInputStream;
static AudioInputStream ais;
static AudioFormat format;
static boolean status = true;
static int port = 50005;
static int sampleRate = 48000;
static DataLine.Info dataLineInfo;
static SourceDataLine sourceDataLine;
public static void main(String args[]) throws Exception {
OutputStream outstream = new FileOutputStream(new File("D:/output.wav"));
DatagramSocket serverSocket = new DatagramSocket(port);
int i = 0;
/**
* Formula for lag = (byte_size/sample_rate)*2
* Byte size 9728 will produce ~ 0.45 seconds of lag. Voice slightly broken.
* Byte size 1400 will produce ~ 0.06 seconds of lag. Voice extremely broken.
* Byte size 4000 will produce ~ 0.18 seconds of lag. Voice slightly more broken then 9728.
*/
byte[] receiveData = new byte[4096];
format = new AudioFormat(sampleRate, 16, 1, true, false);
dataLineInfo = new DataLine.Info(SourceDataLine.class, format);
sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
sourceDataLine.open(format);
sourceDataLine.start();
FloatControl volumeControl = (FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN);
volumeControl.setValue(1.00f);
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
ByteArrayInputStream baiss = new ByteArrayInputStream(
receivePacket.getData());
while (status == true&&i<100) {
i++;
serverSocket.receive(receivePacket);
ais = new AudioInputStream(baiss, format, receivePacket.getLength());
try {
outstream.write(receivePacket.getData(), 0, receivePacket.getData().length);
} catch (Exception e) {
System.out.println("Not working in speakers...");
e.printStackTrace();
}
}
sourceDataLine.stop(); //after i has reacher 100 this happens
sourceDataLine.close();
outstream.close();
}
}