Simulate microphone Input - java

I am trying to write a little program that reads a wav file and sends the output as if it would come from my microphone. Unfortunately I do not have much experience with the sound API.
Background: What I am basically trying to realize is a program that plays a sound while I am in a voicechat (i.e Teamspeak, Ventrilo). To get that to work now I would have to switch the recording device to "What you hear", play the sound and then switch back to microphone. The program should simulate input from the microphone.
So far I could not get any further than just playing the sound. I guess I just need a different SourceLine?
public class Player {
private final int BUFFER_SIZE = 128000;
private AudioInputStream audioStream;
private AudioFormat audioFormat;
private SourceDataLine sourceLine;
public void playSound(File soundFile) {
try {
audioStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
audioFormat = audioStream.getFormat();
DataLine.Info infoIn = new DataLine.Info(SourceDataLine.class,
audioFormat);
try {
sourceLine = (SourceDataLine) AudioSystem.getLine(infoIn);
sourceLine.open(audioFormat);
} catch (LineUnavailableException e) {
e.printStackTrace();
System.exit(1);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
sourceLine.start();
int nBytesRead = 0;
byte[] abData = new byte[BUFFER_SIZE];
while (nBytesRead != -1) {
try {
nBytesRead = audioStream.read(abData, 0, abData.length);
} catch (IOException e) {
e.printStackTrace();
}
if (nBytesRead >= 0) {
#SuppressWarnings("unused")
int nBytesWritten = sourceLine.write(abData, 0, nBytesRead);
}
}
sourceLine.drain();
sourceLine.close();
}
}
Solution:
Install VB Audio Cable (http://vb-audio.pagesperso-orange.fr/Cable/). It's donationware. Make VB-Output standard recording device. In the microphone properties choose VB-Input as playback.
public class Player {
private final int BUFFER_SIZE = 128000;
private AudioInputStream audioStream;
private AudioFormat audioFormat;
private SourceDataLine sourceLine;
public void playSound(File soundFile) {
try {
audioStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
audioFormat = audioStream.getFormat();
DataLine.Info infoIn = new DataLine.Info(SourceDataLine.class,
audioFormat);
try {
Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo();
Mixer mixer = null;
for (int i = 0; i < mixerInfos.length; i++) {
System.out.println(mixerInfos[i].getName());
if (mixerInfos[i].getName().equals(
"CABLE Input (VB-Audio Virtual Cable)")) {
mixer = AudioSystem.getMixer(mixerInfos[i]);
break;
}
}
sourceLine = (SourceDataLine) mixer.getLine(infoIn);
sourceLine.open(audioFormat);
} catch (LineUnavailableException e) {
e.printStackTrace();
System.exit(1);
}
sourceLine.start();
int nBytesRead = 0;
byte[] abData = new byte[BUFFER_SIZE];
while (nBytesRead != -1) {
try {
nBytesRead = audioStream.read(abData, 0, abData.length);
} catch (IOException e) {
e.printStackTrace();
}
if (nBytesRead >= 0) {
#SuppressWarnings("unused")
int nBytesWritten = sourceLine.write(abData, 0, nBytesRead);
}
}
sourceLine.drain();
sourceLine.close();
}
}

You can install some program like Virtual Audio Cable and from your music player redirect playing sound to virtual input. In your program you must listen that virtual input source and you can for test redirect to normal headphones or speaker received signal or saved it to file.

Related

Java Voice Server Not Working

I am trying to make a voice server and the server is throwing this error "javax.sound.sampled.LineUnavailableException: line with format PCM_SIGNED 8000.0 Hz, 8 bit, mono, 1 bytes/frame, not supported.". Here is my code, Thank you in advance
public class VoiceUser extends Thread { // CHAT USER
private ObjectOutputStream clientOutput;
public VoiceUser(Socket sv) {
try {
System.out.println("VSTART");
clientOutput = new ObjectOutputStream(sv.getOutputStream());
outputArray.add(clientOutput);
} catch (IOException e) {
System.out.println("Can't create stable connection between server and client");
}
}
public void run() {
try {
AudioFormat af = new AudioFormat(8000.0f,8,1,true,false);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, af);
TargetDataLine microphone = (TargetDataLine)AudioSystem.getLine(info);
microphone.open(af);
microphone.start();
int bytesRead = 0;
byte[] soundData = new byte[1];
while(bytesRead != -1)
{
bytesRead = microphone.read(soundData, 0, soundData.length);
System.out.println(soundData.length);
if(bytesRead >= 0)
{
for(ObjectOutputStream o : outputArray) {
o.write(soundData, 0, bytesRead);
}
}
}
} catch (IOException | LineUnavailableException e) {
e.printStackTrace();
}
}
}

Starting and stopping music files in Java?

This is my sound class.
public class Sounds extends Thread {
private String filename;
private Position curPosition;
private final int EXTERNAL_BUFFER_SIZE = 524288;
enum Position {
LEFT, RIGHT, NORMAL
};
public Sounds(String wavFile) {
filename = wavFile;
curPosition = Position.NORMAL;
}
public Sounds(String wavfile, Position p) {
filename = wavfile;
curPosition = p;
}
public void run() {
File soundFile = new File(filename);
if (!soundFile.exists()) {
System.err.println(".wav file not found: " + filename);
return;
}
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(soundFile);
} catch (UnsupportedAudioFileException e1) {
e1.printStackTrace();
return;
} catch (IOException e1) {
e1.printStackTrace();
return;
}
AudioFormat format = audioInputStream.getFormat();
SourceDataLine auline = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try {
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
} catch (LineUnavailableException e) {
e.printStackTrace();
return;
} catch (Exception e) {
e.printStackTrace();
return;
}
if (auline.isControlSupported(FloatControl.Type.PAN)) {
FloatControl pan = (FloatControl) auline
.getControl(FloatControl.Type.PAN);
if (curPosition == Position.RIGHT)
pan.setValue(1.0f);
else if (curPosition == Position.LEFT)
pan.setValue(-1.0f);
}
auline.start();
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
try {
while (nBytesRead != -1) {
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0)
auline.write(abData, 0, nBytesRead);
}
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
auline.drain();
auline.close();
}
}
}
And this is my ActionListener that I want to stop the music when the user clicks a button. The music plays on start up.
btnSound.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
btnSound.setVisible(false);
btnNoSound.setVisible(true);
new Sounds("Sounds/MenuMusic.wav").end();
}
});
I can get the music to play just fine, but I can't figure out how to stop it. I tried using .stop() and .end() but I was told they were deprecated. Anyone have any idea how I can do this? thanks.
You could use the clip class. This is my code for reading a .wav file and playing it:
try {
File file = new File(src); // src is the location of the file
AudioInputStream stream = AudioSystem.getAudioInputStream(file);
Clip clip = AudioSystem.getClip();
clip.open(stream);
clip.start();
} catch (Exception e) {
e.printStackTrace();
}
That was, clip.stop() will stop the clip. To reset the clip, use clip.setFramePosition(0). Note that clip does not need to be closed, because if clip.close() is called after clip.start(), the clip will not play.
Hope that's what you were looking for!
EDIT: Scoping
Using scoping in Java, if you declare a local variable in a method, you cannot access it outside of the method. If you want to access the clip outside of the main method, extract it to a field:
class Main {
static Clip clip;
public static void main (String... args) {
try {
File file...
clip = AudioSystem.getClip();
...
} catch...
}
}

