0

.wav ファイルを記録および再生する小さなプログラムがあります。GUIクラスには、「停止」ボタン用の次のコードがあります。

private AudioCapture audCap = new AudioCapture();

stopBtn.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            captureBtn.setEnabled(true);
            stopBtn.setEnabled(false);
            playBtn.setEnabled(true);
            audCap.stopCapture = true; // this doesn't work
            audCap.stopPlayback = true; // this does
        }
    }

AudioCapture() クラスには、再生用の次のコードがあり、停止ボタンをクリックすると正しく停止します。

class PlayThread extends Thread {
    byte tempBuffer[] = new byte[10000];

    public void run() {

        stopPlayback = false;

        try {
            sourceDataLine.open(audioFormat);
            sourceDataLine.start();

            int cnt;
            while ((cnt = audioInputStream.read(tempBuffer, 0,
                    tempBuffer.length)) != -1 && stopPlayback == false) {
                if (cnt > 0) {
                    sourceDataLine.write(tempBuffer, 0, cnt);
                }
            }
            sourceDataLine.drain();
            sourceDataLine.close();

        } catch (Exception e) {
            e.printStackTrace();
            System.exit(0);
        }
    }
}

停止ボタンをクリックしても停止しない、記録/キャプチャ用の次のコードもあります。

class CaptureThread extends Thread {
    // An arbitrary-size temporary holding buffer
    byte tempBuffer[] = new byte[10000];

    public void run() {

        stopCapture = false;
        // record as wave
        AudioFileFormat.Type fileType = AudioFileFormat.Type.WAVE;
        // takes user input file name and appends filetype
        audioFile = new File(wavName + ".wav");

        try {
            while (!stopCapture) {

                int cnt = targetDataLine.read(tempBuffer, 0,
                        tempBuffer.length);
                if (cnt > 0) {
                    AudioSystem.write(new AudioInputStream(targetDataLine),
                            fileType, audioFile);
                }
            }
            targetDataLine.stop();
            targetDataLine.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

stopCature と stopPlayback は、AudioCapture() クラスのインスタンス変数です。

私はEclipseを使用していて、「while (!stopCapture)」にブレークポイントを設定しようとしましたが、これを超えることはないようです。上記のコードに、最初のメソッドが期待どおりに機能するが、2番目のメソッドが機能しない原因があるかどうかは誰にもわかりませんか?

-編集-プログラムの縮小バージョンをSSCEに入れようとしましたが、それでも数百行まで実行されます。

import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class audioTest extends JFrame {

private static final long serialVersionUID = 1L;
AudioCapture audCap = new AudioCapture();

public static void main(String[] args) {
    new audioTest();
}

public audioTest() {

    layoutTransporButtons();
    getContentPane().setLayout(new FlowLayout());
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(350, 100);
    setVisible(true);
}

public void layoutTransporButtons() {

    final JPanel guiButtonPanel = new JPanel();
    final JButton captureBtn = new JButton("Record");
    final JButton stopBtn = new JButton("Stop");
    final JButton playBtn = new JButton("Playback");
    guiButtonPanel.setLayout(new GridLayout());
    this.add(guiButtonPanel);
    captureBtn.setEnabled(true);
    stopBtn.setEnabled(false);
    playBtn.setEnabled(true);

    // Register anonymous listeners
    captureBtn.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            captureBtn.setEnabled(false);
            stopBtn.setEnabled(true);
            playBtn.setEnabled(false);
            // Capture input data from the microphone
            audCap.captureAudio();
        }
    });
    guiButtonPanel.add(captureBtn);

    stopBtn.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            captureBtn.setEnabled(true);
            stopBtn.setEnabled(false);
            playBtn.setEnabled(true);
            audCap.stopRecordAndPlayback = true;
        }
    });
    guiButtonPanel.add(stopBtn);

    playBtn.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            stopBtn.setEnabled(true);
            audCap.playAudio();
        }
    });
    guiButtonPanel.add(playBtn);
}

class AudioCapture {

