Java F XML звукозапись не может истощить целевую линию данных - PullRequest
2 голосов
/ 10 марта 2020

Редактировать: Я нашел решение, изменив всего несколько строк, проблема была только частично из-за плохих циклов. Это было основной частью проблемы:

'' '

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 () убивает поток, поэтому просто использовал .flu sh () вместо этого и мы пугаем.

(TLDR - когда я нажимаю кнопку, чтобы опустошить целевую строку данных, вызываемая функция будет пытаться опустошить линию, но GUI создаст sh и файл не будет выведен)

Я делаю аудиозапись с JavaF XML, используя java класс сэмплированных звуков . Я использую отдельный поток для запуска рекордера во время работы GUI, но проблема возникает при попытке остановить запись и сохранить запись. Мне удалось заставить поток начаться хорошо и запустить при нажатии кнопки. Активируется этим кодом:

Обработчик события F XML при нажатии кнопки:

'' '

    @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");
    }
}

' ''

Код для начала записи в отдельном классе, откуда происходит объект "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();
     }

'' '

Возникла проблема Когда я нажимаю кнопку остановки записи, она будет печатать сливную линию в оболочке, но GUI будет обрабатывать sh, и запись, остановленная, не будет напечатана. Я думаю, что проблема связана с методом .drain ().

Еще раз вот F XML:

'' '

    @FXML
    private void stopButtonAction(ActionEvent event) throws IOException, LineUnavailableException, 
    UnsupportedAudioFileException {    
       RT.setFileName("recording"+".wav");
       recordedFileWAV = RT.getFile();
       if(isRecording == true){
       endRecord();
       }

    }

'' '

Отдельный класс для остановки записи:

' ''

    public void recordStop(boolean isRecording){
    isRecording = false;
    System.out.println("drain line");
    dataLine.drain();
    System.out.println("stop recording");
    dataLine.close();


    }

'' '

И метод в записи класс, который вы можете сохранить:

'' '

    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();
    }

Пожалуйста, дайте мне знать, если вы можете выяснить, что происходит не так или вы можете указать мне в правильном направлении:)

Ответы [ 2 ]

1 голос
/ 10 марта 2020

Следующий совет больше касается общих принципов и лучших практик. Я не потратил время на проверку деталей вашего кода, кроме реакции на то, что я вижу в ваших публицистических c методах остановки и сохранения.

Запись выполняется в собственном потоке (как это должно). Обычный способ взаимодействия с другим потоком - использовать слабую связь. Таким образом, в ваших публикациях c методы остановки и сохранения ограничьте себя установкой флага, например isRecording. Затем получите код в потоке, который управляет воспроизведением, и обратитесь к этому логическому значению. Например, иметь внешний l oop while(isRecording).

. У меня был успех с этим использованием шаблона проектирования со слабой связью при использовании JavaFX с javax.sound.sampled, для управления воспроизведением и для сохранения в файл. Подобные действия помогают прояснить путаницу и конфликты, которые могут возникнуть между классами, экземплярами и потоками.

Надеюсь, это укажет вам направление, которое поможет вам решить проблемы, с которыми вы сталкиваетесь.

0 голосов
/ 15 марта 2020

Решение:

'' '

public void recordStop(){
System.out.println("stop recording");
recordingRunning = false;
if (dataLine != null) {
    dataLine.flush();
    dataLine.close();
    System.out.println("close and drain line");
}

}

' ''

...