Java: How to use microphone input as input for the

2019-07-19 03:15发布

问题:

I want to play the microphone input in realtime using the JavaFX media player (to analyse its frequencies). The problem is, that the MediaPlayer only accepts Strings as source. I know how to write the microphone input into a byte array and into a file.

Using the byte array as source for the MediaPlayer is (for me) not possible. I tried using a temporary file, but that causes the following error:

Exception in thread "JavaFX Application Thread" MediaException: MEDIA_UNSUPPORTED : Empty signature!

I think this is, because I'm using a file as input while I'm still writing new data into it. My full code until now:

public class Music {

static AudioFormat format;
static DataLine.Info info;

public static void input(int i, int j, int pinState) {
    format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);

    try {
        info = new DataLine.Info(TargetDataLine.class, format);
        final TargetDataLine targetLine = (TargetDataLine) AudioSystem.getLine(info);
        targetLine.open();

        AudioInputStream audioStream = new AudioInputStream(targetLine);

        File temp = File.createTempFile("Input", ".wav");
        temp.deleteOnExit();

        Thread targetThread = new Thread() {
            public void run() {
                targetLine.start();
                try {
                    AudioSystem.write(audioStream, AudioFileFormat.Type.WAVE, temp);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };

        targetThread.start();

        Media media = new Media(temp.toURI().toURL().toString());
        MediaPlayer player = new MediaPlayer(media);
        player.setAudioSpectrumThreshold(-100);
        player.setMute(false);
        player.setAudioSpectrumListener(new AudioSpectrumListener() {
             @Override  
             public void spectrumDataUpdate(double timestamp, double duration, float[] magnitudes, float[] phases) {
                 if(Var.nodeController[i] == 3) { //testing if the targetLine should keep on capturing sound
                 } else {
                     targetLine.stop();
                     targetLine.close();
                     player.stop();
                 }
             }
        });
        player.play();
    } catch (LineUnavailableException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}    

}

I need to find a solution to use the microphone input as MediaPlayer input, either using a file or a byte array or any other possible solution.

回答1:

I am going to speculate that the following library might be helpful. https://github.com/SzymonKatra/AudioAnalyzer

Note that it makes use of FFmpeg which claims to be:

A complete, cross-platform solution to record, convert and stream audio and video.

The key component (based on my cursory look-over) seems to be the class FFTAnalyzer.java which the documentation says is based upon an FFT code/algorithm from Princeton.

So, the basic plan (I believe) would be the following:

  1. obtain microphone input (a stream of bytes) from targetdataline
  2. convert N frames of bytes to normalized floats or doubles and package as an array to send to FFTAnalyzer.analyze(double[] samples)
  3. request the analysis results via FFTAnalyzer.getAmplitudes()
  4. examine the result for each equalization band and apply smoothing as appropriate
  5. repeat

I'm unclear as to exactly how much of the library is needed. It could be that since you are not dealing with video or cross-platform issues, only a class or two from this library would be needed.