    volatile boolean stopRecordAndPlayback = false;
    AudioFormat audioFormat;
    TargetDataLine targetDataLine;
    AudioInputStream audioInputStream;
    SourceDataLine sourceDataLine;
    private String wavName;
    private File audioFile;
    /**
     *  capture audio input from microphone and save as .wav file
     */
    public void captureAudio() {

        wavName = JOptionPane.showInputDialog(null,
                "enter name of file to be recorded:");
        try {
            Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();
            // Select an available mixer
            Mixer mixer = AudioSystem.getMixer(mixerInfo[1]);
            // Get everything set up for capture
            audioFormat = getAudioFormat();
            DataLine.Info dataLineInfo = new DataLine.Info(
                    TargetDataLine.class, audioFormat);
            // Get a TargetDataLine on the selected mixer.
            targetDataLine = (TargetDataLine) mixer.getLine(dataLineInfo);
            // Prepare the line for use.
            targetDataLine.open(audioFormat);
            targetDataLine.start();
            // Create a thread to capture the microphone
            Thread captureThread = new CaptureThread();
            captureThread.start();
        } catch (Exception e) {
            System.out.println(e);
            System.exit(0);
        }
    }

    /**
     *  This method plays back the audio data that has
     *  been chosen by the user
     */
    public void playAudio() {
        // add file chooser
        JFileChooser chooser = new JFileChooser();
        chooser.setCurrentDirectory(audioFile);
        int returnVal = chooser.showOpenDialog(chooser);
        // retrieve chosen file
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            // create the file
            audioFile = chooser.getSelectedFile();
        }
        // play chosen file
        try {
            audioInputStream = AudioSystem.getAudioInputStream(audioFile);
            audioFormat = audioInputStream.getFormat();
            DataLine.Info dataLineInfo = new DataLine.Info(
                    SourceDataLine.class, audioFormat);
            sourceDataLine = (SourceDataLine) AudioSystem
                    .getLine(dataLineInfo);
            // Create a thread to play back the data
            new PlayThread().start();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(0);
        }
    }
    /**
     *  This method creates and returns an AudioFormat object
     */
    private AudioFormat getAudioFormat() {
        float sampleRate = 44100.0F;
        // 8000,11025,16000,22050,44100
        int sampleSizeInBits = 16;
        // 8,16
        int channels = 1;
        // 1,2
        boolean signed = true;
        // true,false
        boolean bigEndian = false;
        // true,false
        return new AudioFormat(sampleRate, sampleSizeInBits, channels,
                signed, bigEndian);
    }

    /**
     *  Inner class to capture data from microphone
     */
    class CaptureThread extends Thread {
        // An arbitrary-size temporary holding buffer
        byte tempBuffer[] = new byte[10000];

        public void run() {
            // reset stopCapture to false
            stopRecordAndPlayback = false;
            // record as wave
            AudioFileFormat.Type fileType = AudioFileFormat.Type.WAVE;
            // take user input file name and append file type
            audioFile = new File(wavName + ".wav");

            try {
                targetDataLine.open(audioFormat);
                targetDataLine.start();
                while (!stopRecordAndPlayback) {
                    AudioSystem.write(new AudioInputStream(targetDataLine),
                            fileType, audioFile);
                }
                targetDataLine.stop();
                targetDataLine.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
     *  Inner class to play back the data
     */
    class PlayThread extends Thread {
        byte tempBuffer[] = new byte[10000];

        public void run() {
            // reset stop button
            stopRecordAndPlayback = false;

            try {
                sourceDataLine.open(audioFormat);
                sourceDataLine.start();
                int cnt;
                while ((cnt = audioInputStream.read(tempBuffer, 0,
                        tempBuffer.length)) != -1
                        && stopRecordAndPlayback == false) {
                    if (cnt > 0) {
                        sourceDataLine.write(tempBuffer, 0, cnt);
                    }
                }
                sourceDataLine.drain();
                sourceDataLine.close();
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(0);
            }
        }
    }
}

}

4

1 に答える 1

2

必要なすべての情報を提供するわけではありませんが、プログラム内のデータ競合が原因である可能性が非常に高くなります。

異なるスレッドで実行しているため、スレッド間で何らかの形式の同期を使用して、1 つのスレッドで行った変更が他のスレッドで確実に表示されるようにする必要があります。

通常、あなたの場合、ブール変数 volatile を宣言するだけで十分です。

編集

1 つの可能性は、while ループの条件が、考えているほど頻繁に評価されないことです (もしあったとしても)。ログを追加して、何が起こっているかを確認できます。

stopBtn.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        //your code here
        System.out.println("in actionPerformed: " + stopCatpure);
    }
}

class CaptureThread extends Thread {
    //same code
            while (!stopCapture) {
                System.out.println("in while: " + stopCapture);
                //rest of your code
            }
}
于 2012-09-15T12:00:41.417 に答える