Java FXML 录音机无法排空目标数据线
Java FXML sound recorder can't drain target data line
编辑: 我通过更改几行找到了解决方案,问题只是部分是由于坏循环造成的。这是问题的主要部分:
'''
public void recordStop(){
System.out.println("stop recording");
recordingRunning = false;
if (dataLine != null) {
dataLine.flush();
dataLine.close();
System.out.println("close and drain line");
}
}
'''
使用 .drain() 会杀死线程,所以只使用 .flush() 来代替,我们不寒而栗。
(TLDR - 当我按下一个按钮来排空目标数据行时,调用的函数将尝试排空该行,但 GUI 将崩溃并且没有文件输出)
我一直在用 JavaFXML 制作录音机,使用 java 声音采样 class。当 GUI 运行ning 时,我正在使用单独的线程 运行 记录器,但是在尝试停止记录并保存记录时会出现问题。我已经设法让线程正常启动,并在按下按钮时 运行。这是通过以下代码激活的:
按下按钮时的 FXML 事件处理程序:
'''
@FXML
private void recordingButtonAction(ActionEvent event) throws LineUnavailableException {
if(isRecording == false){
label.setText("Recording");
fileName = RT.setFileName();
channelLocationTracker(channelSelectToggleGroup);
try{
TargetDataLine dataLine =AudioSystem.getTargetDataLine(audioFormat);
}
catch (LineUnavailableException ex) {
ex.printStackTrace();
}
isRecording=true;
}
else{
System.out.println("Already recording");
}
}
'''
开始单独记录的代码 class 其中对象 "RT" 来自:
'''
public TargetDataLine getDataLine() throws LineUnavailableException{
audioFormat = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
if (!AudioSystem.isLineSupported(info)) {
throw new LineUnavailableException(
"Format Unsupported");
}
final TargetDataLine dataLine = AudioSystem.getTargetDataLine(audioFormat);;
AudioSystem.getLine(info);
return dataLine;
}
'''
'''
public void recordStart(boolean isRecording) throws LineUnavailableException{
isRecording = false;
audioFormat = getAudioFormat();
dataLine = getDataLine();
dataLine.open(audioFormat);
dataLine.start();
System.out.println("open line");
System.out.println("start recording");
byte[] buffer = new byte[bufferSz];
int bytesRead = 0;
recordedBytes = new ByteArrayOutputStream();
isRecording = true;
while (isRecording) {
bytesRead = getDataLine().read(buffer, 0, buffer.length);
recordedBytes.write(buffer, 0, bytesRead);
}
}
'''
以及线程本身:
'''
private void startRecord(){
Thread startRec = new Thread(new Runnable(){
public void run(){
try {
isRecording=true;
RT.recordStart(isRecording);
} catch (LineUnavailableException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
startRec.start();
}
'''
当我按下停止记录按钮时出现问题,它会在 shell 中打印引流线,但 GUI 会崩溃并且不会打印停止记录。我认为问题来自 .drain() 方法。
这里又是 FXML:
'''
@FXML
private void stopButtonAction(ActionEvent event) throws IOException, LineUnavailableException,
UnsupportedAudioFileException {
RT.setFileName("recording"+".wav");
recordedFileWAV = RT.getFile();
if(isRecording == true){
endRecord();
}
}
'''
单独class停止录制:
'''
public void recordStop(boolean isRecording){
isRecording = false;
System.out.println("drain line");
dataLine.drain();
System.out.println("stop recording");
dataLine.close();
}
'''
还有录音中的方法class让你保存:
'''
public void recordSave(File wavFile) throws IOException {
byte[] lineData = recordedBytes.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(lineData);
AudioInputStream AIS = new AudioInputStream(bais, audioFormat,lineData.length /
audioFormat.getFrameSize());
AudioSystem.write(AIS, AudioFileFormat.Type.WAVE, wavFile);
AIS.close();
recordedBytes.close();
}
如果你能弄清楚哪里出了问题,或者你能给我指明正确的方向,请告诉我:)
以下建议更多地针对一般原则和最佳实践。我没有花时间检查你的代码的细节,除了对我在你的 public 停止和保存方法中看到的内容做出反应。
您在自己的线程中进行了录制(应该如此)。与另一个线程交互的通常方式是使用松散耦合。因此,在您的 public 停止和保存方法中,限制您自己设置一个标志,例如 isRecording
。然后,让控制播放的线程中的代码参考那个布尔值。例如,有一个外循环 while(isRecording)
.
我在将 JavaFX 与 javax.sound.sampled 结合使用时成功地使用了这种松散耦合设计模式,用于控制播放和保存到文件。以这种方式做事有助于澄清 类、实例和线程之间可能发生的混淆和冲突。
希望这能为您指明方向,解决您遇到的问题。
解决方案:
'''
public void recordStop(){
System.out.println("stop recording");
recordingRunning = false;
if (dataLine != null) {
dataLine.flush();
dataLine.close();
System.out.println("close and drain line");
}
}
'''
编辑: 我通过更改几行找到了解决方案,问题只是部分是由于坏循环造成的。这是问题的主要部分:
'''
public void recordStop(){
System.out.println("stop recording");
recordingRunning = false;
if (dataLine != null) {
dataLine.flush();
dataLine.close();
System.out.println("close and drain line");
}
}
'''
使用 .drain() 会杀死线程,所以只使用 .flush() 来代替,我们不寒而栗。
(TLDR - 当我按下一个按钮来排空目标数据行时,调用的函数将尝试排空该行,但 GUI 将崩溃并且没有文件输出)
我一直在用 JavaFXML 制作录音机,使用 java 声音采样 class。当 GUI 运行ning 时,我正在使用单独的线程 运行 记录器,但是在尝试停止记录并保存记录时会出现问题。我已经设法让线程正常启动,并在按下按钮时 运行。这是通过以下代码激活的:
按下按钮时的 FXML 事件处理程序:
'''
@FXML
private void recordingButtonAction(ActionEvent event) throws LineUnavailableException {
if(isRecording == false){
label.setText("Recording");
fileName = RT.setFileName();
channelLocationTracker(channelSelectToggleGroup);
try{
TargetDataLine dataLine =AudioSystem.getTargetDataLine(audioFormat);
}
catch (LineUnavailableException ex) {
ex.printStackTrace();
}
isRecording=true;
}
else{
System.out.println("Already recording");
}
}
'''
开始单独记录的代码 class 其中对象 "RT" 来自:
'''
public TargetDataLine getDataLine() throws LineUnavailableException{
audioFormat = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
if (!AudioSystem.isLineSupported(info)) {
throw new LineUnavailableException(
"Format Unsupported");
}
final TargetDataLine dataLine = AudioSystem.getTargetDataLine(audioFormat);;
AudioSystem.getLine(info);
return dataLine;
}
''' '''
public void recordStart(boolean isRecording) throws LineUnavailableException{
isRecording = false;
audioFormat = getAudioFormat();
dataLine = getDataLine();
dataLine.open(audioFormat);
dataLine.start();
System.out.println("open line");
System.out.println("start recording");
byte[] buffer = new byte[bufferSz];
int bytesRead = 0;
recordedBytes = new ByteArrayOutputStream();
isRecording = true;
while (isRecording) {
bytesRead = getDataLine().read(buffer, 0, buffer.length);
recordedBytes.write(buffer, 0, bytesRead);
}
}
'''
以及线程本身:
'''
private void startRecord(){
Thread startRec = new Thread(new Runnable(){
public void run(){
try {
isRecording=true;
RT.recordStart(isRecording);
} catch (LineUnavailableException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
startRec.start();
}
'''
当我按下停止记录按钮时出现问题,它会在 shell 中打印引流线,但 GUI 会崩溃并且不会打印停止记录。我认为问题来自 .drain() 方法。
这里又是 FXML:
'''
@FXML
private void stopButtonAction(ActionEvent event) throws IOException, LineUnavailableException,
UnsupportedAudioFileException {
RT.setFileName("recording"+".wav");
recordedFileWAV = RT.getFile();
if(isRecording == true){
endRecord();
}
}
'''
单独class停止录制:
'''
public void recordStop(boolean isRecording){
isRecording = false;
System.out.println("drain line");
dataLine.drain();
System.out.println("stop recording");
dataLine.close();
}
'''
还有录音中的方法class让你保存:
'''
public void recordSave(File wavFile) throws IOException {
byte[] lineData = recordedBytes.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(lineData);
AudioInputStream AIS = new AudioInputStream(bais, audioFormat,lineData.length /
audioFormat.getFrameSize());
AudioSystem.write(AIS, AudioFileFormat.Type.WAVE, wavFile);
AIS.close();
recordedBytes.close();
}
如果你能弄清楚哪里出了问题,或者你能给我指明正确的方向,请告诉我:)
以下建议更多地针对一般原则和最佳实践。我没有花时间检查你的代码的细节,除了对我在你的 public 停止和保存方法中看到的内容做出反应。
您在自己的线程中进行了录制(应该如此)。与另一个线程交互的通常方式是使用松散耦合。因此,在您的 public 停止和保存方法中,限制您自己设置一个标志,例如 isRecording
。然后,让控制播放的线程中的代码参考那个布尔值。例如,有一个外循环 while(isRecording)
.
我在将 JavaFX 与 javax.sound.sampled 结合使用时成功地使用了这种松散耦合设计模式,用于控制播放和保存到文件。以这种方式做事有助于澄清 类、实例和线程之间可能发生的混淆和冲突。
希望这能为您指明方向,解决您遇到的问题。
解决方案:
'''
public void recordStop(){
System.out.println("stop recording");
recordingRunning = false;
if (dataLine != null) {
dataLine.flush();
dataLine.close();
System.out.println("close and drain line");
}
}
'''