How can I print sound as byte array? or int array?

I'm making anti-phase sound with java.(anti-phase is reflected wave. x-coordinate is not changed, but y-coordinate is upside down.)
Before reflecting sound wave, I have to get byte array(or int array) from sound.
I get sound from microphone of my laptop.
Here is my CODE(I got original code, which record sound as file, in web. I modified it little)
public class NoiseController extends Thread{
private TargetDataLine line;
private AudioInputStream audioInputStream;
public NoiseController(TargetDataLine line) {
this.line = line;
this.audioInputStream = new AudioInputStream(line);
}
public void start() {
line.start();
super.start();
}
public void stopRecording() {
line.stop();
line.close();
}
public void run() {
try {
int packet;
while((packet = audioInputStream.read()) != -1)
System.out.println(packet);
}
catch(IOException ioe) {
ioe.getStackTrace();
}
}
public static void main(String[] args) {
AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100.0F, 16, 2, 4, 44100.0F, false);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
TargetDataLine targetDataLine = null;
try {
targetDataLine = (TargetDataLine)AudioSystem.getLine(info);
targetDataLine.open(audioFormat);
}
catch(LineUnavailableException lue) {
out("unable to get a recording line");
lue.printStackTrace();
System.exit(-1);
}
AudioFileFormat.Type targetType = AudioFileFormat.Type.WAVE;
NoiseController recorder = new NoiseController(targetDataLine);
System.out.println(targetDataLine);
System.out.println(targetType);
out("Press ENTER to start the recording.");
try {
System.in.read();
}
catch(IOException ioe) {
ioe.printStackTrace();
}
recorder.start();
out("Recording...");
out("Press ENTER to stop the recording.");
try {
System.in.read();
System.in.read();
}
catch(IOException ioe) {
ioe.getStackTrace();
}
recorder.stopRecording();
out("Recording stopped.");
}
private static void out(String msg) {
System.out.println(msg);
}
}
However, Console doesn't print anything while recording...
It shows just
com.sun.media.sound.DirectAudioDevice$DirectTDL#25154f_
WAVE
Press ENTER to start the recording.
Recording...
Press ENTER to stop the recording.
Recording stopped.
If I edit run() like AudioSystem.write(stream, fileType, out);
instead of
int packet;
while((packet = audioInputStream.read()) != -1)
System.out.println(packet);
program saves wav file.
What is wrong in my program?
you are not printing the Exception as Uwe Allner said.
I´ve also try to correct it and I think the result must be like this:
public class NoiseController extends Thread {
private final TargetDataLine line;
private final AudioInputStream audioInputStream;
public NoiseController(final TargetDataLine line) {
this.line = line;
this.audioInputStream = new AudioInputStream(line);
}
#Override
public void start() {
line.start();
super.start();
}
public void stopRecording() {
line.stop();
line.close();
try {
audioInputStream.close();
} catch (final IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
try {
final int bufferSize = 1024;
int read = 0;
final byte[] frame = new byte[bufferSize];
while ((read = audioInputStream.read(frame)) != -1 && line.isOpen()) {
// only the first read bytes are valid
System.out.println(Arrays.toString(frame));
}
} catch (final IOException ioe) {
ioe.printStackTrace();
}
}
public static void main(final String[] args) {
final AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100.0F, 16, 2, 4, 44100.0F, false);
final DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
TargetDataLine targetDataLine = null;
try {
targetDataLine = (TargetDataLine) AudioSystem.getLine(info);
targetDataLine.open(audioFormat);
} catch (final LineUnavailableException lue) {
out("unable to get a recording line");
lue.printStackTrace();
System.exit(-1);
}
final AudioFileFormat.Type targetType = AudioFileFormat.Type.WAVE;
final NoiseController recorder = new NoiseController(targetDataLine);
System.out.println(targetDataLine);
System.out.println(targetType);
out("Press ENTER to start the recording.");
try {
System.in.read();
} catch (final IOException ioe) {
ioe.printStackTrace();
}
recorder.start();
out("Recording...");
out("Press ENTER to stop the recording.");
try {
System.in.read();
System.in.read();
} catch (final IOException ioe) {
ioe.printStackTrace();
}
recorder.stopRecording();
out("Recording stopped.");
}
private static void out(final String msg) {
System.out.println(msg);
}
}

