mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-11 16:17:24 -05:00
386 lines
12 KiB
Java
386 lines
12 KiB
Java
/*******************************************************************************
|
|
* sdr-trunk
|
|
* Copyright (C) 2014-2018 Dennis Sheirer
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
|
* later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with this program.
|
|
* If not, see <http://www.gnu.org/licenses/>
|
|
*
|
|
******************************************************************************/
|
|
package io.github.dsheirer.gui.instrument;
|
|
|
|
import io.github.dsheirer.gui.instrument.decoder.AbstractDecoderPane;
|
|
import io.github.dsheirer.sample.Listener;
|
|
import io.github.dsheirer.sample.buffer.ReusableBuffer;
|
|
import io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster;
|
|
import io.github.dsheirer.source.IControllableFileSource;
|
|
import io.github.dsheirer.source.IFrameLocationListener;
|
|
import io.github.dsheirer.source.wave.ComplexWaveSource;
|
|
import io.github.dsheirer.source.wave.RealWaveSource;
|
|
import javafx.event.ActionEvent;
|
|
import javafx.event.EventHandler;
|
|
import javafx.geometry.Pos;
|
|
import javafx.scene.control.Alert;
|
|
import javafx.scene.control.Button;
|
|
import javafx.scene.control.ButtonType;
|
|
import javafx.scene.control.Label;
|
|
import javafx.scene.control.TextField;
|
|
import javafx.scene.layout.HBox;
|
|
import org.kordamp.ikonli.fontawesome.FontAwesome;
|
|
import org.kordamp.ikonli.javafx.FontIcon;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import javax.sound.sampled.UnsupportedAudioFileException;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
|
|
public class PlaybackController extends HBox implements IFrameLocationListener
|
|
{
|
|
private final static Logger mLog = LoggerFactory.getLogger(PlaybackController.class);
|
|
|
|
private Button mRewindButton;
|
|
private TextField mPlaybackPositionText;
|
|
private Button mPlay1Button;
|
|
private Button mPlay10Button;
|
|
private Button mPlay30Button;
|
|
private Button mPlay100Button;
|
|
private Button mPlay1000Button;
|
|
private Button mPlay2000Button;
|
|
private HBox mControlsBox;
|
|
private Label mFileLabel;
|
|
private EventHandler<ActionEvent> mPlayEventHandler;
|
|
private AbstractDecoderPane mSampleRateListener;
|
|
|
|
private IControllableFileSource mControllableFileSource;
|
|
private ReusableBufferBroadcaster mReusableBufferBroadcaster = new ReusableBufferBroadcaster();
|
|
|
|
public PlaybackController()
|
|
{
|
|
super(10);
|
|
|
|
getChildren().addAll(getControlsBox(), getFileLabel());
|
|
|
|
disableControls();
|
|
}
|
|
|
|
public void setSampleRateListener(AbstractDecoderPane decoderPane)
|
|
{
|
|
mSampleRateListener = decoderPane;
|
|
|
|
if(mSampleRateListener != null && mControllableFileSource != null)
|
|
{
|
|
mSampleRateListener.setSampleRate(mControllableFileSource.getSampleRate());
|
|
}
|
|
}
|
|
|
|
public void load(File file)
|
|
{
|
|
if(file != null && file.isFile())
|
|
{
|
|
if(ComplexWaveSource.supports(file))
|
|
{
|
|
try
|
|
{
|
|
mControllableFileSource = new ComplexWaveSource(file);
|
|
mControllableFileSource.setListener(this);
|
|
((ComplexWaveSource)mControllableFileSource).setListener(mReusableBufferBroadcaster);
|
|
mControllableFileSource.open();
|
|
|
|
if(mSampleRateListener != null)
|
|
{
|
|
mSampleRateListener.setSampleRate(mControllableFileSource.getSampleRate());
|
|
}
|
|
}
|
|
catch(UnsupportedAudioFileException e)
|
|
{
|
|
mLog.error("Unsupported Audio File Type [" + (file != null ? file.getAbsolutePath() : "null") + "]");
|
|
|
|
Alert alert = new Alert(Alert.AlertType.ERROR, "The file type is unsupported.", ButtonType.OK);
|
|
alert.show();
|
|
return;
|
|
}
|
|
catch(IOException ioe)
|
|
{
|
|
mLog.error("Error opening file [" + (file != null ? file.getAbsolutePath() : "null") + "]", ioe);
|
|
|
|
Alert alert = new Alert(Alert.AlertType.ERROR, "There was an error opening the file",
|
|
ButtonType.OK);
|
|
alert.show();
|
|
return;
|
|
}
|
|
|
|
enableControls();
|
|
}
|
|
else if(RealWaveSource.supports(file))
|
|
{
|
|
try
|
|
{
|
|
mControllableFileSource = new RealWaveSource(file);
|
|
mControllableFileSource.setListener(this);
|
|
((RealWaveSource)mControllableFileSource).setListener(mReusableBufferBroadcaster);
|
|
mControllableFileSource.open();
|
|
|
|
if(mSampleRateListener != null)
|
|
{
|
|
mSampleRateListener.setSampleRate(mControllableFileSource.getSampleRate());
|
|
}
|
|
}
|
|
catch(UnsupportedAudioFileException e)
|
|
{
|
|
mLog.error("Unsupported Audio File Type [" + (file != null ? file.getAbsolutePath() : "null") + "]");
|
|
|
|
Alert alert = new Alert(Alert.AlertType.ERROR, "The file type is unsupported.", ButtonType.OK);
|
|
alert.show();
|
|
return;
|
|
}
|
|
catch(IOException ioe)
|
|
{
|
|
mLog.error("Error opening file [" + (file != null ? file.getAbsolutePath() : "null") + "]", ioe);
|
|
|
|
Alert alert = new Alert(Alert.AlertType.ERROR, "There was an error opening the file",
|
|
ButtonType.OK);
|
|
alert.show();
|
|
return;
|
|
}
|
|
|
|
enableControls();
|
|
}
|
|
|
|
getFileLabel().setText(file.getName());
|
|
}
|
|
}
|
|
|
|
public void close()
|
|
{
|
|
if(mControllableFileSource != null)
|
|
{
|
|
try
|
|
{
|
|
mControllableFileSource.close();
|
|
}
|
|
catch(IOException ioe)
|
|
{
|
|
mLog.error("Error closing file", ioe);
|
|
}
|
|
}
|
|
|
|
disableControls();
|
|
}
|
|
|
|
/**
|
|
* Adds listener to receive complex buffers from this playback
|
|
*/
|
|
public void addListener(Listener<ReusableBuffer> listener)
|
|
{
|
|
mReusableBufferBroadcaster.addListener(listener);
|
|
}
|
|
|
|
/**
|
|
* Removes the listener from receiving complex buffers from this playback
|
|
*/
|
|
public void removeListener(Listener<ReusableBuffer> listener)
|
|
{
|
|
mReusableBufferBroadcaster.removeListener(listener);
|
|
}
|
|
|
|
/**
|
|
* Sets all of the playback controls to the specified enabled state.
|
|
*/
|
|
private void disableControls()
|
|
{
|
|
getRewindButton().setDisable(true);
|
|
getPlaybackPositionText().setDisable(true);
|
|
getPlay1Button().setDisable(true);
|
|
getPlay10Button().setDisable(true);
|
|
getPlay100Button().setDisable(true);
|
|
getPlay1000Button().setDisable(true);
|
|
}
|
|
|
|
/**
|
|
* Sets all of the playback controls to the specified enabled state.
|
|
*/
|
|
private void enableControls()
|
|
{
|
|
getRewindButton().setDisable(false);
|
|
getPlaybackPositionText().setDisable(false);
|
|
getPlay1Button().setDisable(false);
|
|
getPlay10Button().setDisable(false);
|
|
getPlay100Button().setDisable(false);
|
|
getPlay1000Button().setDisable(false);
|
|
}
|
|
|
|
private HBox getControlsBox()
|
|
{
|
|
if(mControlsBox == null)
|
|
{
|
|
mControlsBox = new HBox();
|
|
|
|
mControlsBox.getChildren().addAll(getRewindButton(), getPlaybackPositionText(), getPlay1Button(),
|
|
getPlay10Button(), getPlay30Button(), getPlay100Button(), getPlay1000Button(), getPlay2000Button());
|
|
}
|
|
|
|
return mControlsBox;
|
|
}
|
|
|
|
|
|
private Button getRewindButton()
|
|
{
|
|
if(mRewindButton == null)
|
|
{
|
|
mRewindButton = new Button();
|
|
mRewindButton.setGraphic(new FontIcon(FontAwesome.FAST_BACKWARD));
|
|
}
|
|
|
|
return mRewindButton;
|
|
}
|
|
|
|
private Button getPlay1Button()
|
|
{
|
|
if(mPlay1Button == null)
|
|
{
|
|
mPlay1Button = new Button("1");
|
|
mPlay1Button.setUserData(1);
|
|
mPlay1Button.setOnAction(getPlaybackEventHandler());
|
|
mPlay1Button.setGraphic(new FontIcon(FontAwesome.PLAY));
|
|
}
|
|
|
|
return mPlay1Button;
|
|
}
|
|
|
|
private Button getPlay10Button()
|
|
{
|
|
if(mPlay10Button == null)
|
|
{
|
|
mPlay10Button = new Button("10");
|
|
mPlay10Button.setUserData(10);
|
|
mPlay10Button.setOnAction(getPlaybackEventHandler());
|
|
mPlay10Button.setGraphic(new FontIcon(FontAwesome.FAST_FORWARD));
|
|
}
|
|
|
|
return mPlay10Button;
|
|
}
|
|
|
|
private Button getPlay30Button()
|
|
{
|
|
if(mPlay30Button == null)
|
|
{
|
|
mPlay30Button = new Button("30");
|
|
mPlay30Button.setUserData(30);
|
|
mPlay30Button.setOnAction(getPlaybackEventHandler());
|
|
mPlay30Button.setGraphic(new FontIcon(FontAwesome.FAST_FORWARD));
|
|
}
|
|
|
|
return mPlay30Button;
|
|
}
|
|
|
|
private Button getPlay100Button()
|
|
{
|
|
if(mPlay100Button == null)
|
|
{
|
|
mPlay100Button = new Button("100");
|
|
mPlay100Button.setUserData(100);
|
|
mPlay100Button.setOnAction(getPlaybackEventHandler());
|
|
mPlay100Button.setGraphic(new FontIcon(FontAwesome.FAST_FORWARD));
|
|
}
|
|
|
|
return mPlay100Button;
|
|
}
|
|
|
|
private Button getPlay1000Button()
|
|
{
|
|
if(mPlay1000Button == null)
|
|
{
|
|
mPlay1000Button = new Button("1000");
|
|
mPlay1000Button.setUserData(1000);
|
|
mPlay1000Button.setOnAction(getPlaybackEventHandler());
|
|
mPlay1000Button.setGraphic(new FontIcon(FontAwesome.FAST_FORWARD));
|
|
}
|
|
|
|
return mPlay1000Button;
|
|
}
|
|
|
|
private Button getPlay2000Button()
|
|
{
|
|
if(mPlay2000Button == null)
|
|
{
|
|
mPlay2000Button = new Button("2000");
|
|
mPlay2000Button.setUserData(2000);
|
|
mPlay2000Button.setOnAction(getPlaybackEventHandler());
|
|
mPlay2000Button.setGraphic(new FontIcon(FontAwesome.FAST_FORWARD));
|
|
}
|
|
|
|
return mPlay2000Button;
|
|
}
|
|
|
|
private EventHandler<ActionEvent> getPlaybackEventHandler()
|
|
{
|
|
if(mPlayEventHandler == null)
|
|
{
|
|
mPlayEventHandler = new EventHandler<ActionEvent>()
|
|
{
|
|
@Override
|
|
public void handle(ActionEvent event)
|
|
{
|
|
int count = (int)((Button)event.getSource()).getUserData();
|
|
|
|
if(mControllableFileSource != null)
|
|
{
|
|
try
|
|
{
|
|
mControllableFileSource.next(count, true);
|
|
}
|
|
catch(IOException ioe)
|
|
{
|
|
mLog.error("Error while playing samples");
|
|
}
|
|
}
|
|
|
|
}
|
|
};
|
|
}
|
|
|
|
return mPlayEventHandler;
|
|
}
|
|
|
|
private TextField getPlaybackPositionText()
|
|
{
|
|
if(mPlaybackPositionText == null)
|
|
{
|
|
mPlaybackPositionText = new TextField("0");
|
|
mPlaybackPositionText.setAlignment(Pos.CENTER);
|
|
mPlaybackPositionText.setPrefWidth(80);
|
|
}
|
|
|
|
return mPlaybackPositionText;
|
|
}
|
|
|
|
private Label getFileLabel()
|
|
{
|
|
if(mFileLabel == null)
|
|
{
|
|
mFileLabel = new Label();
|
|
}
|
|
|
|
return mFileLabel;
|
|
}
|
|
|
|
@Override
|
|
public void frameLocationUpdated(int location)
|
|
{
|
|
getPlaybackPositionText().setText(String.valueOf(location));
|
|
}
|
|
|
|
@Override
|
|
public void frameLocationReset()
|
|
{
|
|
mLog.info("Frame location reset ... ignoring?");
|
|
}
|
|
}
|