Echo when recording and playing sound - java

I have a simple application that starts recording from the microphone and then immediately plays the sounds back to my headphones, however the problem here is: the sound quality is not good and there is a lasting echo after speaking something in the microphone which can last up to 5 seconds after speaking. I'm not sure whether the problem lies in the Java Sound API and I need to switch to another library.
I also want to mention that I use a headphone that is plugged into my computer. When I use low volume then the sound plays normal however when I turn it up to 90% of my maximum value the sound quality really becomes bad.
Here is my code:
AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);
DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, format);
TargetDataLine mic = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
mic.open();
mic.start();
DataLine.Info dataLineInfo2 = new DataLine.Info(SourceDataLine.class, format);
SourceDataLine speakers = (SourceDataLine) AudioSystem.getLine(dataLineInfo2);
speakers.open();
speakers.start();
byte[] buffer = new byte[1024];
while(true) {
mic.read(buffer, 0, buffer.length);
speakers.write(buffer, 0, buffer.length);
}

Related

Detect Specific Frequency From Microphone Java

I'm trying to capture audio that is coming from microphone and i wanted to check the frequency of sound. If I get a frequency greater then let's say : 1316.8 then I will start recording for 1 minute.
I am struggling with converting byte Data to Frequency.
I have used Javax.sound to capture audio that is coming from microphone and I have done the recording part as well.
AudioFormat format = new AudioFormat(44100, 16, 2, true, true);
DataLine.Info targetInfo = new DataLine.Info(TargetDataLine.class, format);
DataLine.Info sourceInfo = new DataLine.Info(SourceDataLine.class, format);
try {
TargetDataLine targetLine = (TargetDataLine) AudioSystem.getLine(targetInfo);
targetLine.open(format);
targetLine.start();
SourceDataLine sourceLine = (SourceDataLine) AudioSystem.getLine(sourceInfo);
sourceLine.open(format);
sourceLine.start();
int numBytesRead;
byte[] targetData = new byte[targetLine.getBufferSize() / 5];
I expect the output to be like Frequency of every sound that is coming from microphone.

How to capture sound in Java?

I'm trying to capture the sound of the PC. I have managed to capture the sound that enters the microphone through TargetDataLine, but I cannot find the way to capture the sound that comes out of the speakers.
I've been watching the mixer but I have not managed to capture the sound. I would like to know if someone has done it and if you can give me some clue as to where to start.
Although, your question is not really according to the "rules", here is a code snippet:
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)) {
LOGGER.error("Line not supported");
System.exit(0);
}
microphone = (TargetDataLine) AudioSystem.getLine(info);
microphone.open(format);
microphone.start();
LOGGER.info("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();
}
Get more info from here:
https://www.programcreek.com/java-api-examples/?class=javax.sound.sampled.TargetDataLine&method=read

How to play back raw audio stream?

I receive a stream of audio data (one channel, 16000Hz, 170ms buffer) in my android app and I want to play this audio.
I discovered AudioTrack but when I am playing the sound I only get loud and awkward sound.
My code so far looks like this:
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 16000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, 128000, AudioTrack.MODE_STREAM);
audioTrack.play();
while (true) {
byte[] buf = new byte[32000];
inputStream.readFully(buf);
audioTrack.write(buf, 0, buf.length);
}
How to fix this?
refer to this example: buf size needs to be carefull calculated based on your data, not necessarily random 32000.
int bufsize = AudioTrack.getMinBufferSize(
8000,
AudioFormat.CHANNEL_CONFIGURATION_STEREO,
AudioFormat.ENCODING_PCM_16BIT
);
AudioTrack trackplayer = new AudioTrack(
AudioManager.STREAM_MUSIC, 8000,
AudioFormat.CHANNEL_CONFIGURATION_ STEREO,
AudioFormat.ENCODING_PCM_16BIT,
bufsize,
AudioTrack.MODE_STREAM
);
trackplayer.play();
trackplayer.write(bytes_pkg, 0, bytes_pkg.length);
trackplayer.stop();
trackplayer.release();

Weird behaviout of Java AudioFormat when bits per sample change

I am trying to play a audio stream that is returned to me by a server via UDP. The server uses DPCM to encode the audio, thus every byte contains two audio samples. When I play the audio with 8 bits/sample everything works fine, but when I try with 16 doing AudioFormat DPCM = new AudioFormat(8000,16,1,true,false); the clip is shorter and not so clear. What am I doing wrong?
ByteArrayOutputStream sound_buffer = new ByteArrayOutputStream();
clientRequest = new DatagramPacket( sound_request_buffer, sound_request_buffer.length );
server.send(clientRequest);
for(int i=0;i<100;i++){
buffer = new byte[128];
serverResponse = new DatagramPacket( buffer, buffer.length);
client.receive(serverResponse);
sound_buffer.write(buffer);
}
byte[] encoded_sound = sound_buffer.toByteArray();
byte[] decoded_sound = new byte[2*encoded_sound.length];
byte msnibble = (byte)((encoded_sound[0]>>4) & 0x000F);
decoded_sound[0] = (byte)(msnibble - 8);
byte lsnibble = (byte)(encoded_sound[0] & 0x000F );
decoded_sound[1] = (byte) (decoded_sound[0] + lsnibble - 8);
for(int i=1;i<encoded_sound.length;i++){
msnibble = (byte)((encoded_sound[i] >> 4) & 0x000F);
decoded_sound[2*i] = (byte)(decoded_sound[2*i-1] + msnibble - 8);
lsnibble = (byte)(encoded_sound[i] & 0x000F );
decoded_sound[2*i+1] = (byte)(decoded_sound[2*i] + lsnibble - 8);
}
AudioFormat DPCM = new AudioFormat(8000,8,1,true,false);
SourceDataLine lineOut=AudioSystem.getSourceDataLine(DPCM);
lineOut.open(DPCM,decoded_sound.length);
lineOut.start();
lineOut.write(decoded_sound,0,decoded_sound.length);
The problem is that you are giving the SourceDataLine 8-bit audio and telling it to play it as if it were 16-bit audio. This will make it halve the playback time (because it uses twice the number of bits per sample). It also does weird stuff with the actual numbers that are used for the sound, but I'm not exactly sure what (I haven't tested your example.)
The AudioFormat doesn't format the audio, it tells the SourceDataLine how your audio is currently formatted so that it plays it correctly.
I'm not really sure what you want to do, and I guess it would depend on why you want 16-bit audio. You might need to request 16-bit audio from the server instead of 8-bit, or you might not even need the audio to be 16-bit.

Java capture audio with pulseaudio

i'm trying to capture/play audio with java in linux with pulseaudio server.
there's no problem with playing.
i can open capture device (microphone) but when calling micro.available returns 0 forever.
any tip ?
audioFormat = new AudioFormat(44100, 16, 2, true, false);
targetInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
sourceInfo = new DataLine.Info(SourceDataLine.class, audioFormat);
targetDataLine = (TargetDataLine) AudioSystem.getTargetDataLine(audioFormat);
targetDataLine.open();
targetDataLine.start();
sourceDataLine = (SourceDataLine) AudioSystem.getLine(sourceInfo);
sourceDataLine.open(audioFormat);
The problem is in the sun jdk. With openjdk it works.

Categories