The Most efficient way of playing wav sound Java

I am developing a drum metronome. So I have .wav sound files and I need to play them with using minimum computer memory and CPU because it's very important for the metronome to play the sample on the exact time. Currently I use the code from this link
How to play .wav files with java
class MakeSound {
private final int BUFFER_SIZE = 128000;
private File soundFile;
private AudioInputStream audioStream;
private AudioFormat audioFormat;
private SourceDataLine sourceLine;
/**
* #param filename the name of the file that is going to be played
*/
public void playSound(String filename){
String strFilename = filename;
try {
soundFile = new File(strFilename);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
try {
audioStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e){
e.printStackTrace();
System.exit(1);
}
audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
try {
sourceLine = (SourceDataLine) AudioSystem.getLine(info);
sourceLine.open(audioFormat);
} catch (LineUnavailableException e) {
e.printStackTrace();
System.exit(1);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
sourceLine.start();
int nBytesRead = 0;
byte[] abData = new byte[BUFFER_SIZE];
while (nBytesRead != -1) {
try {
nBytesRead = audioStream.read(abData, 0, abData.length);
} catch (IOException e) {
e.printStackTrace();
}
if (nBytesRead >= 0) {
#SuppressWarnings("unused")
int nBytesWritten = sourceLine.write(abData, 0, nBytesRead);
}
}
sourceLine.drain();
sourceLine.close();
}
}
This code works but it's too slow for using it in a metronome app. So which is the fastest way of playing wav sound files. Please take into account that sometimes I need to play them simultaneously so the sound should play as a separate thread I think.
Thanks
i am assuming that you have a working method that looks like this:
example #1: (don't do this)
public void startMetronome(){
boolean abort = false;
String audoFileName = new String("myAudioFile);
do{
playSound(audoFileName );
while(abort != false);
}
or maybe you've done some better implementation like this:
exapmle#2: (don't do this either)
Runnable r = new Runnable(){
boolean abort = false;
String audoFileName = new String("myAudioFile);
do{
playSound(audoFileName );
try{
Thread.sleep(500);
}catch (Exception e);
while(abort != false);
}
new Thread(r).start();
in any case you're doing a big mistake: you initialize every time you play a sound the sound line and every time you load the file again and again.
but thats a toally wrong approach, you have to load the file once, open the line once and play the sound repetially on the line!
(cheap) solution #3:
adjust your playSoundmethode like this:
public void playSound(String filename){
//same as above
String strFilename = filename;
soundFile = new File(strFilename); //i've shorened the catch/throws, to make it more readable
audioStream = AudioSystem.getAudioInputStream(soundFile);
audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
sourceLine = (SourceDataLine) AudioSystem.getLine(info);
sourceLine.open(audioFormat);
sourceLine.start();
//right now, the line is set up and all data is availible
boolean isRunning = true;
while(isRunning){ //this is an endless loop!
int nBytesRead = 0;
byte[] abData = new byte[BUFFER_SIZE];
while (nBytesRead != -1) {
nBytesRead = audioStream.read(abData, 0, abData.length);
//and your timing here
try{
Thread.sleep(500);
}catch (Exception e);
}
sourceLine.drain();
sourceLine.close();
}
and best practice would be to play the whole thing in an seperate thread... (as example #2)

How to play .wav files in java without lag for games

I have a game that I want to play audio in. What I want to be able to do is that I should be able to declare a ClipPlayer object with the arguments of a path name. Then the constructor should be able to load the sound and then I can just make a call with that object so it won't lag. This is the code that I am using currently for sound:
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
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.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
public class ClipPlayer {
AudioInputStream in;
AudioFormat decodedFormat;
AudioInputStream din;
AudioFormat baseFormat;
SourceDataLine line;
private boolean loop;
private BufferedInputStream stream;
// private ByteArrayInputStream stream;
/**
* recreate the stream
*
*/
public void reset() {
try {
stream.reset();
in = AudioSystem.getAudioInputStream(stream);
din = AudioSystem.getAudioInputStream(decodedFormat, in);
line = getLine(decodedFormat);
} catch (Exception e) {
e.printStackTrace();
}
}
public void close() {
try {
line.close();
din.close();
in.close();
} catch (IOException e) {
}
}
ClipPlayer(String filename, boolean loop) {
this(filename);
this.loop = loop;
}
ClipPlayer(String filename) {
this.loop = false;
try {
InputStream raw = Object.class.getResourceAsStream(filename);
stream = new BufferedInputStream(raw);
// ByteArrayOutputStream out = new ByteArrayOutputStream();
// byte[] buffer = new byte[1024];
// int read = raw.read(buffer);
// while( read > 0 ) {
// out.write(buffer, 0, read);
// read = raw.read(buffer);
// }
// stream = new ByteArrayInputStream(out.toByteArray());
in = AudioSystem.getAudioInputStream(stream);
din = null;
if (in != null) {
baseFormat = in.getFormat();
decodedFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED, baseFormat
.getSampleRate(), 16, baseFormat.getChannels(),
baseFormat.getChannels() * 2, baseFormat
.getSampleRate(), false);
din = AudioSystem.getAudioInputStream(decodedFormat, in);
line = getLine(decodedFormat);
}
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
private SourceDataLine getLine(AudioFormat audioFormat)
throws LineUnavailableException {
SourceDataLine res = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class,
audioFormat);
res = (SourceDataLine) AudioSystem.getLine(info);
res.open(audioFormat);
return res;
}
public void play() {
try {
boolean firstTime = true;
while (firstTime || loop) {
firstTime = false;
byte[] data = new byte[4096];
if (line != null) {
line.start();
int nBytesRead = 0;
while (nBytesRead != -1) {
nBytesRead = din.read(data, 0, data.length);
if (nBytesRead != -1)
line.write(data, 0, nBytesRead);
}
line.drain();
line.stop();
line.close();
reset();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Declare, load and cache the sounds as class attributes. Then when it is time to hear them, play them in a Clip.

Categories