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
Related
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'm trying to detect the silence in order to stop recording the audio from a mic. My current code is:
public byte[] getRecord() throws AudioException {
try {
// Reset the flag
stopped = false;
// Start a new thread to wait during listening
Thread stopper = new Thread(() -> {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
br.readLine();
stopped = true;
} catch (IOException ex) {
ex.printStackTrace();
}
stop();
});
// Start the thread that can stop the record
stopper.start();
return record();
} catch (Exception e) {
throw new LineUnavailableException("Unable to record your voice", e);
}
}
private byte[] record() throws LineUnavailableException {
AudioFormat format = AudioUtil.getAudioFormat(audioConf);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
// Checks if system supports the data line
if (!AudioSystem.isLineSupported(info)) {
return null;
}
microphone = (TargetDataLine) AudioSystem.getLine(info);
microphone.open(format);
microphone.start();
System.out.println("Listening, tap enter to stop ...");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int numBytesRead;
byte[] data = new byte[microphone.getBufferSize() / 5];
// Begin audio capture.
microphone.start();
// Here, stopped is a global boolean set by another thread.
while (!stopped) {
// Read the next chunk of data from the TargetDataLine.
numBytesRead = microphone.read(data, 0, data.length);
// Save this chunk of data.
byteArrayOutputStream.write(data, 0, numBytesRead);
}
return byteArrayOutputStream.toByteArray();
}
At the moment I stop the recording using a shell but I'd like to know how I can stop it in the while loop.
After a lot of tries now it seems to work. This is the updated code:
private byte[] record() throws LineUnavailableException {
AudioFormat format = AudioUtil.getAudioFormat(audioConf);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
// Checks if system supports the data line
if (!AudioSystem.isLineSupported(info)) {
return null;
}
microphone = (TargetDataLine) AudioSystem.getLine(info);
microphone.open(format);
microphone.start();
System.out.println("Listening, tap enter to stop ...");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int numBytesRead;
byte[] data = new byte[microphone.getBufferSize() / 5];
short[] shorts = new short[data.length / 2];
long startSilence = 0;
boolean pause = false;
// Begin audio capture.
microphone.start();
// Here, stopped is a global boolean set by another thread.
while (!stopped) {
// Read the next chunk of data from the TargetDataLine.
numBytesRead = microphone.read(data, 0, data.length);
ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
// Save this chunk of data.
byteArrayOutputStream.write(data, 0, numBytesRead);
double rms = 0;
for (int i = 0; i < shorts.length; i++) {
double normal = shorts[i] / 32768f;
rms += normal * normal;
}
rms = Math.sqrt(rms / shorts.length);
System.out.println("Listening, rms is " + rms);
if (rms < 0.1) {
long now = System.currentTimeMillis();
if (now - startSilence > 5000 && pause)
break;
if (!pause) {
startSilence = now;
System.out.println("Listening, new silence at " + startSilence);
}
pause = true;
} else
pause = false;
}
return byteArrayOutputStream.toByteArray();
}
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();
}
}
I'm trying to create code to get wav files into an array list and then for the arraylist to play the files. Why does this code not work? Thanks.
public class trackList {
public void tracklist(){
ArrayList<String> songs = new ArrayList();
songs.add("c:\\01.wav");
songs.add("c:\\02.wav");
byte[] buffer = new byte[4096];
for(int x = 0; x < songs.size(); x++){
try{
AudioInputStream ais = AudioSystem.getAudioInputStream(songs(x));
AudioFormat format = ais.getFormat();
SourceDataLine line = AudioSystem.getSourceDataLine(format);
line.open(format);
line.start();
while (ais.available() > 0) {
int len = ais.read(buffer);
line.write(buffer, 0, len);
}
line.drain();
line.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
Not a Java expert, but probably the line:
AudioInputStream ais = AudioSystem.getAudioInputStream(songs(x));
Must be
AudioInputStream ais = AudioSystem.getAudioInputStream(songs.get(x));
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();
}