Updates to exporter and data map in FX GUI

This commit is contained in:
Jamie Mac 2024-08-21 12:53:53 +01:00
parent 791dad9439
commit 2c11ff435b
28 changed files with 1310 additions and 809 deletions

View File

@ -6,7 +6,7 @@
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk-21.0.2.13-hotspot"> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/Amazon Coretto 21">
<attributes> <attributes>
<attribute name="module" value="true"/> <attribute name="module" value="true"/>
<attribute name="maven.pomderived" value="true"/> <attribute name="maven.pomderived" value="true"/>

View File

@ -65,7 +65,7 @@ public class DataMapPaneFX extends PamBorderPane implements UserDisplayNodeFX {
/** /**
* Pane which allows users to change scale on datamap. * Pane which allows users to change scale on datamap.
*/ */
private ScalePaneFX scalePane; private DataMapSettingsPane dataMapSettingsPane;
private PamVBox settingsPane; private PamVBox settingsPane;
@ -87,14 +87,14 @@ public class DataMapPaneFX extends PamBorderPane implements UserDisplayNodeFX {
//create all the different panes, //create all the different panes,
summaryPane = new SummaryPaneFX(dataMapControl, this); summaryPane = new SummaryPaneFX(dataMapControl, this);
scalePane=new ScalePaneFX(dataMapControl,this);
scrollingDataPanel= new ScrollingDataPaneFX(dataMapControl, this); scrollingDataPanel= new ScrollingDataPaneFX(dataMapControl, this);
dataMapSettingsPane=new DataMapSettingsPane(dataMapControl,this);
//create the setting spane //create the setting spane
settingsPane=new PamVBox(); settingsPane=new PamVBox();
// settingsPane.getChildren().add(summaryPane); // settingsPane.getChildren().add(summaryPane);
settingsPane.getChildren().add(scalePane); settingsPane.getChildren().add(dataMapSettingsPane.getContentNode());
settingsPane.setPadding(new Insets(40,10,10,10)); settingsPane.setPadding(new Insets(40,10,10,10));
settingsPane.setPrefWidth(HIDE_PANE_WIDTH); settingsPane.setPrefWidth(HIDE_PANE_WIDTH);
@ -178,12 +178,11 @@ public class DataMapPaneFX extends PamBorderPane implements UserDisplayNodeFX {
* Called from ScalePanel when anything * Called from ScalePanel when anything
* to do with scaling changes. * to do with scaling changes.
*/ */
@Deprecated
public void scaleChanged() { public void scaleChanged() {
if (scalePane == null || scrollingDataPanel == null) { if (dataMapSettingsPane == null || scrollingDataPanel == null) {
return; return;
} }
scalePane.getParams(dataMapControl.dataMapParameters); dataMapSettingsPane.getParams(dataMapControl.dataMapParameters);
//scrollingDataPanel.scaleChange(); //scrollingDataPanel.scaleChange();
} }
@ -228,24 +227,30 @@ public class DataMapPaneFX extends PamBorderPane implements UserDisplayNodeFX {
switch (changeType) { switch (changeType) {
case PamControllerInterface.INITIALIZATION_COMPLETE: case PamControllerInterface.INITIALIZATION_COMPLETE:
scrollingDataPanel.updateScrollBar(); scrollingDataPanel.updateScrollBar();
scalePane.checkDataGramPane(); dataMapSettingsPane.setParams(dataMapControl.dataMapParameters);
this.repaintAll(); this.repaintAll();
break;
case PamControllerInterface.CHANGED_OFFLINE_DATASTORE: case PamControllerInterface.CHANGED_OFFLINE_DATASTORE:
scrollingDataPanel.updateScrollBar(); scrollingDataPanel.updateScrollBar();
scalePane.checkDataGramPane(); dataMapSettingsPane.checkDataGramPane();
dataMapSettingsPane.setParams(dataMapControl.dataMapParameters);
break;
case PamControllerInterface.ADD_CONTROLLEDUNIT: case PamControllerInterface.ADD_CONTROLLEDUNIT:
scalePane.checkDataGramPane();
case PamControllerInterface.REMOVE_CONTROLLEDUNIT: case PamControllerInterface.REMOVE_CONTROLLEDUNIT:
scalePane.checkDataGramPane(); dataMapSettingsPane.checkDataGramPane();
dataMapSettingsPane.setParams(dataMapControl.dataMapParameters);
break;
case PamControllerInterface.INITIALIZE_LOADDATA: case PamControllerInterface.INITIALIZE_LOADDATA:
case PamControllerInterface.EXTERNAL_DATA_IMPORTED: case PamControllerInterface.EXTERNAL_DATA_IMPORTED:
scrollingDataPanel.updateScrollBar(); scrollingDataPanel.updateScrollBar();
scalePane.checkDataGramPane(); dataMapSettingsPane.checkDataGramPane();
dataMapSettingsPane.setParams(dataMapControl.dataMapParameters);
this.repaintAll(); this.repaintAll();
break; break;
case PamControllerInterface.OFFLINE_DATA_LOADED: case PamControllerInterface.OFFLINE_DATA_LOADED:
scrollingDataPanel.updateScrollBar(); scrollingDataPanel.updateScrollBar();
scalePane.checkDataGramPane(); dataMapSettingsPane.checkDataGramPane();
dataMapSettingsPane.setParams(dataMapControl.dataMapParameters);
this.repaintAll(); this.repaintAll();
break; break;
case PamControllerInterface.DATA_LOAD_COMPLETE: case PamControllerInterface.DATA_LOAD_COMPLETE:
@ -304,4 +309,22 @@ public class DataMapPaneFX extends PamBorderPane implements UserDisplayNodeFX {
return null; return null;
} }
/**
* Get the current number of data stream panes
* @return the number of data stream panes
*/
public int getNumDataStreamPanes() {
return this.scrollingDataPanel.getNumDataStreamPanes();
}
/**
* Get a data stream pane.
* @param n - the index of the data stream pane
* @return the data stream pane or null if the index is out of bounds.
*/
public DataStreamPaneFX getDataStreamPane(int n) {
return this.scrollingDataPanel.getDataSyreamPane( n);
}
} }

View File

@ -0,0 +1,489 @@
package dataMap.layoutFX;
import dataGram.DatagramManager;
import dataGram.DatagramScaleInformation;
import dataGram.DatagramSettings;
import dataMap.DataMapControl;
import dataMap.DataMapParameters;
import PamController.PamController;
import PamUtils.PamCalendar;
import binaryFileStorage.BinaryStore;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import pamViewFX.PamGuiManagerFX;
import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.PamGridPane;
import pamViewFX.fxNodes.PamVBox;
import pamViewFX.fxNodes.comboBox.ColorComboBox;
import pamViewFX.fxNodes.pamDialogFX.PamDialogFX;
import pamViewFX.fxNodes.sliders.ColourRangeSlider;
import pamViewFX.fxNodes.utilityPanes.PamToggleSwitch;
import pamViewFX.fxNodes.utilsFX.ColourArray;
import pamViewFX.fxNodes.utilsFX.ColourArray.ColourArrayType;
import pamViewFX.fxSettingsPanes.DynamicSettingsPane;
/**
* Settings pane which allows users to change settings for data maps.
*
* @author Jamie Macaulay
*
*/
public class DataMapSettingsPane extends DynamicSettingsPane<DataMapParameters> {
/*
* Reference to the data map control.
*/
private DataMapControl dataMapControl;
/**
* Reference to the dataMapPane.
*/
private DataMapPaneFX dataMapPane;
// /**
// * The slider which determines time scale.
// */
// private Slider timeSlider;
/**
* Shows the time scale in pix/hour
*/
private Label timeScaleLabel;
/**
* Selects unit count on vertical scale
*/
private ComboBox<String> scaleBox;
/**
* Check box for log vertical scale.
*/
private PamToggleSwitch logScaleToggle;
// /**
// * The chosen time values.
// */
// private double[] timeScaleChoices = DataMapParameters.hScaleChoices;
/**
* Combo box holding options to channge the datargam bin size
*/
private ComboBox<String> datagramBox;
/**
* Holds a list of times for the datagram bin size.
*/
private ComboBox<String> dataGramComboBox;
/**
* Holds everything.
*/
private PamVBox holder;
/**
* Grid pane with settings for the data scales
*/
private PamGridPane scaleSettingsPane;
private Label dataGramLabel;
private ComboBox<String> dataGramBox;
/**
* Holdes datagram settings.
*/
private PamVBox dataGramSettingsPane;
private DataGramColPane dataGramColPane;
private PamBorderPane mainPain;
public DataMapSettingsPane(DataMapControl dataMapControl, DataMapPaneFX dataMapPane) {
super(null);
this.dataMapControl = dataMapControl;
this.dataMapPane = dataMapPane;
// //create the holder pane.
// PamVBox vBoxHolder=new PamVBox();
// vBoxHolder.setSpacing(5);
// Label title=new Label("Scales");
// PamGuiManagerFX.titleFont2style(title);
// vBoxHolder.getChildren().addAll(title, controlPane);
//add the scale
holder=new PamVBox();
holder.setSpacing(5);
Label scaleLabel = new Label("Data Scale");
PamGuiManagerFX.titleFont2style(scaleLabel);
holder.getChildren().add(scaleLabel);
holder.getChildren().add(scaleSettingsPane = createScalePane());
//adds the datagram settings pane which is dependent on binary storage.
checkDataGramPane();
mainPain = new PamBorderPane();
mainPain.setCenter(holder);
//set params for the pane
setParams(dataMapControl.dataMapParameters);
checkDataGramPane(); // create datagram pane if a binary store already added.
sayHScale();
}
/**
* Adds a settings pane for the data gram if a binary store is present.
*/
public void checkDataGramPane(){
if (BinaryStore.findBinaryStoreControl()!=null){
DatagramManager dataGramManager=BinaryStore.findBinaryStoreControl().getDatagramManager();
if (dataGramManager!=null && dataGramSettingsPane==null) {
PamVBox datagramholder = new PamVBox();
datagramholder.setSpacing(5);
Label datagramLabel = new Label("Datagrams");
PamGuiManagerFX.titleFont2style(datagramLabel);
datagramholder.getChildren().add(datagramLabel);
datagramholder.getChildren().add(createDatagramPane(dataGramManager));
holder.getChildren().add(this.dataGramSettingsPane = datagramholder);
}
}
else {
holder.getChildren().remove(this.dataGramSettingsPane);
datagramBox=null;
}
}
/**
* Create the a datagram combo box to change the size of the datagram
* @param dataGramManager - the datagram manager for the current biinary store.
* @return a combo box with datagram bin sizes.
*/
private ComboBox<String> createDataGramBinPane(DatagramManager dataGramManager){
dataGramComboBox=new ComboBox<String>(createDurationList(dataGramManager));
dataGramComboBox.getSelectionModel().select(durationToString(dataGramManager.getDatagramSettings().datagramSeconds*1000L));
dataGramComboBox.valueProperty().addListener(( ov, t, t1) -> {
if (t==t1) return;
else {
PamController.getInstance();
boolean ans=PamDialogFX.showWarning(PamController.getMainStage(), "Warning", "Recalculating the datagram for a large dataset may take a long time" +
"Are you sure you want to continue");
if (ans){
int index=dataGramComboBox.getSelectionModel().getSelectedIndex();
//messy- datagramSeconfds should be in millis but left for backwards compatibility.
dataGramManager.getDatagramSettings().datagramSeconds=(int) (DatagramSettings.defaultDatagramSeconds[index]/1000);
dataGramManager.updateDatagrams();
dataMapPane.repaintAll();
}
}
});
return dataGramComboBox;
}
/**
* Convert duration to string.
* @param duration in millis.
*/
private String durationToString(long duration){
return (" " + PamCalendar.formatDuration(duration));
}
/**
* Create list of load times.
* @return list of load times duration.
*/
private ObservableList<String> createDurationList(DatagramManager dataGramManager){
ObservableList<String> loadTimeList=FXCollections.observableArrayList();
for (int i=0; i<DatagramSettings.defaultDatagramSeconds.length; i++){
loadTimeList.add(durationToString(DatagramSettings.defaultDatagramSeconds[i]));
}
return loadTimeList;
}
private Pane createDatagramPane(DatagramManager dataGramManager) {
dataGramLabel= new Label("Datagram bin size");
ComboBox<String> datagramBinsBox = createDataGramBinPane(dataGramManager);
//Pane for colouring datagrams.
dataGramBox=new ComboBox<String> ();
//find all datagrams.
updateDataStreamBox();
dataGramBox.setOnAction((action)->{
dataGramColPane.setDataStreamPanel(dataMapPane.getDataStreamPane(dataGramBox.getSelectionModel().getSelectedIndex()));
});
//holds settings for the datagram
dataGramColPane = new DataGramColPane();
PamGridPane holder = new PamGridPane();
holder.setHgap(5);
holder.setVgap(5);
//holder.setGridLinesVisible(true);
int row = 0;
holder.add(dataGramLabel, 0,row);
holder.add(datagramBinsBox, 1, row);
row++;
holder.add(new Label("Select datagram"), 0, row);
holder.add(dataGramBox, 1, row);
row++;
GridPane.setHgrow(dataGramColPane, Priority.ALWAYS);
holder.add(dataGramColPane, 0, row);
//dunno why this always had to be set after the child has been added to work.
GridPane.setColumnSpan(dataGramColPane, 3);
//hack to make sure the third column of the gris expands to fit the pane
ColumnConstraints rightCol = new ColumnConstraints();
rightCol.setHgrow(Priority.ALWAYS);
holder.getColumnConstraints().addAll(new ColumnConstraints(), new ColumnConstraints(), rightCol);
return holder;
}
private void updateDataStreamBox() {
System.out.println("UPDATE DATA STREAM BOX: " + this.dataMapPane.getNumDataStreamPanes());
for (int i=0; i<this.dataMapPane.getNumDataStreamPanes(); i++) {
if (dataMapPane.getDataStreamPane(i).getScaleType() == DatagramScaleInformation.PLOT_3D) {
dataGramBox.getItems().add(dataMapPane.getDataStreamPane(i).getDataName().getName());
}
}
}
/**
* Allows the user to change datagram colours.
*
*/
public class DataGramColPane extends PamBorderPane {
private ColourRangeSlider colourSlider;
private Label ampLabel;
private ColorComboBox colorBox;
private ColourArrayType colorArray = ColourArrayType.HSV;
private DataStreamPaneFX dataStreamPane;
public DataGramColPane() {
//create colour slider
//colour slider
colourSlider=new ColourRangeSlider();
colourSlider.setShowTickMarks(false);
colourSlider.setShowTickLabels(false);
colourSlider.setOrientation(Orientation.HORIZONTAL);
//amplifier label
// String dBRef = GlobalMedium.getdBRefString(PamController.getInstance().getGlobalMediumManager().getCurrentMedium());
Label ampLabel = new Label("Colour scale");
colorBox=new ColorComboBox(ColorComboBox.COLOUR_ARRAY_BOX);
colorBox.setPrefWidth(80);
colourSlider.highValueProperty().addListener((obsVal, oldVal, newVal)->{
});
//Change the colour of the colour slider when combo box is changed.
colorBox.valueProperty().addListener(new ChangeListener<String>() {
@Override public void changed(ObservableValue<? extends String> ov, String t, String t1) {
//change the colour of the colour range slider.
setColours();
}
});
colorBox.setValue(ColourArray.getName(getColourArrayType()));
//need to set up alignment properly. //FIXME- a bit messy
BorderPane.setAlignment(colorBox, Pos.CENTER);
//sliderPane.setPadding(new Insets(10,0,0,0));
BorderPane.setMargin(colorBox, new Insets(0,5,0,5));
this.setCenter(colourSlider);
this.setRight(colorBox);
//set up so the correct color
colorBox.setValue(ColourArray.getName(getColourArrayType()));
colourSlider.setColourArrayType(getColourArrayType());
}
public void setDataStreamPanel(DataStreamPaneFX selectedItem) {
this.dataStreamPane=selectedItem;
//TODO - set the colours here.
}
/**
* Set colours depending on current colour selection in combo box.
*/
private void setColours(){
this.setColourArrayType(ColourArray.getColourArrayType(colorBox.getValue()));
colourSlider.setColourArrayType(getColourArrayType());
}
public ColourArrayType getColourArrayType() {
return colorArray;
}
public void setColourArrayType(ColourArrayType colourArrayType) {
this.colorArray = colourArrayType;
}
}
/**
* Create a pane to change vertical scales.
* @return pamne with controls to change vertical scales.
*/
private PamGridPane createScalePane() {
PamGridPane controlPane=new PamGridPane();
controlPane.setHgap(5);
controlPane.setVgap(5);
// //create time scale controls
// controlPane.add(new Label("Time window"),0,1);
//
// //create time slider
// timeSlider=new Slider(0, timeScaleChoices.length-1, 1);
// timeSlider.setShowTickLabels(true);
// timeSlider.setShowTickMarks(true);
// timeSlider.setMajorTickUnit(1);
//
// timeSlider.setLabelFormatter(new ScaleStringConverter());
//
//// PamGridPane.setHalignment(timeSlider, Pos.BOTTOM_CENTER);
//
// controlPane.add(timeSlider,1,1);
// //add listener to time slider to change datamap.
// timeSlider.valueProperty().addListener((ov, oldVal, newVal)->{
// sayHScale();
// dataMapPane.scaleChanged();
// });
//
// controlPane.add(timeScaleLabel=new Label(""),3,1);
//create vertical scale controls
scaleBox=new ComboBox<String> ();
scaleBox.getItems().add("No Scaling");
scaleBox.getItems().add("per Second");
scaleBox.getItems().add("per Minute");
scaleBox.getItems().add("per Hour");
scaleBox.getItems().add("per Day");
controlPane.add(new Label("Show detections "),0,0);
controlPane.add(scaleBox,1,0);
// scaleBox.setPrefWidth(200);
scaleBox.valueProperty().addListener((ov, oldVal, newVal)->{
dataMapPane.scaleChanged();
});
logScaleToggle=new PamToggleSwitch("Log Scale");
logScaleToggle.selectedProperty().addListener((obsVal, oldVal, newVal)->{
dataMapPane.scaleChanged();
});
controlPane.add(logScaleToggle,0,1);
return controlPane;
}
/**
* Show the horizontal scale.
*/
private void sayHScale() {
// double hChoice = timeScaleChoices[this.];
// timeScaleLabel.setText(String.format("%s pixs/hour", new Double(timeScaleChoices[(int) hChoice]).toString()));
}
//HACK use setting flag to avoid immediate callback which overwrites changes 2 and 3 !
boolean setting = false;
public void setParams(DataMapParameters dataMapParameters) {
setting = true;
// timeSlider.setValue(dataMapParameters.hScaleChoice);
scaleBox.getSelectionModel().select(dataMapParameters.vScaleChoice);
logScaleToggle.setSelected(dataMapParameters.vLogScale);
//make sure the combo box has correct datastreams
updateDataStreamBox();
setting = false;
}
public DataMapParameters getParams(DataMapParameters dataMapParameters) {
if (setting) return dataMapParameters;
// dataMapParameters.hScaleChoice = (int) timeSlider.getValue();
dataMapParameters.vScaleChoice = scaleBox.getSelectionModel().getSelectedIndex();
dataMapParameters.vLogScale = logScaleToggle.isSelected();
return dataMapParameters;
}
@Override
public String getName() {
return "Datamap settings";
}
@Override
public Node getContentNode() {
// TODO Auto-generated method stub
return mainPain;
}
@Override
public void paneInitialized() {
// TODO Auto-generated method stub
}
}

View File

@ -138,6 +138,7 @@ public class DataStreamPaneFX extends PamBorderPane {
dataGraph = new DataGraphFX(); dataGraph = new DataGraphFX();
dataGraph.setupAxis(); dataGraph.setupAxis();
dataName = new DataName(); dataName = new DataName();
dataName.setName(dataBlock.getDataName());
this.setTop(topPane=createTopPane()); this.setTop(topPane=createTopPane());
this.setCenter(dataGraph); this.setCenter(dataGraph);
@ -990,6 +991,16 @@ public class DataStreamPaneFX extends PamBorderPane {
} }
public class DataName { public class DataName {
private String name;
public String getName() {
return name;
}
public void setName(String dataName) {
this.name=dataName;
}
} }

View File

@ -1,293 +0,0 @@
package dataMap.layoutFX;
import dataGram.DatagramManager;
import dataGram.DatagramSettings;
import dataMap.DataMapControl;
import dataMap.DataMapParameters;
import PamController.PamController;
import PamUtils.PamCalendar;
import binaryFileStorage.BinaryStore;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.util.StringConverter;
import pamViewFX.PamGuiManagerFX;
import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.PamGridPane;
import pamViewFX.fxNodes.PamHBox;
import pamViewFX.fxNodes.PamVBox;
import pamViewFX.fxNodes.pamDialogFX.PamDialogFX;
import pamViewFX.fxNodes.sliders.PamSlider;
import pamViewFX.fxNodes.utilityPanes.PamToggleSwitch;
/**
* Allows uses to change the horizontal and vertical scales on the data map.
*
* @author Jamie Macaulay
*
*/
public class ScalePaneFX extends PamBorderPane {
/*
* Reference to the data map control.
*/
private DataMapControl dataMapControl;
/**
* Reference to the dataMapPane.
*/
private DataMapPaneFX dataMapPane;
/**
* The slider which determines time scale.
*/
private Slider timeSlider;
/**
* Shows the time scale in pix/hour
*/
private Label timeScaleLabel;
/**
* Selects unit count on vertical scale
*/
private ComboBox<String> scaleBox;
/**
* Check box for log vertical scale.
*/
private PamToggleSwitch logScaleBox;
/**
* The chosen time values.
*/
private double[] timeScaleChoices = DataMapParameters.hScaleChoices;
/**
* Combo box holding options to channge the datargam bin size
*/
private ComboBox<String> datagramBox;
/**
* Holds a list of times for the datagram bin size.
*/
private ComboBox<String> dataGramComboBox;
/**
* Holds everything.
*/
private PamVBox holder;
/**
* Grid pane with settings for the data scales
*/
private PamGridPane scaleSettingsPane;
private Label dataGramLabel;
public ScalePaneFX(DataMapControl dataMapControl, DataMapPaneFX dataMapPane) {
this.dataMapControl = dataMapControl;
this.dataMapPane = dataMapPane;
// //create the holder pane.
// PamVBox vBoxHolder=new PamVBox();
// vBoxHolder.setSpacing(5);
// Label title=new Label("Scales");
// PamGuiManagerFX.titleFont2style(title);
// vBoxHolder.getChildren().addAll(title, controlPane);
holder=new PamVBox();
holder.setSpacing(20);
holder.getChildren().add(scaleSettingsPane = createScalePane());
this.setCenter(holder);
//set params for the pane
setParams(dataMapControl.dataMapParameters);
checkDataGramPane(); // create datagram pane if a binary store already added.
sayHScale();
}
/**
* Adds a settings pane for the datagram if a binary store is present.
*/
public void checkDataGramPane(){
if (BinaryStore.findBinaryStoreControl()!=null){
DatagramManager dataGramManager=BinaryStore.findBinaryStoreControl().getDatagramManager();
if (dataGramManager!=null && datagramBox==null) {
datagramBox=createDatagramPane(dataGramManager);
scaleSettingsPane.add(dataGramLabel= new Label("Datagram bin size"), 0, 2);
scaleSettingsPane.add(dataGramComboBox, 1, 2);
}
}
else {
scaleSettingsPane.getChildren().remove(dataGramLabel);
scaleSettingsPane.getChildren().remove(dataGramComboBox);
datagramBox=null;
}
}
/**
* Create the a datagram combo box to change the size of the datagram
* @param dataGramManager - the datagram manager for the current biinary store.
* @return a combo box with datagram bin sizes.
*/
private ComboBox<String> createDatagramPane(DatagramManager dataGramManager){
dataGramComboBox=new ComboBox<String>(createDurationList(dataGramManager));
dataGramComboBox.getSelectionModel().select(durationToString(dataGramManager.getDatagramSettings().datagramSeconds*1000L));
dataGramComboBox.valueProperty().addListener(( ov, t, t1) -> {
if (t==t1) return;
else {
PamController.getInstance();
boolean ans=PamDialogFX.showWarning(PamController.getMainStage(), "Warning", "<html>Recalculating the datagram for a large dataset may take a long time<br>" +
"Are you sure you want to continue ?</html>");
if (ans){
int index=dataGramComboBox.getSelectionModel().getSelectedIndex();
//messy- datagramSeconfds should be in millis but left for backwards compatibility.
dataGramManager.getDatagramSettings().datagramSeconds=(int) (DatagramSettings.defaultDatagramSeconds[index]/1000);
dataGramManager.updateDatagrams();
dataMapPane.repaintAll();
}
}
});
return dataGramComboBox;
}
/**
* Convert duration to string.
* @param duration in millis.
*/
private String durationToString(long duration){
return (" " + PamCalendar.formatDuration(duration));
}
/**
* Create list of load times.
* @return list of load times duration.
*/
private ObservableList<String> createDurationList(DatagramManager dataGramManager){
ObservableList<String> loadTimeList=FXCollections.observableArrayList();
for (int i=0; i<DatagramSettings.defaultDatagramSeconds.length; i++){
loadTimeList.add(durationToString(DatagramSettings.defaultDatagramSeconds[i]));
}
return loadTimeList;
}
private PamGridPane createScalePane() {
PamGridPane controlPane=new PamGridPane();
controlPane.setHgap(5);
controlPane.setVgap(5);
//create time scale controls
controlPane.add(new Label("Time window"),0,1);
//create time slider
timeSlider=new Slider(0, timeScaleChoices.length-1, 1);
timeSlider.setShowTickLabels(true);
timeSlider.setShowTickMarks(true);
timeSlider.setMajorTickUnit(1);
timeSlider.setLabelFormatter(new ScaleStringConverter());
// PamGridPane.setHalignment(timeSlider, Pos.BOTTOM_CENTER);
controlPane.add(timeSlider,1,1);
//add listener to time slider to change datamap.
timeSlider.valueProperty().addListener((ov, oldVal, newVal)->{
sayHScale();
dataMapPane.scaleChanged();
});
controlPane.add(timeScaleLabel=new Label(""),3,1);
//create vertical scale controls
controlPane.add(new Label("Data counts"),0,0);
scaleBox=new ComboBox<String> ();
scaleBox.getItems().add("No Scaling");
scaleBox.getItems().add("per Second");
scaleBox.getItems().add("per Minute");
scaleBox.getItems().add("per Hour");
scaleBox.getItems().add("per Day");
controlPane.add(scaleBox,1,0);
scaleBox.setPrefWidth(200);
scaleBox.valueProperty().addListener((ov, oldVal, newVal)->{
dataMapPane.scaleChanged();
});
logScaleBox=new PamToggleSwitch("Log Scale");
logScaleBox.selectedProperty().addListener((obsVal, oldVal, newVal)->{
dataMapPane.scaleChanged();
});
controlPane.add(logScaleBox,3,0);
return controlPane;
}
class ScaleStringConverter extends StringConverter<Double> {
@Override
public String toString(Double object) {
return String.valueOf(timeScaleChoices[object.intValue()]);
}
@Override
public Double fromString(String string) {
return Double.valueOf(string);
}
}
/**
* Show the horizontal scale.
*/
private void sayHScale() {
double hChoice = timeSlider.getValue();
timeScaleLabel.setText(String.format("%s pixs/hour", new Double(timeScaleChoices[(int) hChoice]).toString()));
}
//HACK use setting flag to avoid immediate callback which overwrites changes 2 and 3 !
boolean setting = false;
public void setParams(DataMapParameters dataMapParameters) {
setting = true;
timeSlider.setValue(dataMapParameters.hScaleChoice);
scaleBox.getSelectionModel().select(dataMapParameters.vScaleChoice);
logScaleBox.setSelected(dataMapParameters.vLogScale);
setting = false;
}
public void getParams(DataMapParameters dataMapParameters) {
if (setting) return;
dataMapParameters.hScaleChoice = (int) timeSlider.getValue();
dataMapParameters.vScaleChoice = scaleBox.getSelectionModel().getSelectedIndex();
dataMapParameters.vLogScale = logScaleBox.isSelected();
}
}

View File

@ -28,7 +28,7 @@ public class ScrollingDataPaneFX extends PamBorderPane {
/** /**
* Standard millis to wait for repaint. * Standard millis to wait for repaint.
* Do not ake this too high i.e. above 50 or the display gets very jerky * Do not make this too high i.e. above 50 or the display gets very jerky
*/ */
public static final long REPAINTMILLIS = 50; public static final long REPAINTMILLIS = 50;
@ -496,4 +496,24 @@ public class ScrollingDataPaneFX extends PamBorderPane {
// this.notifyScrollChange(); // this.notifyScrollChange();
// } // }
/**
* Get the current number of data stream panes
* @return the number of data stream panes
*/
public int getNumDataStreamPanes() {
return this.dataStreamPanels.size();
}
/**
* Get a data stream pane.
* @param n - the index of the data stream pane
* @return the data stream pane or null if the index is out of bounds.
*/
public DataStreamPaneFX getDataSyreamPane(int n) {
if (n<this.dataStreamPanels.size()) {
return dataStreamPanels.get(n);
}
else return null;
}
} }

View File

@ -7,16 +7,13 @@ import PamView.paneloverlay.overlaymark.OverlayMark;
import PamguardMVC.PamDataUnit; import PamguardMVC.PamDataUnit;
import PamguardMVC.PamRawDataBlock; import PamguardMVC.PamRawDataBlock;
import detectiongrouplocaliser.DetectionGroupSummary; import detectiongrouplocaliser.DetectionGroupSummary;
import export.wavExport.WavFileExportManager; import export.wavExport.WavDetExport;
import javafx.animation.Timeline;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.scene.control.Labeled; import javafx.scene.control.Labeled;
import javafx.scene.control.Tooltip; import javafx.scene.control.Tooltip;
import javafx.scene.effect.ColorInput;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import pamViewFX.fxGlyphs.PamGlyphDude; import pamViewFX.fxGlyphs.PamGlyphDude;
import pamViewFX.fxNodes.PamButton; import pamViewFX.fxNodes.PamButton;
import wavFiles.WavFileWriter;
/** /**
* Export a .wav clip. * Export a .wav clip.
@ -27,27 +24,27 @@ public class WavExportOverlayMenu extends ExportOverlayMenu {
private Text wavFileGlyph; private Text wavFileGlyph;
/** // /**
* The wav file write // * The wav file write
*/ // */
private WavFileWriter wavFile; // private WavFileWriter wavFile;
//
// private String defaultPath;
//
// private String currentFolder;
private String defaultPath; private WavDetExport wavExportManager;
private String currentFolder; // private ColorInput shadow;
//
private WavFileExportManager wavExportManager; // private Timeline timline;
private ColorInput shadow;
private Timeline timline;
private PamButton pamButton; private PamButton pamButton;
public WavExportOverlayMenu(){ public WavExportOverlayMenu(){
// wavFileGlyph=PamGlyphDude.createPamGlyph(MaterialDesignIcon.FILE_MUSIC, standardIconSize); // wavFileGlyph=PamGlyphDude.createPamGlyph(MaterialDesignIcon.FILE_MUSIC, standardIconSize);
wavFileGlyph=PamGlyphDude.createPamIcon("mdi2f-file-music", standardIconSize+14); wavFileGlyph=PamGlyphDude.createPamIcon("mdi2f-file-music", standardIconSize+14);
wavExportManager= new WavFileExportManager(); wavExportManager= new WavDetExport();
//set a callback when saving is finsihed. //set a callback when saving is finsihed.
wavExportManager.setOnWavSaved((saveFile, flag)->{ wavExportManager.setOnWavSaved((saveFile, flag)->{
@ -132,7 +129,7 @@ public class WavExportOverlayMenu extends ExportOverlayMenu {
*/ */
private void writeWavFile(DetectionGroupSummary foundDataUnits, int selectedIndex, OverlayMark mark) { private void writeWavFile(DetectionGroupSummary foundDataUnits, int selectedIndex, OverlayMark mark) {
// animateButton() ; //start button animation. // animateButton() ; //start button animation.
wavExportManager.dataUnits2Wav(foundDataUnits, selectedIndex, mark); wavExportManager.writeOverlayMarkWav(foundDataUnits, selectedIndex, mark);
} }
@ -148,7 +145,7 @@ public class WavExportOverlayMenu extends ExportOverlayMenu {
rawDataBlock=foundDataUnits.getDataList().get(0).getParentDataBlock().getRawSourceDataBlock(); rawDataBlock=foundDataUnits.getDataList().get(0).getParentDataBlock().getRawSourceDataBlock();
} }
//is there available raw data //is there available raw data
if (mark!=null && WavFileExportManager.haveRawData(rawDataBlock, (long) mark.getLimits()[0], (long) mark.getLimits()[1])) { if (mark!=null && WavDetExport.haveRawData(rawDataBlock, (long) mark.getLimits()[0], (long) mark.getLimits()[1])) {
return true; return true;
} }

View File

@ -12,7 +12,7 @@ import dataPlotsFX.layout.TDGraphFX.TDPlotPane;
import dataPlotsFX.overlaymark.menuOptions.OverlayMenuItem; import dataPlotsFX.overlaymark.menuOptions.OverlayMenuItem;
import dataPlotsFX.overlaymark.menuOptions.OverlayMenuManager; import dataPlotsFX.overlaymark.menuOptions.OverlayMenuManager;
import detectiongrouplocaliser.DetectionGroupSummary; import detectiongrouplocaliser.DetectionGroupSummary;
import export.wavExport.WavFileExportManager; import export.wavExport.WavDetExport;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Orientation; import javafx.geometry.Orientation;
import javafx.geometry.Pos; import javafx.geometry.Pos;
@ -546,7 +546,7 @@ public class TDMenuPane extends PamBorderPane {
PamRawDataBlock pamRawBlock = findRawSourceBlock(); PamRawDataBlock pamRawBlock = findRawSourceBlock();
// System.out.println("Pam raw data block: " + pamRawBlock); // System.out.println("Pam raw data block: " + pamRawBlock);
if (WavFileExportManager.haveRawData(pamRawBlock, (long) overlayMarker.getCurrentMark().getLimits()[0], (long) overlayMarker.getCurrentMark().getLimits()[1])) { if (WavDetExport.haveRawData(pamRawBlock, (long) overlayMarker.getCurrentMark().getLimits()[0], (long) overlayMarker.getCurrentMark().getLimits()[1])) {
//System.out.println("Overaly Marker start X: " + overlayMarker.getCurrentMark().getLimits()[0] + " end: " + overlayMarker.getCurrentMark().getLimits()[1]); //System.out.println("Overaly Marker start X: " + overlayMarker.getCurrentMark().getLimits()[0] + " end: " + overlayMarker.getCurrentMark().getLimits()[1]);
//System.out.println("Overlay Marker start Y: " + overlayMarker.getCurrentMark().getLimits()[2] + " end: " + overlayMarker.getCurrentMark().getLimits()[3]); //System.out.println("Overlay Marker start Y: " + overlayMarker.getCurrentMark().getLimits()[2] + " end: " + overlayMarker.getCurrentMark().getLimits()[3]);
groupDetectionDisplay.showRawData(pamRawBlock, overlayMarker.getCurrentMark().getLimits(), overlayMarker.getCurrentMark().getMarkChannels()); groupDetectionDisplay.showRawData(pamRawBlock, overlayMarker.getCurrentMark().getLimits(), overlayMarker.getCurrentMark().getMarkChannels());

View File

@ -925,6 +925,8 @@ public class Scrolling2DPlotDataFX {
//reset transform in case of other drawings on base canvas. //reset transform in case of other drawings on base canvas.
if (orientation == Orientation.VERTICAL) g2d.setTransform(horzAffine); if (orientation == Orientation.VERTICAL) g2d.setTransform(horzAffine);
} }

View File

@ -22,9 +22,13 @@ import javafx.scene.layout.Pane;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
/** /**
* A general pane with a frequency slider, colour bar slider and colour combo box. These nodes are interconnected so when colour combo box is changed colours change. * A general pane with a frequency slider, colour bar slider and colour combo
* Other than that this pane does nothing but all slider value properties are available to be used in another class or subclass. This means this control pane should be * box. These nodes are interconnected so when colour combo box is changed
* available to be used for any spectrogram/3D colour image. * colours change. Other than that this pane does nothing but all slider value
* properties are available to be used in another class or subclass. This means
* this control pane should be available to be used for any spectrogram/3D
* colour image.
*
* @author Jamie Macaulay * @author Jamie Macaulay
* *
*/ */

View File

@ -48,8 +48,12 @@ public abstract class MLDataUnitExport<T extends PamDataUnit<?, ?>> {
//UID for the detection. //UID for the detection.
Matrix UID = Mat5.newScalar(dataUnit.getUID()); Matrix UID = Mat5.newScalar(dataUnit.getUID());
//the start sample. Matrix startSample = Mat5.newScalar(0);
Matrix startSample = Mat5.newScalar(dataUnit.getStartSample()); if (dataUnit.getStartSample()!=null) {
//the start sample.
startSample = Mat5.newScalar(dataUnit.getStartSample());
}
//the duration of the detection in samples. //the duration of the detection in samples.
Matrix sampleDuration = Mat5.newScalar(dataUnit.getSampleDuration()); Matrix sampleDuration = Mat5.newScalar(dataUnit.getSampleDuration());

View File

@ -11,7 +11,7 @@ import PamguardMVC.PamDataUnit;
import export.CSVExport.CSVExportManager; import export.CSVExport.CSVExportManager;
import export.MLExport.MLDetectionsManager; import export.MLExport.MLDetectionsManager;
import export.RExport.RExportManager; import export.RExport.RExportManager;
import export.wavExport.WavFileExportManager; import export.wavExport.WavDetExportManager;
/** /**
* Exports data to external files. Manages the file sizes and creates data buffers for * Exports data to external files. Manages the file sizes and creates data buffers for
@ -61,7 +61,7 @@ public class PamExporterManager {
//add the MATLAB export //add the MATLAB export
pamExporters.add(new MLDetectionsManager()); pamExporters.add(new MLDetectionsManager());
pamExporters.add(new RExportManager(this)); pamExporters.add(new RExportManager(this));
pamExporters.add(new WavFileExportManager()); pamExporters.add(new WavDetExportManager());
// pamExporters.add(new CSVExportManager()); // pamExporters.add(new CSVExportManager());
} }

View File

@ -37,6 +37,7 @@ import PamguardMVC.PamDataBlock;
import export.ExportParams; import export.ExportParams;
import export.PamExporterManager; import export.PamExporterManager;
import offlineProcessing.OLProcessDialog; import offlineProcessing.OLProcessDialog;
import offlineProcessing.OLProcessDialog.OLMonitor;
import offlineProcessing.OfflineTaskGroup; import offlineProcessing.OfflineTaskGroup;
import offlineProcessing.TaskMonitor; import offlineProcessing.TaskMonitor;
import offlineProcessing.TaskMonitorData; import offlineProcessing.TaskMonitorData;
@ -359,7 +360,7 @@ public class ExportProcessDialog {
public void setParams(ExportParams params) { public void setParams(ExportParams params) {
System.out.println("EXPORT: SET PARAMS: " +params); // System.out.println("EXPORT: SET PARAMS: " +params);
if (params ==null) currentParams = new ExportParams(); if (params ==null) currentParams = new ExportParams();
currentParams = params.clone(); currentParams = params.clone();
@ -367,46 +368,87 @@ public class ExportProcessDialog {
buttonGroup.clearSelection(); buttonGroup.clearSelection();
exportButtons[params.exportChoice].setSelected(true); exportButtons[params.exportChoice].setSelected(true);
System.out.println("EXPORT: SET PARAMS: " +currentParams.folder); // System.out.println("EXPORT: SET PARAMS: " +currentParams.folder);
exportTo.setText(currentParams.folder); exportTo.setText(currentParams.folder);
spinner.setValue(currentParams.maximumFileSize); spinner.setValue(currentParams.maximumFileSize);
enableTasks(); enableTasks();
} }
/**
* Ok, this is a bit of a hack but because we run tasks for multiple data blocks
* we have to run a new task whenever the previous task is finished. So we use a task monitor
* to deetct when the task is finsihed and then, instead of finishing we run a new task.
*/
class ExportTaskMonitor extends OLMonitor {
private int taskIndex;
private ExportTaskGroup exportTaskGroup;
private boolean started = false;
private int activeTasks;
public ExportTaskMonitor(int i, ExportTaskGroup exportTaskGroup) {
super();
this.taskIndex = i;
this.exportTaskGroup = exportTaskGroup;
this.activeTasks = 0;
for (int i1=0; i1<exportTaskGroup.getNTasks(); i1++) {
if (exportTaskGroup.getTask(i1).isDoRun()) {
activeTasks++;
}
}
}
@Override
} public void setTaskStatus(TaskMonitorData taskMonitorData) {
class ExportTaskMonitor implements TaskMonitor { switch (taskMonitorData.taskStatus) {
case COMPLETE:
private int taskIndex; if (taskIndex<exportTaskGroup.getNTasks() && !started) {
exportTaskGroup.runTaskFrom(taskIndex+1);
private ExportTaskGroup exportTaskGroup; started = true;
}
private boolean started = false; break;
default:
public ExportTaskMonitor(int i, ExportTaskGroup exportTaskGroup) { super.setTaskStatus(taskMonitorData);
this.taskIndex = i; }
this.exportTaskGroup = exportTaskGroup;
} //A hack which sets the global
switch (taskMonitorData.taskActivity) {
case LINKING:
@Override case LOADING:
public void setTaskStatus(TaskMonitorData taskMonitorData) {
if (taskMonitorData.taskStatus== TaskStatus.COMPLETE && !started) { //the progress of one datablocks
System.out.println(" TASK COMPLETE:"); double progress = ((double) taskMonitorData.progValue)/taskMonitorData.progMaximum;
if (taskIndex<exportTaskGroup.getNTasks()) { double totalProgress = ((double) taskIndex)/activeTasks + progress/activeTasks;
exportTaskGroup.runTaskFrom(taskIndex+1); // System.out.println("Total progress: " + taskMonitorData.progValue + " of " + taskMonitorData.progMaximum + " - " + totalProgress + "%" + " " + progress + " " + activeTasks + " " + taskIndex);
started = true; //needs to be added to the overall progress
int max = getGlobalProgress().getMaximum();
getGlobalProgress().setValue((int) (totalProgress*max));
default:
break;
} }
} }
} }
public ExportTaskMonitor newExportTaskMonitor(int i, ExportTaskGroup exportTaskGroup) {
return new ExportTaskMonitor(i, exportTaskGroup);
}
} }
/** /**
* Export task * Export task
*/ */
@ -428,12 +470,12 @@ public class ExportProcessDialog {
* @param i - the index * @param i - the index
*/ */
public void runTaskFrom(int i) { public void runTaskFrom(int i) {
System.out.println("RUN TASK FROM :" + i);
//sets the porimary datablock to that of the relevent task.
this.setPrimaryDataBlock(getTask(i).getDataBlock()); this.setPrimaryDataBlock(getTask(i).getDataBlock());
if (i<getNTasks()-1) { if (i<getNTasks()-1) {
//will start a new thread after this one has finished //will start a new thread after this one has finished
this.setTaskMonitor(new ExportTaskMonitor(i, this)); this.setTaskMonitor(mtOfflineDialog.newExportTaskMonitor(i, this));
} }
super.runTasks(); super.runTasks();
} }

View File

@ -56,7 +56,7 @@ public class ExportTask extends OfflineTask<PamDataUnit<?,?>>{
//System.out.println("Data selector null: " + this.getDataBlock().getDataName() + " " + dataUnit); //System.out.println("Data selector null: " + this.getDataBlock().getDataName() + " " + dataUnit);
exporter.exportDataUnit(dataUnit, false); exporter.exportDataUnit(dataUnit, false);
} }
else if (dataSelector.scoreData(dataUnit)>0 && dataSelector.getParams().getCombinationFlag() != DataSelectParams.DATA_SELECT_DISABLE) { else if (dataSelector.scoreData(dataUnit)>0 || dataSelector.getParams().getCombinationFlag() == DataSelectParams.DATA_SELECT_DISABLE) {
//System.out.println("Data selector OK: " + this.getDataBlock().getDataName() + " " + dataUnit); //System.out.println("Data selector OK: " + this.getDataBlock().getDataName() + " " + dataUnit);
exporter.exportDataUnit(dataUnit, false); exporter.exportDataUnit(dataUnit, false);
} }
@ -73,7 +73,7 @@ public class ExportTask extends OfflineTask<PamDataUnit<?,?>>{
@Override @Override
public void loadedDataComplete() { public void loadedDataComplete() {
System.out.println("EXPORTER: loaded data complete"); // System.out.println("EXPORTER: loaded data complete");
//force the exporter so save any renaming data units in the buffer //force the exporter so save any renaming data units in the buffer
exporter.exportDataUnit(null, true); exporter.exportDataUnit(null, true);
exporter.close(); exporter.close();

View File

@ -1,6 +1,5 @@
package export.wavExport; package export.wavExport;
import java.awt.Component;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -20,46 +19,36 @@ import PamguardMVC.PamObservable;
import PamguardMVC.PamObserver; import PamguardMVC.PamObserver;
import PamguardMVC.PamObserverAdapter; import PamguardMVC.PamObserverAdapter;
import PamguardMVC.PamRawDataBlock; import PamguardMVC.PamRawDataBlock;
import PamguardMVC.RawDataHolder;
import PamguardMVC.dataOffline.OfflineDataLoading; import PamguardMVC.dataOffline.OfflineDataLoading;
import dataMap.OfflineDataMapPoint; import dataMap.OfflineDataMapPoint;
import detectiongrouplocaliser.DetectionGroupSummary; import detectiongrouplocaliser.DetectionGroupSummary;
import export.PamDataUnitExporter;
import javafx.scene.layout.Pane;
import wavFiles.Wav16AudioFormat; import wavFiles.Wav16AudioFormat;
import wavFiles.WavFileWriter; import wavFiles.WavFileWriter;
/** public class WavDetExport {
* Manages .wav file writing based on what type of data unit is selected and whether raw data is available.
* <p>
* There are two primary use cases;
* <br>
* 1) Order raw data from an overlay mark and save as a wav file
* <br>
* 2) Save a list of data units to wav files - either a single file with zero pads, a concatonated file or seperate files.
*
* @author Jamie Macaulay
*
*/
public class WavFileExportManager implements PamDataUnitExporter {
/** /**
* Successful writing of .wav file. * Successful writing of .wav file.
*/ */
public static final int SUCCESS_WAV=0; // public static final int SUCCESS_WAV=0;
/** /**
* Successful writing of .wav file from data contained in detections. * Successful writing of .wav file from data contained in detections.
*/ */
public static final int SUCCESS_DET_WAV=1; // public static final int SUCCESS_DET_WAV=1;
/** /**
* General failure in wav file writing * General failure in wav file writing
*/ */
public static final int FAILURE_WAV=2; // public static final int FAILURE_WAV=2;
public static final int LOADING_WAV=2; // public static final int LOADING_WAV=2;
/**
* The maximum allowed size
*/
private static final double MAX_ZEROPAD_SIZE_MEGABYTES = 1024; //MB
/** /**
* The default path to write files to * The default path to write files to
@ -80,7 +69,7 @@ public class WavFileExportManager implements PamDataUnitExporter {
private WavOptionsPanel wavOptionsPanel; private WavOptionsPanel wavOptionsPanel;
public WavFileExportManager() { public WavDetExport() {
wavDataUnitExports.add(new RawHolderWavExport()); wavDataUnitExports.add(new RawHolderWavExport());
defaultPath=FileSystemView.getFileSystemView().getDefaultDirectory().getPath(); defaultPath=FileSystemView.getFileSystemView().getDefaultDirectory().getPath();
@ -179,7 +168,7 @@ public class WavFileExportManager implements PamDataUnitExporter {
* @param selectedIndex - the currently selected data unit. * @param selectedIndex - the currently selected data unit.
* @param mark - overlay mark. * @param mark - overlay mark.
*/ */
public int dataUnits2Wav(DetectionGroupSummary foundDataUnits, int selectedIndex, OverlayMark mark) { public int writeOverlayMarkWav(DetectionGroupSummary foundDataUnits, int selectedIndex, OverlayMark mark) {
System.out.println("Data units 2 wav"); System.out.println("Data units 2 wav");
//this order for .wav files. //this order for .wav files.
//if there is a mark then save limits of mark. If there is one data unit then set limits of data units //if there is a mark then save limits of mark. If there is one data unit then set limits of data units
@ -224,15 +213,18 @@ public class WavFileExportManager implements PamDataUnitExporter {
int flag=-1; int flag=-1;
String currentFileS = createFileName(foundDataUnits.getFirstTimeMillis());
File file = new File(currentFileS);
if (hasAllWavClips) { if (hasAllWavClips) {
flag = saveDataUnitWav(foundDataUnits); flag = writeDetGroupWav(foundDataUnits, file, false);
} }
else if (!hasAllWavClips && haveRawData) { else if (!hasAllWavClips && haveRawData) {
//no raw data //no raw data
flag = saveRawWav(start, end, rawDataBlock); flag = saveRawWav(start, end, rawDataBlock);
} }
else { else {
flag = saveDataUnitWav(foundDataUnits); flag = writeDetGroupWav(foundDataUnits, file, false);
} }
return flag; return flag;
@ -263,47 +255,129 @@ public class WavFileExportManager implements PamDataUnitExporter {
/** /**
* Save wav data from a data unit instead of from the raw file store. * Save wav data from a data unit instead of from the raw file store.
* @param foundDataUnits - the list of found data units. * @param foundDataUnits - the list of found data units.
* @param currentFile - path to current file to save to.
* @param zeroPad - if true will zeroPad detections.
* @return the number of data units that were saved. * @return the number of data units that were saved.
*/ */
private int saveDataUnitWav(DetectionGroupSummary foundDataUnits) { public int writeDetGroupWav(DetectionGroupSummary foundDataUnits, File filename, boolean zeroPad) {
return saveDataUnitWav(foundDataUnits.getDataList()); return writeDataUnitWav(foundDataUnits.getDataList(), filename, zeroPad);
} }
/** /**
* Save data units which contain raw data to a wav file. Note that this assumed * Save data units which contain raw data to individual wav files within a folder.
* the data units all contain raw data and are in order. * @param foundDataUnits - list of data units to save.
* * @param currentFile - the current folder. If this is a file name the parent directory will be used.
* @param foundDataUnits - data units containing raw data. * @return the number of data units saved
* @return the number of data units saved - this should be the same as the size
* of the data unit list.
*/ */
private int saveDataUnitWav(List<PamDataUnit> foundDataUnits) { public int writeDataUnitWavs(List<PamDataUnit> foundDataUnits, File currentFile) {
int n=0; int n=0;
WavFileWriter wavWrite = null; WavFileWriter wavWrite = null;
for (PamDataUnit fnDataUnit: foundDataUnits){ for (PamDataUnit fnDataUnit: foundDataUnits){
String currentFile = createFileName(fnDataUnit.getTimeMilliseconds());
AudioFormat audioFormat = new Wav16AudioFormat(fnDataUnit.getParentDataBlock().getSampleRate(), PamUtils.getNumChannels(fnDataUnit.getChannelBitmap())); AudioFormat audioFormat = new Wav16AudioFormat(fnDataUnit.getParentDataBlock().getSampleRate(), PamUtils.getNumChannels(fnDataUnit.getChannelBitmap()));
System.out.println("Save detection wav." + foundDataUnits.size()); String currentFileS = createFileName(fnDataUnit.getTimeMilliseconds());
//System.out.println("Save detection wav." + foundDataUnits.size());
for (int i=0; i<wavDataUnitExports.size(); i++) { for (int i=0; i<wavDataUnitExports.size(); i++) {
if (wavDataUnitExports.get(i).getUnitClass().isAssignableFrom(fnDataUnit.getClass())) { if (wavDataUnitExports.get(i).getUnitClass().isAssignableFrom(fnDataUnit.getClass())) {
wavWrite= new WavFileWriter(currentFile, audioFormat); wavWrite= new WavFileWriter(currentFileS, audioFormat);
System.out.println("Append wav." + foundDataUnits.size()); System.out.println("Write individual wav." + foundDataUnits.size());
//save the wav file of detection //save the wav file of detection
wavWrite.append(wavDataUnitExports.get(i).getWavClip(fnDataUnit)); wavWrite.append(wavDataUnitExports.get(i).getWavClip(fnDataUnit));
n++; n++;
wavWrite.close(); wavWrite.close();
break; break;
} }
} }
} }
return n;
}
/**
* Save data units which contain raw data to a wav file. Note that this assumed
* the data units all contain raw data, the raw data is at the same sample rate and number of channels
* and the data units are in order. This will APPEND to the wav file if it currently exists.
*
* @param foundDataUnits - data units containing raw data.
* @param currentFile - path to current file to save to.
* @param zeroPad - if true will zeroPad detections.
* @return the number of data units saved - this should be the same as the size
* of the data unit list.
*/
public int writeDataUnitWav(List<PamDataUnit> foundDataUnits, File currentFile, boolean zeroPad) {
int n=0;
WavFileWriter wavWrite = null;
PamDataUnit lastfnDataUnit = null;
if (foundDataUnits==null || foundDataUnits.size()<=0) {
return 0;
}
//System.out.println("Save detection wav." + foundDataUnits.size());
AudioFormat audioFormat = new Wav16AudioFormat(foundDataUnits.get(0).getParentDataBlock().getSampleRate(), PamUtils.getNumChannels(foundDataUnits.get(0).getChannelBitmap()));
wavWrite= new WavFileWriter(currentFile.getAbsolutePath(), audioFormat);
for (PamDataUnit fnDataUnit: foundDataUnits){
for (int i=0; i<wavDataUnitExports.size(); i++) {
if (wavDataUnitExports.get(i).getUnitClass().isAssignableFrom(fnDataUnit.getClass())) {
System.out.println("Append wav. data unit: " + n + " samples: " + wavDataUnitExports.get(i).getWavClip(fnDataUnit)[0].length + " zeroPad: " + zeroPad);
if (zeroPad && lastfnDataUnit!=null) {
//we need to append zero samples between the detections.
long timeMillisDiff = fnDataUnit.getTimeMilliseconds() - lastfnDataUnit.getTimeMilliseconds();
long sampleDiff = fnDataUnit.getStartSample() - lastfnDataUnit.getStartSample();
int samplesPad;
//are the two similar? - are they within 5 milliseconds
if (Math.abs(((sampleDiff/audioFormat.getSampleRate())*1000.) - timeMillisDiff)<5){
//use the sample diff
samplesPad = (int) sampleDiff;
}
else {
//use time millis for padding. May indicate that data units are from different wav files.
samplesPad = (int) ((((double) timeMillisDiff)/1000.)*audioFormat.getSampleRate());
}
//now safety check - is this more than one GB of data. Each sample is 16bits but the input double array is 64 bits each.
double size = samplesPad*16*audioFormat.getChannels()/1024/1024;
//
if (size>MAX_ZEROPAD_SIZE_MEGABYTES) {
wavWrite.close();
System.err.println(String.format("WavExportManager: A zero padding of %.2f MB was requested. The maximum allowed size is %.2f - "
+ "the .wav file was closed and any additional data units have not been written %s", size, MAX_ZEROPAD_SIZE_MEGABYTES, currentFile));
return n;
}
System.out.println("Append wav. zero pad" + samplesPad);
wavWrite.append(new double[audioFormat.getChannels()][samplesPad]);
}
//save the wav file of detection
if (wavWrite.append(wavDataUnitExports.get(i).getWavClip(fnDataUnit))) {
n++;
}
lastfnDataUnit = fnDataUnit;
break;
}
}
}
wavWrite.close();
//send a message that the wav file has saved //send a message that the wav file has saved
if (wavWrite!=null && saveCallback!=null) saveCallback.wavSaved(wavWrite.getFileName(), 0); if (wavWrite!=null && saveCallback!=null) saveCallback.wavSaved(wavWrite.getFileName(), 0);
@ -340,85 +414,6 @@ public class WavFileExportManager implements PamDataUnitExporter {
} }
@Override
public boolean hasCompatibleUnits(Class dataUnitType) {
// boolean implementsInterface = Arrays.stream(dataUnitType.getInterfaces()).anyMatch(i -> i == RawDataHolder.class);
if ( RawDataHolder.class.isAssignableFrom(dataUnitType)) return true;
return false;
}
@Override
public boolean exportData(File fileName,
List<PamDataUnit> dataUnits, boolean append) {
//should we zeropad?
saveDataUnitWav(dataUnits);
return true;
}
@Override
public String getFileExtension() {
return "wav";
}
@Override
public String getIconString() {
return "mdi2f-file-music";
}
@Override
public String getName() {
return "raw sound";
}
@Override
public void close() {
// TODO Auto-generated method stub
}
@Override
public boolean isNeedsNewFile() {
return false;
}
@Override
public Component getOptionsPanel() {
if (this.wavOptionsPanel==null) {
this.wavOptionsPanel = new WavOptionsPanel();
}
return wavOptionsPanel;
}
@Override
public Pane getOptionsPane() {
// TODO Auto-generated method stub
return null;
}
/** /**
* Observes incoming raw data and saves to a wav file * Observes incoming raw data and saves to a wav file
* *
@ -528,70 +523,4 @@ public class WavFileExportManager implements PamDataUnitExporter {
} }
// hello(){
//
//
// if (mark==null) {
// start= foundDataUnits.getFirstTimeMillis();
// end= foundDataUnits.getLastTimeMillis();
// }
//
// File folder = new File(currentFolder);
//
// //save a .wav file clip.
// if (!folder.exists()){
// if (!folder.mkdir()){
// //TODO- warning message.
// return;
// }
// }
//
// String currentPath = PamCalendar.formatFileDateTime();
// //add data types to the filen,ae
// for (int i=0 ;i<mlData.size(); i++ ){
// currentPath=currentPath + "_" + mlData.get(i).getName();
// }
// //add correct file type.
// currentPath = currentPath + ".mat";
// currentPath = currentFolder+"\\"+currentPath;
//
//
// if (append && clipControl.clipSettings.storageOption == ClipSettings.STORE_WAVFILES) {
// wavFile.append(rawData);
// lastClipDataUnit.setSampleDuration(rawEnd-lastClipDataUnit.getStartSample());
// clipDataBlock.updatePamData(lastClipDataUnit, dataUnit.getTimeMilliseconds());
// // System.out.println(String.format("%d samples added to file", rawData[0].length));
// }
// else {
// ClipDataUnit clipDataUnit;
// long startMillis = dataUnit.getTimeMilliseconds() - (long) (clipGenSetting.preSeconds*1000.);
// if (clipControl.clipSettings.storageOption == ClipSettings.STORE_WAVFILES) {
// String folderName = getClipFileFolder(dataUnit.getTimeMilliseconds(), true);
// String fileName = getClipFileName(startMillis);
// AudioFormat af = new Wav16AudioFormat(getSampleRate(), rawData.length);
// wavFile = new WavFileWriter(folderName+fileName, af);
// wavFile.write(rawData);
// wavFile.close();
// // make a data unit to go with it.
// clipDataUnit = new ClipDataUnit(startMillis, dataUnit.getTimeMilliseconds(), rawStart,
// (int)(rawEnd-rawStart), channelMap, fileName, dataBlock.getDataName(), rawData, getSampleRate());
// }
// else {
// clipDataUnit = new ClipDataUnit(startMillis, dataUnit.getTimeMilliseconds(), rawStart,
// (int)(rawEnd-rawStart), channelMap, "", dataBlock.getDataName(), rawData, getSampleRate());
// }
// clipDataUnit.setFrequency(dataUnit.getFrequency());
// lastClipDataUnit = clipDataUnit;
// if (bearingLocaliser != null) {
// localiseClip(clipDataUnit, bearingLocaliser, hydrophoneMap);
// }
// clipDataBlock.addPamData(clipDataUnit);
// }
//
// return 0; // no error.
// }
//
// }
// }
} }

View File

@ -0,0 +1,229 @@
package export.wavExport;
import java.awt.Component;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.sound.sampled.AudioFormat;
import javax.swing.filechooser.FileSystemView;
import PamController.PamController;
import PamDetection.RawDataUnit;
import PamUtils.PamCalendar;
import PamUtils.PamUtils;
import PamView.paneloverlay.overlaymark.OverlayMark;
import PamguardMVC.LoadObserver;
import PamguardMVC.PamDataUnit;
import PamguardMVC.PamObservable;
import PamguardMVC.PamObserver;
import PamguardMVC.PamObserverAdapter;
import PamguardMVC.PamRawDataBlock;
import PamguardMVC.RawDataHolder;
import PamguardMVC.dataOffline.OfflineDataLoading;
import dataMap.OfflineDataMapPoint;
import detectiongrouplocaliser.DetectionGroupSummary;
import export.PamDataUnitExporter;
import javafx.scene.layout.Pane;
import wavFiles.Wav16AudioFormat;
import wavFiles.WavFileWriter;
/**
* Writes data units and/or ordered raw data to a wav file. Has functions to
* handle .wav file writing based on overlay marks and detection groups with
* functions to make decisions based on what type of data unit is selected and
* whether raw data is available.
* <p>
* There are two primary use cases; <br>
* 1) Order raw data from an overlay mark and save as a wav file <br>
* 2) Save a list of data units to wav files - either a single file with zero
* pads, a concatenated file or separate files.
*
* @author Jamie Macaulay
*
*/
public class WavDetExportManager implements PamDataUnitExporter {
/**
* Options for exporting wav files.
*/
private WavExportOptions wavFileoptions = new WavExportOptions();
/**
* Settings panel for wav file exporting
*/
private WavOptionsPanel wavOptionsPanel;
/**
* Exporter of wav files.
*/
private WavDetExport wavDetExport = new WavDetExport();
public WavDetExportManager() {
}
@Override
public boolean hasCompatibleUnits(Class dataUnitType) {
// boolean implementsInterface = Arrays.stream(dataUnitType.getInterfaces()).anyMatch(i -> i == RawDataHolder.class);
if ( RawDataHolder.class.isAssignableFrom(dataUnitType)) return true;
return false;
}
@Override
public boolean exportData(File fileName,
List<PamDataUnit> dataUnits, boolean append) {
//make sure we have the latest options.
if (wavOptionsPanel!=null) {
//means the options panel has been opened.
wavFileoptions = wavOptionsPanel.getParams(wavFileoptions);
}
//should we zeropad?
//saveDataUnitWav(dataUnits);
switch (wavFileoptions.wavSaveChoice) {
case WavExportOptions.SAVEWAV_CONCAT:
wavDetExport.writeDataUnitWav(dataUnits, fileName, false);
break;
case WavExportOptions.SAVEWAV_INDIVIDUAL:
//here the filename will not be used but the parent folder will be used instead to write
//lots of wav files to.
wavDetExport.writeDataUnitWavs(dataUnits, fileName);
break;
case WavExportOptions.SAVEWAV_ZERO_PAD:
wavDetExport.writeDataUnitWav(dataUnits, fileName, true);
break;
}
return true;
}
@Override
public String getFileExtension() {
return "wav";
}
@Override
public String getIconString() {
return "mdi2f-file-music";
}
@Override
public String getName() {
return "raw sound";
}
@Override
public void close() {
// TODO Auto-generated method stub
}
@Override
public boolean isNeedsNewFile() {
return false;
}
@Override
public Component getOptionsPanel() {
if (this.wavOptionsPanel==null) {
this.wavOptionsPanel = new WavOptionsPanel();
}
wavOptionsPanel.setParams(this.wavFileoptions) ;
return wavOptionsPanel;
}
@Override
public Pane getOptionsPane() {
// TODO - make FX version of settings.
return null;
}
// hello(){
//
//
// if (mark==null) {
// start= foundDataUnits.getFirstTimeMillis();
// end= foundDataUnits.getLastTimeMillis();
// }
//
// File folder = new File(currentFolder);
//
// //save a .wav file clip.
// if (!folder.exists()){
// if (!folder.mkdir()){
// //TODO- warning message.
// return;
// }
// }
//
// String currentPath = PamCalendar.formatFileDateTime();
// //add data types to the filen,ae
// for (int i=0 ;i<mlData.size(); i++ ){
// currentPath=currentPath + "_" + mlData.get(i).getName();
// }
// //add correct file type.
// currentPath = currentPath + ".mat";
// currentPath = currentFolder+"\\"+currentPath;
//
//
// if (append && clipControl.clipSettings.storageOption == ClipSettings.STORE_WAVFILES) {
// wavFile.append(rawData);
// lastClipDataUnit.setSampleDuration(rawEnd-lastClipDataUnit.getStartSample());
// clipDataBlock.updatePamData(lastClipDataUnit, dataUnit.getTimeMilliseconds());
// // System.out.println(String.format("%d samples added to file", rawData[0].length));
// }
// else {
// ClipDataUnit clipDataUnit;
// long startMillis = dataUnit.getTimeMilliseconds() - (long) (clipGenSetting.preSeconds*1000.);
// if (clipControl.clipSettings.storageOption == ClipSettings.STORE_WAVFILES) {
// String folderName = getClipFileFolder(dataUnit.getTimeMilliseconds(), true);
// String fileName = getClipFileName(startMillis);
// AudioFormat af = new Wav16AudioFormat(getSampleRate(), rawData.length);
// wavFile = new WavFileWriter(folderName+fileName, af);
// wavFile.write(rawData);
// wavFile.close();
// // make a data unit to go with it.
// clipDataUnit = new ClipDataUnit(startMillis, dataUnit.getTimeMilliseconds(), rawStart,
// (int)(rawEnd-rawStart), channelMap, fileName, dataBlock.getDataName(), rawData, getSampleRate());
// }
// else {
// clipDataUnit = new ClipDataUnit(startMillis, dataUnit.getTimeMilliseconds(), rawStart,
// (int)(rawEnd-rawStart), channelMap, "", dataBlock.getDataName(), rawData, getSampleRate());
// }
// clipDataUnit.setFrequency(dataUnit.getFrequency());
// lastClipDataUnit = clipDataUnit;
// if (bearingLocaliser != null) {
// localiseClip(clipDataUnit, bearingLocaliser, hydrophoneMap);
// }
// clipDataBlock.addPamData(clipDataUnit);
// }
//
// return 0; // no error.
// }
//
// }
// }
}

View File

@ -25,7 +25,7 @@ public class WavExportOptions implements Serializable, Cloneable {
public static final int SAVEWAV_INDIVIDUAL = 2; public static final int SAVEWAV_INDIVIDUAL = 2;
/** /**
* Flag to indicuate how to save files * Flag to indicate how to save files
*/ */
public int wavSaveChoice = SAVEWAV_CONCAT; public int wavSaveChoice = SAVEWAV_CONCAT;

View File

@ -38,17 +38,17 @@ public class WavOptionsPanel extends PamPanel {
this.setLayout((new GridBagLayout())); this.setLayout((new GridBagLayout()));
addComponent(this, zeroPad = new JRadioButton("Concat"), c); addComponent(this, zeroPad = new JRadioButton("Zero Pad"), c);
c.gridx++; c.gridx++;
addComponent(this, noZeroPad = new JRadioButton("Zero pad"), c); addComponent(this, noZeroPad = new JRadioButton("Concatonate"), c);
c.gridx++; c.gridx++;
addComponent(this, indvidualWav = new JRadioButton("Individual"), c); addComponent(this, indvidualWav = new JRadioButton("Individual"), c);
c.gridx++; // c.gridx++;
addComponent(this, new JLabel(" wav"), c); // addComponent(this, new JLabel(" wav"), c);
// Initialization of object of "ButtonGroup" class. // Initialization of object of "ButtonGroup" class.
ButtonGroup buttonGroup = new ButtonGroup(); ButtonGroup buttonGroup = new ButtonGroup();
@ -97,8 +97,8 @@ public class WavOptionsPanel extends PamPanel {
public WavExportOptions getParams(WavExportOptions wavExportOptions) { public WavExportOptions getParams(WavExportOptions wavExportOptions) {
if (zeroPad.isSelected()) wavExportOptions.wavSaveChoice = WavExportOptions.SAVEWAV_ZERO_PAD; if (zeroPad.isSelected()) wavExportOptions.wavSaveChoice = WavExportOptions.SAVEWAV_ZERO_PAD;
if (noZeroPad.isSelected()) wavExportOptions.wavSaveChoice = WavExportOptions.SAVEWAV_ZERO_PAD; if (noZeroPad.isSelected()) wavExportOptions.wavSaveChoice = WavExportOptions.SAVEWAV_CONCAT;
if (indvidualWav.isSelected()) wavExportOptions.wavSaveChoice = WavExportOptions.SAVEWAV_ZERO_PAD; if (indvidualWav.isSelected()) wavExportOptions.wavSaveChoice = WavExportOptions.SAVEWAV_INDIVIDUAL;
return wavExportOptions; return wavExportOptions;
} }

View File

@ -63,6 +63,7 @@ public class OLProcessDialog extends PamDialog {
private JButton[] settingsButton; private JButton[] settingsButton;
private JLabel status, currFile; private JLabel status, currFile;
private JProgressBar globalProgress; // file by file progress 1: nFiles private JProgressBar globalProgress; // file by file progress 1: nFiles
private JProgressBar loadedProgress; // progress throgh loaded data private JProgressBar loadedProgress; // progress throgh loaded data
private JCheckBox deleteOldData; private JCheckBox deleteOldData;
private JLabel dataInfo; private JLabel dataInfo;
@ -723,7 +724,7 @@ public class OLProcessDialog extends PamDialog {
* @author Doug Gillespie * @author Doug Gillespie
* *
*/ */
class OLMonitor implements TaskMonitor { public class OLMonitor implements TaskMonitor {
@Override @Override
public void setTaskStatus(TaskMonitorData taskMonitorData) { public void setTaskStatus(TaskMonitorData taskMonitorData) {
@ -734,6 +735,7 @@ public class OLProcessDialog extends PamDialog {
else { else {
currFile.setText(taskMonitorData.fileOrStatus); currFile.setText(taskMonitorData.fileOrStatus);
} }
switch (taskMonitorData.taskActivity) { switch (taskMonitorData.taskActivity) {
case LINKING: case LINKING:
case LOADING: case LOADING:
@ -755,6 +757,7 @@ public class OLProcessDialog extends PamDialog {
default: default:
break; break;
} }
switch (taskMonitorData.taskStatus) { switch (taskMonitorData.taskStatus) {
case COMPLETE: case COMPLETE:
globalProgress.setValue(100); globalProgress.setValue(100);
@ -878,6 +881,11 @@ public class OLProcessDialog extends PamDialog {
public void setNeedaNote(boolean isNeedaNote) { public void setNeedaNote(boolean isNeedaNote) {
this.isNeedaNote = isNeedaNote; this.isNeedaNote = isNeedaNote;
} }
public JProgressBar getGlobalProgress() {
return globalProgress;
}

View File

@ -43,29 +43,29 @@ import org.controlsfx.control.ToggleSwitch;
* *
*/ */
public class PamGuiFX extends StackPane implements PamViewInterface { public class PamGuiFX extends StackPane implements PamViewInterface {
/** /**
* This is essentially one PAMGuard stage. PAMGuard may have multiple stages in which case it will have multiple PAMGuiFX instances. * This is essentially one PAMGuard stage. PAMGuard may have multiple stages in which case it will have multiple PAMGuiFX instances.
*/ */
private PamTabPane mainTabPane; private PamTabPane mainTabPane;
/** /**
* The preferred width of the side pane. * The preferred width of the side pane.
*/ */
public static final double SIDE_PANE_PREF_WIDTH = 250; public static final double SIDE_PANE_PREF_WIDTH = 250;
// /** // /**
// * Icon for menu // * Icon for menu
// */ // */
// public Image menuIconGrey=new Image(getClass().getResourceAsStream("/Resources/MenuButton.png")); // public Image menuIconGrey=new Image(getClass().getResourceAsStream("/Resources/MenuButton.png"));
// //
// public Image showButtonGrey=new Image(getClass().getResourceAsStream("/Resources/SidePanelShow2Grey.png")); // public Image showButtonGrey=new Image(getClass().getResourceAsStream("/Resources/SidePanelShow2Grey.png"));
// //
// public Image hideButtonGrey=new Image(getClass().getResourceAsStream("/Resources/SidePanelHide2Grey.png")); // public Image hideButtonGrey=new Image(getClass().getResourceAsStream("/Resources/SidePanelHide2Grey.png"));
// //
// public Image recordStart=new Image(getClass().getResourceAsStream("/Resources/recordStart.png")); // public Image recordStart=new Image(getClass().getResourceAsStream("/Resources/recordStart.png"));
// //
// public Image playPause=new Image(getClass().getResourceAsStream("/Resources/playStart.png")); // public Image playPause=new Image(getClass().getResourceAsStream("/Resources/playStart.png"));
/** /**
* A reference to the stage this PAMGUIFX belongs to. * A reference to the stage this PAMGUIFX belongs to.
@ -81,18 +81,18 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
* Hiding side pane. * Hiding side pane.
*/ */
private HidingPane hidingSidePane; private HidingPane hidingSidePane;
/** /**
* The Pane which holds everything that sits in hide pane. * The Pane which holds everything that sits in hide pane.
*/ */
private PamVBox sidePaneContent; private PamVBox sidePaneContent;
/** /**
* Pane which holds main PAMGUARD settings * Pane which holds main PAMGUARD settings
*/ */
private PamVBox settingsPane; private PamVBox settingsPane;
/** /**
* Hiding pane which holds settings * Hiding pane which holds settings
*/ */
@ -121,34 +121,34 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
* @param pamGuiManagerFX - the GUI manager. * @param pamGuiManagerFX - the GUI manager.
*/ */
public PamGuiFX (PamTabPane mainTabPane, Stage stage, PamGuiManagerFX pamGuiManagerFX){ public PamGuiFX (PamTabPane mainTabPane, Stage stage, PamGuiManagerFX pamGuiManagerFX){
this.stage=stage; this.stage=stage;
this.pamGuiManagerFX=pamGuiManagerFX; this.pamGuiManagerFX=pamGuiManagerFX;
this.mainTabPane = mainTabPane; this.mainTabPane = mainTabPane;
Node layout=createMainPane(mainTabPane, stage); Node layout=createMainPane(mainTabPane, stage);
//add main pane to PamGui //add main pane to PamGui
this.getChildren().add(layout); this.getChildren().add(layout);
} }
public PamGuiFX (Stage stage, PamGuiManagerFX pamGuiManagerFX){ public PamGuiFX (Stage stage, PamGuiManagerFX pamGuiManagerFX){
this.stage=stage; this.stage=stage;
this.pamGuiManagerFX=pamGuiManagerFX; this.pamGuiManagerFX=pamGuiManagerFX;
//create the main tab pane. //create the main tab pane.
this.mainTabPane = new PamTabPane(); this.mainTabPane = new PamTabPane();
Node layout=createMainPane(mainTabPane, stage); Node layout=createMainPane(mainTabPane, stage);
//add main pane to PamGui //add main pane to PamGui
this.getChildren().add(layout); this.getChildren().add(layout);
} }
/** /**
* Create the pane which sits inside stage and holds tabs, side pane. * Create the pane which sits inside stage and holds tabs, side pane.
* @param mainTabPane - the main tab pane for the scene. * @param mainTabPane - the main tab pane for the scene.
@ -174,7 +174,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
//create the button which shows the hiding panel. Although we get this button from the hiding pane, where to place //create the button which shows the hiding panel. Although we get this button from the hiding pane, where to place
//it and what colour it is etc has to be set for whatever pane it is to be located in. //it and what colour it is etc has to be set for whatever pane it is to be located in.
PamButton showButtonRight=hidingSidePane.getShowButton(); PamButton showButtonRight=hidingSidePane.getShowButton();
// showButtonRight.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_LEFT, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize)); // showButtonRight.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_LEFT, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
showButtonRight.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-left", PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize)); showButtonRight.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-left", PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
//showLeftButton.setText(PamFontAwesome.ICON_CHEVRON_LEFT); //showLeftButton.setText(PamFontAwesome.ICON_CHEVRON_LEFT);
showButtonRight.getStyleClass().add("close-button-left-trans"); showButtonRight.getStyleClass().add("close-button-left-trans");
@ -183,10 +183,10 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
//alter animations to remove/add showButton to tab pane. //alter animations to remove/add showButton to tab pane.
//TODO- tried to have animation here to hide buttons but didn't appear to work. //TODO- tried to have animation here to hide buttons but didn't appear to work.
//Maybe an issue with running another animation from animation thread? //Maybe an issue with running another animation from animation thread?
// showButton.prefWidthProperty().addListener((listener)->{ // showButton.prefWidthProperty().addListener((listener)->{
// mainTabPane.layout(); //Don't need this // mainTabPane.layout(); //Don't need this
// }); // });
hidingSidePane.getTimeLineShow().setOnFinished((value)->{ hidingSidePane.getTimeLineShow().setOnFinished((value)->{
showButtonRight.setPrefWidth(1); showButtonRight.setPrefWidth(1);
showButtonRight.setVisible(false); showButtonRight.setVisible(false);
@ -203,55 +203,55 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
PamButton closeButtonLeft=hidingSidePane.getHideButton(); PamButton closeButtonLeft=hidingSidePane.getHideButton();
closeButtonLeft.getStyleClass().add("close-button-right-trans"); closeButtonLeft.getStyleClass().add("close-button-right-trans");
// closeButtonLeft.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_RIGHT, Color.DARKGRAY.darker(), PamGuiManagerFX.iconSize)); // closeButtonLeft.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_RIGHT, Color.DARKGRAY.darker(), PamGuiManagerFX.iconSize));
closeButtonLeft.prefHeightProperty().bind(mainTabPane.getHeaderHeightProperty()); closeButtonLeft.prefHeightProperty().bind(mainTabPane.getHeaderHeightProperty());
//add hiding pane to main pane. //add hiding pane to main pane.
layout.setRight(hidingSidePane); layout.setRight(hidingSidePane);
/**create settings pane. This allows access to primary PAMGUARD settings.**/ /**create settings pane. This allows access to primary PAMGUARD settings.**/
settingsPane=new PamSettingsMenuPane(); settingsPane=new PamSettingsMenuPane();
settingsPane.setPrefWidth(250); settingsPane.setPrefWidth(250);
hidingPaneLeft=new HidingPane(Side.LEFT, settingsPane, this, false); hidingPaneLeft=new HidingPane(Side.LEFT, settingsPane, this, false);
hidingPaneLeft.showHidePane(false); hidingPaneLeft.showHidePane(false);
hidingPaneLeft.getStylesheets().addAll(pamGuiManagerFX.getPamSettingsCSS()); hidingPaneLeft.getStylesheets().addAll(pamGuiManagerFX.getPamSettingsCSS());
PamButton showButtonLeft=hidingPaneLeft.getShowButton(); PamButton showButtonLeft=hidingPaneLeft.getShowButton();
// showButtonLeft.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.BARS, Color.LIGHTGRAY, PamGuiManagerFX.iconSize)); // showButtonLeft.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.BARS, Color.LIGHTGRAY, PamGuiManagerFX.iconSize));
showButtonLeft.setGraphic(PamGlyphDude.createPamIcon("mdi2m-menu", Color.LIGHTGRAY, PamGuiManagerFX.iconSize)); showButtonLeft.setGraphic(PamGlyphDude.createPamIcon("mdi2m-menu", Color.LIGHTGRAY, PamGuiManagerFX.iconSize));
showButtonLeft.getStyleClass().add("close-button-right-trans"); showButtonLeft.getStyleClass().add("close-button-right-trans");
showButtonLeft.setStyle(" -fx-background-radius: 0 0 0 0;"); showButtonLeft.setStyle(" -fx-background-radius: 0 0 0 0;");
PamButton closeRightButton=hidingPaneLeft.getHideButton(); PamButton closeRightButton=hidingPaneLeft.getHideButton();
closeRightButton.setPrefWidth(40); closeRightButton.setPrefWidth(40);
closeRightButton.getStyleClass().add("close-button-left-trans"); closeRightButton.getStyleClass().add("close-button-left-trans");
// closeRightButton.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_LEFT, Color.WHITE, PamGuiManagerFX.iconSize)); // closeRightButton.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_LEFT, Color.WHITE, PamGuiManagerFX.iconSize));
closeRightButton.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-left", Color.WHITE, PamGuiManagerFX.iconSize)); closeRightButton.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-left", Color.WHITE, PamGuiManagerFX.iconSize));
closeRightButton.prefHeightProperty().bind(mainTabPane.getHeaderHeightProperty()); closeRightButton.prefHeightProperty().bind(mainTabPane.getHeaderHeightProperty());
//add hiding pane to main pane. //add hiding pane to main pane.
layout.setLeft(hidingPaneLeft); layout.setLeft(hidingPaneLeft);
// //Create a button which sits at end of tab pane // //Create a button which sits at end of tab pane
// settingsButton = new PamButton(); // settingsButton = new PamButton();
// settingsButton.setMinWidth(Control.USE_PREF_SIZE); // settingsButton.setMinWidth(Control.USE_PREF_SIZE);
// settingsButton.setGraphic(Glyph.create("FontAwesome|BARS").size(22).color(Color.DARKGREY.darker())); // settingsButton.setGraphic(Glyph.create("FontAwesome|BARS").size(22).color(Color.DARKGREY.darker()));
// settingsButton.getStyleClass().add("transparent-button"); // settingsButton.getStyleClass().add("transparent-button");
//// settingsButton.setPadding(new Insets(0,10,0,10)); //// settingsButton.setPadding(new Insets(0,10,0,10));
// settingsButton.setOnAction(e -> { // settingsButton.setOnAction(e -> {
// //TODO-open settings menu // //TODO-open settings menu
// }); // });
mainTabPane.setTabEndRegion(showButtonRight); mainTabPane.setTabEndRegion(showButtonRight);
mainTabPane.setTabStartRegion(showButtonLeft); mainTabPane.setTabStartRegion(showButtonLeft);
// mainTabPane.getStyleClass().add(Styles.TABS_FLOATING); // mainTabPane.getStyleClass().add(Styles.TABS_FLOATING);
mainTabPane.getAddTabButton().setOnAction((value)->{ mainTabPane.getAddTabButton().setOnAction((value)->{
addPamTab(new TabInfo("Display " + (this.getNumTabs()+1)), null ,true); addPamTab(new TabInfo("Display " + (this.getNumTabs()+1)), null ,true);
mainTabPane.layout(); mainTabPane.layout();
}); });
//now have a holder - add the loading pane. //now have a holder - add the loading pane.
/**create left hiding pane**/ /**create left hiding pane**/
loadPane=new PamLoadingPane(this.pamGuiManagerFX); loadPane=new PamLoadingPane(this.pamGuiManagerFX);
@ -259,14 +259,14 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
hidingLoadPane.setPrefHeight(110); hidingLoadPane.setPrefHeight(110);
hidingLoadPane.removeHideButton(); hidingLoadPane.removeHideButton();
hidingLoadPane.showHidePane(false); hidingLoadPane.showHidePane(false);
PamBorderPane layoutHolder=new PamBorderPane(layout); PamBorderPane layoutHolder=new PamBorderPane(layout);
layoutHolder.setTop(hidingLoadPane); layoutHolder.setTop(hidingLoadPane);
return layoutHolder; return layoutHolder;
} }
/** /**
* Get the load pane for the PamGuiFX- shows loading data and other status updates. * Get the load pane for the PamGuiFX- shows loading data and other status updates.
* @return the PamLoadingf Pane * @return the PamLoadingf Pane
@ -281,79 +281,79 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
public void show(){ public void show(){
stage.show(); stage.show();
} }
/** /**
* Convenience function to add a closable tab to the display with a new UserDisplayNodeFX. * Convenience function to add a closable tab to the display with a new UserDisplayNodeFX.
* @param name- tab name. * @param name- tab name.
* @param content- content to add to the tab. Can be null; * @param content- content to add to the tab. Can be null;
*/ */
public PamGuiTabFX addPamTab(TabInfo tabInfo, UserDisplayNodeFX content, boolean detachable ){ public PamGuiTabFX addPamTab(TabInfo tabInfo, UserDisplayNodeFX content, boolean detachable ){
//create holder pane and add to tab //create holder pane and add to tab
PamGuiTabFX newTab = new PamGuiTabFX(tabInfo, this); PamGuiTabFX newTab = new PamGuiTabFX(tabInfo, this);
newTab.setToolbar(new ToolBarPane(newTab)); newTab.setToolbar(new ToolBarPane(newTab));
//static displays have non closable tabs and non resizable displays //static displays have non closable tabs and non resizable displays
if (content!=null){ if (content!=null){
newTab.setClosable(!content.isStaticDisplay()); newTab.setClosable(!content.isStaticDisplay());
newTab.setResizableDisplays(!content.isStaticDisplay()); newTab.setResizableDisplays(!content.isStaticDisplay());
if (content.isStaticDisplay()){ if (content.isStaticDisplay()){
//if static, then add to center. //if static, then add to center.
newTab.getContentHolder().setCenter(content.getNode()); newTab.getContentHolder().setCenter(content.getNode());
} }
else{ else{
//add content- will not add and return null if content is null //add content- will not add and return null if content is null
newTab.addInternalPane(content); newTab.addInternalPane(content);
} }
} }
newTab.setOnClosed((action)->{
//when a tab is closer.
for (int i=0; i<newTab.getInternalPanes().size(); i++) {
System.out.println("REMOVE TAB: " + newTab.getInternalPanes().size());
newTab.getInternalPanes().get(i).getUserDisplayNode().closeNode(); newTab.setOnClosed((action)->{
if (newTab.getInternalPanes().get(i).getUserDisplayNode().getUserDisplayControl()!=null) { //when a tab is closer.
System.out.println("REMOVE CONTROLLED DISPLAY UNIT: " + newTab.getInternalPanes().get(i).getUserDisplayNode().getUserDisplayControl()); for (int i=0; i<newTab.getInternalPanes().size(); i++) {
//the display is a standalone display and so remove the tab means the controlled unit should be removed from the data model System.out.println("REMOVE TAB: " + newTab.getInternalPanes().size());
PamController.getInstance().removeControlledUnt(newTab.getInternalPanes().get(i).getUserDisplayNode().getUserDisplayControl());
PamGuiManagerFX.getInstance().getDataModelFX().dataModeltoPamModel(); newTab.getInternalPanes().get(i).getUserDisplayNode().closeNode();
} if (newTab.getInternalPanes().get(i).getUserDisplayNode().getUserDisplayControl()!=null) {
} System.out.println("REMOVE CONTROLLED DISPLAY UNIT: " + newTab.getInternalPanes().get(i).getUserDisplayNode().getUserDisplayControl());
}); //the display is a standalone display and so remove the tab means the controlled unit should be removed from the data model
PamController.getInstance().removeControlledUnt(newTab.getInternalPanes().get(i).getUserDisplayNode().getUserDisplayControl());
newTab.setDetachable(detachable); PamGuiManagerFX.getInstance().getDataModelFX().dataModeltoPamModel();
}
//add tab }
mainTabPane.getTabs().add(newTab); });
return newTab; newTab.setDetachable(detachable);
//add tab
mainTabPane.getTabs().add(newTab);
return newTab;
} }
/** /**
* Add a tab for the data model. * Add a tab for the data model.
* @param dataModelPaneFX - the data model * @param dataModelPaneFX - the data model
*/ */
public DataModelPaneFX addDataModelTab() { public DataModelPaneFX addDataModelTab() {
PamGuiTabFX newTab = new PamGuiTabFX(new TabInfo("Data Model"), this); PamGuiTabFX newTab = new PamGuiTabFX(new TabInfo("Data Model"), this);
newTab.setToolbar(new ToolBarPane(newTab)); newTab.setToolbar(new ToolBarPane(newTab));
newTab.setClosable(false); //can't close a data model newTab.setClosable(false); //can't close a data model
newTab.setDetachable(false); newTab.setDetachable(false);
mainTabPane.getTabs().add(newTab); mainTabPane.getTabs().add(newTab);
DataModelPaneFX dataModelPaneFX=new DataModelPaneFX(); DataModelPaneFX dataModelPaneFX=new DataModelPaneFX();
//create controls in the tool bar for the data model //create controls in the tool bar for the data model
dataModelPaneFX.createToolbarControls(newTab); dataModelPaneFX.createToolbarControls(newTab);
newTab.setMainContent(dataModelPaneFX); newTab.setMainContent(dataModelPaneFX);
return dataModelPaneFX; return dataModelPaneFX;
} }
/** /**
* Get all tabs for this PamGuiFX * Get all tabs for this PamGuiFX
* @return list of tabs in the PamGuiFX * @return list of tabs in the PamGuiFX
@ -365,7 +365,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
} }
return tabs; return tabs;
} }
/** /**
* Add a tab to the tab pane. * Add a tab to the tab pane.
* @param pamGuiTabFX - the tab to add * @param pamGuiTabFX - the tab to add
@ -374,7 +374,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
// add a tab. // add a tab.
mainTabPane.getTabs().add(pamGuiTabFX); mainTabPane.getTabs().add(pamGuiTabFX);
} }
/** /**
* Add tabs to the tab pane. * Add tabs to the tab pane.
* @param pamGuiTabFX - the tabs to add * @param pamGuiTabFX - the tabs to add
@ -383,7 +383,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
// add a tab.> // add a tab.>
mainTabPane.getTabs().addAll(pamGuiTabFXs); mainTabPane.getTabs().addAll(pamGuiTabFXs);
} }
/** /**
* Get the number of tabs currently open. * Get the number of tabs currently open.
* @return the number of tabs. * @return the number of tabs.
@ -391,7 +391,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
public int getNumTabs(){ public int getNumTabs(){
return mainTabPane.getTabs().size(); return mainTabPane.getTabs().size();
} }
/** /**
* Get a tab * Get a tab
* @param i - tab index * @param i - tab index
@ -400,16 +400,16 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
public PamGuiTabFX getTab(int i){ public PamGuiTabFX getTab(int i){
return (PamGuiTabFX) mainTabPane.getTabs().get(i); return (PamGuiTabFX) mainTabPane.getTabs().get(i);
} }
/** /**
* Select a tab * Select a tab
* @param j - index * @param j - index
*/ */
public void selectTab(int j) { public void selectTab(int j) {
this.mainTabPane.getSelectionModel().select(j); this.mainTabPane.getSelectionModel().select(j);
} }
/** /**
* Create the tool bar pane. The top of each tab content node contains a tool * Create the tool bar pane. The top of each tab content node contains a tool
@ -423,24 +423,24 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
* *
*/ */
public class ToolBarPane extends PamBorderPane { public class ToolBarPane extends PamBorderPane {
/** /**
* Record/batch process button. In real time starts/stops data acquisition. In viewer mode * Record/batch process button. In real time starts/stops data acquisition. In viewer mode
* opens the batch run manager to allow batch processing of data e.g. reclassifying clicks. * opens the batch run manager to allow batch processing of data e.g. reclassifying clicks.
*/ */
private PamButton recordButton; private PamButton recordButton;
/** /**
*Play/pause button. Plays back sound in real time/viewer mode. *Play/pause button. Plays back sound in real time/viewer mode.
*/ */
private PamButton playButton; private PamButton playButton;
/** /**
* Holds all extra controls in the toolbar. * Holds all extra controls in the toolbar.
*/ */
private PamHBox centerHBox; private PamHBox centerHBox;
/** /**
* Height of the toolbar. * Height of the toolbar.
*/ */
@ -466,59 +466,76 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
* Button to select what autosort option for windows. * Button to select what autosort option for windows.
*/ */
private MenuButton autoSortChoice; private MenuButton autoSortChoice;
public ToolBarPane(PamGuiTabFX pamGuiTab){ public ToolBarPane(PamGuiTabFX pamGuiTab){
super(); super();
this.pamGuiTab=pamGuiTab;
//create record and play buttons.
PamHBox playControls=new PamHBox();
recordButton=new PamButton();
// recordButton.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CIRCLE, Color.LIMEGREEN, PamGuiManagerFX.iconSize));
recordButton.setGraphic(PamGlyphDude.createPamIcon("mdi2r-record-circle", Color.RED, PamGuiManagerFX.iconSize));
recordButton.getStyleClass().add("transparent-button");
//recordButton.setStyle(" -fx-background-radius: 50;");
recordButton.setOnAction((action)->{
if (PamController.getInstance().getPamStatus()==PamController.PAM_RUNNING){
PamController.getInstance().pamStop();
pamGuiManagerFX.setPamRunning(false);
}
else {
PamController.getInstance().pamStart();
pamGuiManagerFX.setPamRunning(true);
}
});
playButton=new PamButton(); this.pamGuiTab=pamGuiTab;
// playButton.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.PLAY, Color.BLACK, PamGuiManagerFX.iconSize));
playButton.setGraphic(PamGlyphDude.createPamIcon("mdi2p-play", Color.BLACK, PamGuiManagerFX.iconSize)); PamHBox analysisControls=new PamHBox();
playButton.getStyleClass().add("transparent-button"); analysisControls.setSpacing(10);
//playButton.setStyle(" -fx-background-radius: 50;"); analysisControls.setPadding(new Insets(0,10,0,20));
playButton.setOnAction((action)->{ // playControls.getStyleClass().add("pane-opaque");
//TODO analysisControls.setPrefHeight(prefHeight);
//start pamguard analysisControls.setAlignment(Pos.CENTER);
//PamController.getInstance().pamStart();
}); if (PamController.getInstance().getRunMode() == PamController.RUN_PAMVIEW) {
//in PMAGUard viewer mode we want a reporcess button
playControls.getChildren().addAll(recordButton,playButton);
playControls.setSpacing(10); PamButton reProcessButton=new PamButton("Reprocess...");
playControls.setPadding(new Insets(0,10,0,20)); reProcessButton.setGraphic(PamGlyphDude.createPamIcon("mdi2c-cog-transfer", PamGuiManagerFX.iconSize));
// playControls.getStyleClass().add("pane-opaque"); reProcessButton.setOnAction((action->{
playControls.setPrefHeight(prefHeight);
playControls.setAlignment(Pos.CENTER); }));
analysisControls.getChildren().addAll(reProcessButton);
}
else {
//real time mode
//create record and play buttons.
recordButton=new PamButton();
// recordButton.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CIRCLE, Color.LIMEGREEN, PamGuiManagerFX.iconSize));
recordButton.setGraphic(PamGlyphDude.createPamIcon("mdi2r-record-circle", Color.RED, PamGuiManagerFX.iconSize));
recordButton.getStyleClass().add("transparent-button");
recordButton.setStyle("-fx-padding: 0 10 0 10;");
//recordButton.setStyle(" -fx-background-radius: 50;");
recordButton.setOnAction((action)->{
if (PamController.getInstance().getPamStatus()==PamController.PAM_RUNNING){
PamController.getInstance().pamStop();
pamGuiManagerFX.setPamRunning(false);
}
else {
PamController.getInstance().pamStart();
pamGuiManagerFX.setPamRunning(true);
}
});
// playButton=new PamButton();
//// playButton.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.PLAY, Color.BLACK, PamGuiManagerFX.iconSize));
// playButton.setGraphic(PamGlyphDude.createPamIcon("mdi2p-play", Color.BLACK, PamGuiManagerFX.iconSize));
// playButton.getStyleClass().add("transparent-button");
// //playButton.setStyle(" -fx-background-radius: 50;");
// playButton.setOnAction((action)->{
// //TODO
// //start pamguard
// //PamController.getInstance().pamStart();
// });
analysisControls.getChildren().addAll(recordButton);
}
//create window editing button. This holds a toggle to edit windows and options. //create window editing button. This holds a toggle to edit windows and options.
rightHBox=new PamHBox(); rightHBox=new PamHBox();
rightHBox.setAlignment(Pos.CENTER_LEFT); rightHBox.setAlignment(Pos.CENTER_LEFT);
rightHBox.setPadding(new Insets(0,10,0,20)); rightHBox.setPadding(new Insets(0,10,0,20));
rightHBox.setSpacing(5); rightHBox.setSpacing(5);
// rightHBox.getStyleClass().add("pane-opaque"); // rightHBox.getStyleClass().add("pane-opaque");
editWindows=new ToggleSwitch("Resize"); editWindows=new ToggleSwitch("Resize");
//HACK, //HACK,
editWindows.setPadding(new Insets(8,0,0,0)); editWindows.setPadding(new Insets(8,0,0,0));
@ -527,56 +544,56 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
boolean editable=!pamGuiTab.getEditable(); boolean editable=!pamGuiTab.getEditable();
pamGuiTab.setPanesEditable(editable); pamGuiTab.setPanesEditable(editable);
}); });
//add a choice box to allow users to automatically resize windows. //add a choice box to allow users to automatically resize windows.
autoSortChoice=new MenuButton(); autoSortChoice=new MenuButton();
autoSortChoice.getStyleClass().add("transparent-button"); autoSortChoice.getStyleClass().add("transparent-button");
// autoSortChoice.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.ELLIPSIS_V, // autoSortChoice.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.ELLIPSIS_V,
autoSortChoice.setGraphic(PamGlyphDude.createPamIcon("mdi2d-dots-vertical", autoSortChoice.setGraphic(PamGlyphDude.createPamIcon("mdi2d-dots-vertical",
Color.DARKGRAY, PamGuiManagerFX.iconSize)); Color.DARKGRAY, PamGuiManagerFX.iconSize));
MenuItem tile=new MenuItem("Tile"); MenuItem tile=new MenuItem("Tile");
tile.setOnAction((action)->{ tile.setOnAction((action)->{
pamGuiTab.autoSortPanes(PamGuiTabFX.SORT_TILE); pamGuiTab.autoSortPanes(PamGuiTabFX.SORT_TILE);
}); });
MenuItem vertical=new MenuItem("Horizontal"); MenuItem vertical=new MenuItem("Horizontal");
vertical.setOnAction((action)->{ vertical.setOnAction((action)->{
pamGuiTab.autoSortPanes(PamGuiTabFX.SORT_HORIZONTAL); pamGuiTab.autoSortPanes(PamGuiTabFX.SORT_HORIZONTAL);
}); });
MenuItem horizontal=new MenuItem("Vertical"); MenuItem horizontal=new MenuItem("Vertical");
horizontal.setOnAction((action)->{ horizontal.setOnAction((action)->{
pamGuiTab.autoSortPanes(PamGuiTabFX.SORT_VERTICAL); pamGuiTab.autoSortPanes(PamGuiTabFX.SORT_VERTICAL);
}); });
autoSortChoice.getItems().addAll(tile, vertical, horizontal); autoSortChoice.getItems().addAll(tile, vertical, horizontal);
rightHBox.getChildren().addAll(editWindows, autoSortChoice); rightHBox.getChildren().addAll(editWindows, autoSortChoice);
//create content hboc for extra controls. //create content hboc for extra controls.
centerHBox=new PamHBox(); centerHBox=new PamHBox();
centerHBox.setSpacing(10); centerHBox.setSpacing(10);
//need to set this style to prevent the pane form being transparent. //need to set this style to prevent the pane form being transparent.
//centerHBox.getStyleClass().add("pane-opaque"); //centerHBox.getStyleClass().add("pane-opaque");
centerHBox.setPrefHeight(prefHeight); centerHBox.setPrefHeight(prefHeight);
this.setCenter(centerHBox); this.setCenter(centerHBox);
this.setLeft(playControls); this.setLeft(analysisControls);
this.setRight(rightHBox); this.setRight(rightHBox);
this.setPrefHeight(prefHeight); this.setPrefHeight(prefHeight);
this.getStyleClass().add("pane-opaque"); this.getStyleClass().add("pane-opaque");
//this.setPadding(new Insets(0,0,0,0)); //this.setPadding(new Insets(0,0,0,0));
this.toFront(); this.toFront();
} }
/** /**
* Get the content HBox. This holds any extra controls in the top tool bar. * Get the content HBox. This holds any extra controls in the top tool bar.
* @return HBox to add extra toolbar content to. * @return HBox to add extra toolbar content to.
@ -584,7 +601,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
public PamHBox getCenterHBox(){ public PamHBox getCenterHBox(){
return centerHBox; return centerHBox;
} }
/** /**
* Add a node to the content area of the toolbar. * Add a node to the content area of the toolbar.
* @param node - node to add. * @param node - node to add.
@ -592,7 +609,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
public void addToolbarNode(Node node){ public void addToolbarNode(Node node){
centerHBox.getChildren().add(node); centerHBox.getChildren().add(node);
} }
/** /**
* Get the button which starts and stops PAMGUARD. * Get the button which starts and stops PAMGUARD.
* @return the button. * @return the button.
@ -600,7 +617,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
public Button getRecordButton(){ public Button getRecordButton(){
return recordButton; return recordButton;
} }
/** /**
* Get the HBox on the right hand side of the toolbar. * Get the HBox on the right hand side of the toolbar.
* @return hbox on right hand side of display. * @return hbox on right hand side of display.
@ -616,7 +633,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
/** /**
* Show the controls which allows manula resizing of the pane. * Show the controls which allows manual resizing of the pane.
* @param resize. * @param resize.
*/ */
public void showResizableControl(boolean resize) { public void showResizableControl(boolean resize) {
@ -627,7 +644,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
} }
} }
/** /**
* Get all record buttons from the different toolbars in this stage. * Get all record buttons from the different toolbars in this stage.
* @return list of record buttons. * @return list of record buttons.
@ -640,7 +657,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
} }
return buttons; return buttons;
} }
/** /**
* Remove an internal pane if it is contained within any tabs within the PamGuiFX * Remove an internal pane if it is contained within any tabs within the PamGuiFX
* @param removeNode - remove the pane if it contains this node. * @param removeNode - remove the pane if it contains this node.
@ -651,7 +668,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
tabs.get(i).removeInternalPane(removeNode); tabs.get(i).removeInternalPane(removeNode);
} }
} }
/** /**
* Show the PamLoadPnae- this shows the pane that contains progress bars for loading data. * Show the PamLoadPnae- this shows the pane that contains progress bars for loading data.
* @param show - true to show pane. * @param show - true to show pane.
@ -676,13 +693,13 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
* @param pamTaskUpdate - information on a thread which s currently doing some work. * @param pamTaskUpdate - information on a thread which s currently doing some work.
*/ */
public void notifyLoadProgress(PamTaskUpdate pamTaskUpdate) { public void notifyLoadProgress(PamTaskUpdate pamTaskUpdate) {
Platform.runLater (() -> this.loadPane.updateLoadPane(pamTaskUpdate)); Platform.runLater (() -> this.loadPane.updateLoadPane(pamTaskUpdate));
} }
@Override @Override
public void pamStarted() { public void pamStarted() {
this.pamGuiManagerFX.pamStarted(); this.pamGuiManagerFX.pamStarted();
} }
@Override @Override
@ -693,19 +710,19 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
@Override @Override
public void modelChanged(int changeType) { public void modelChanged(int changeType) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override @Override
public void addControlledUnit(PamControlledUnit unit) { public void addControlledUnit(PamControlledUnit unit) {
this.pamGuiManagerFX.addControlledUnit(unit); this.pamGuiManagerFX.addControlledUnit(unit);
} }
@Override @Override
public void removeControlledUnit(PamControlledUnit unit) { public void removeControlledUnit(PamControlledUnit unit) {
this.pamGuiManagerFX.removeControlledUnit(unit); this.pamGuiManagerFX.removeControlledUnit(unit);
} }
@Override @Override
@ -716,7 +733,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
@Override @Override
public void setTitle(String title) { public void setTitle(String title) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override @Override
@ -733,7 +750,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
@Override @Override
public void enableGUIControl(boolean enable) { public void enableGUIControl(boolean enable) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
/** /**
@ -769,7 +786,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
public PamVBox getSidePane() { public PamVBox getSidePane() {
return sidePaneContent; return sidePaneContent;
} }
/** /**
* Show the side pane. The side pane holds extra quick access * Show the side pane. The side pane holds extra quick access
* controls for modules. * controls for modules.
@ -778,7 +795,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
public void showSidePane(boolean show) { public void showSidePane(boolean show) {
this.hidingSidePane.showHidePane(show); this.hidingSidePane.showHidePane(show);
} }
/** /**
* Rename a tab at a selected index. * Rename a tab at a selected index.
* @param selectedItem - the new name * @param selectedItem - the new name

View File

@ -1,15 +1,9 @@
package pamViewFX; package pamViewFX;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import atlantafx.base.controls.ToggleSwitch;
import atlantafx.base.theme.PrimerDark;
import atlantafx.base.theme.PrimerLight;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.control.ContentDisplay; import javafx.scene.control.ContentDisplay;
@ -96,7 +90,16 @@ public class PamLauncherPane extends PamBorderPane {
// this.getStylesheets().add(getClass().getResource(primerPAMGuard).toExternalForm()); // this.getStylesheets().add(getClass().getResource(primerPAMGuard).toExternalForm());
// this.getStylesheets().add(getClass().getResource(new PrimerDark().getUserAgentStylesheet()).toExternalForm()); // this.getStylesheets().add(getClass().getResource(new PrimerDark().getUserAgentStylesheet()).toExternalForm());
PamStylesManagerFX.getPamStylesManagerFX().setCurStyle(new PamDefaultStyle()); PamStylesManagerFX.getPamStylesManagerFX().setCurStyle(new PamDefaultStyle());
}
private void setStyle(boolean PAMGuardFX) {
this.getStylesheets().clear();
if (PAMGuardFX) {
PamStylesManagerFX.getPamStylesManagerFX().setCurStyle(new PamAtlantaStyle());
this.getStylesheets().addAll(PamStylesManagerFX.getPamStylesManagerFX().getCurStyle().getDialogCSS());
this.setStyle("-fx-background-color: -fx-darkbackground");
}
} }

View File

@ -42,7 +42,6 @@ import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup; import javafx.scene.control.ToggleGroup;
import javafx.scene.control.Tooltip; import javafx.scene.control.Tooltip;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.paint.Color;
/** /**
* Pane which holds settings menu. All primary settings are accessed from this pane which sits in a hiding pane to the right * Pane which holds settings menu. All primary settings are accessed from this pane which sits in a hiding pane to the right

View File

@ -4,6 +4,8 @@ import java.util.ArrayList;
import PamView.ColourScheme; import PamView.ColourScheme;
import PamView.PamColors; import PamView.PamColors;
import atlantafx.base.theme.CupertinoDark;
import atlantafx.base.theme.CupertinoLight;
import atlantafx.base.theme.PrimerDark; import atlantafx.base.theme.PrimerDark;
import atlantafx.base.theme.PrimerLight; import atlantafx.base.theme.PrimerLight;
@ -53,6 +55,7 @@ public class PamAtlantaStyle extends PamDefaultStyle {
// private String guiCSS = new NordDark().getUserAgentStylesheet(); // private String guiCSS = new NordDark().getUserAgentStylesheet();
// protected String primerlight = "/Resources/css/primer-light.css"; // protected String primerlight = "/Resources/css/primer-light.css";
protected String primerlight = new PrimerLight().getUserAgentStylesheet(); protected String primerlight = new PrimerLight().getUserAgentStylesheet();
// protected String primerlight = new CupertinoLight().getUserAgentStylesheet();
/** /**
* Relative location of the CSS style sheet to be used for the Pamguard standard * Relative location of the CSS style sheet to be used for the Pamguard standard
@ -62,6 +65,7 @@ public class PamAtlantaStyle extends PamDefaultStyle {
// private String dialogCSS = new PrimerDark().getUserAgentStylesheet(); // private String dialogCSS = new PrimerDark().getUserAgentStylesheet();
// protected String primerdark = "/Resources/css/primer-dark.css"; // protected String primerdark = "/Resources/css/primer-dark.css";
protected String primerdark = new PrimerDark().getUserAgentStylesheet(); protected String primerdark = new PrimerDark().getUserAgentStylesheet();
// protected String primerdark = new CupertinoDark().getUserAgentStylesheet();
/** /**

View File

@ -7,6 +7,7 @@ import java.util.ArrayList;
import org.jamdev.jdl4pam.transforms.DLTransformsFactory; import org.jamdev.jdl4pam.transforms.DLTransformsFactory;
import org.jamdev.jdl4pam.transforms.DLTransfromParams; import org.jamdev.jdl4pam.transforms.DLTransfromParams;
import org.jamdev.jdl4pam.transforms.SimpleTransformParams; import org.jamdev.jdl4pam.transforms.SimpleTransformParams;
import org.jamdev.jpamutils.wavFiles.AudioData;
import org.jamdev.jdl4pam.transforms.DLTransform.DLTransformType; import org.jamdev.jdl4pam.transforms.DLTransform.DLTransformType;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -31,7 +32,7 @@ public class ClickDLTest {
System.out.println("*****Click classification Deep Learning C*****"); System.out.println("*****Click classification Deep Learning C*****");
//relative paths to the resource folders. //relative paths to the resource folders.
String relModelPath = "./src/test/resources/rawDeepLearningClassifier/Generic/risso_click/updated_model/saved_model.pb"; String relModelPath = "./src/test/resources/rawDeepLearningClassifier/Generic/risso_click/uniform_model/saved_model.pb";
String clicksPath = "./src/test/resources/rawDeepLearningClassifier/Generic/risso_click/clicks.mat"; String clicksPath = "./src/test/resources/rawDeepLearningClassifier/Generic/risso_click/clicks.mat";
Path path = Paths.get(relModelPath); Path path = Paths.get(relModelPath);
@ -45,14 +46,17 @@ public class ClickDLTest {
//create the transforms. //create the transforms.
ArrayList<DLTransfromParams> dlTransformParamsArr = new ArrayList<DLTransfromParams>(); ArrayList<DLTransfromParams> dlTransformParamsArr = new ArrayList<DLTransfromParams>();
dlTransformParamsArr.add(new SimpleTransformParams(DLTransformType.NORMALISE_WAV)); //waveform transforms.
dlTransformParamsArr.add(new SimpleTransformParams(DLTransformType.DECIMATE_SCIPY, 248000.));
dlTransformParamsArr.add(new SimpleTransformParams(DLTransformType.PEAK_TRIM, 128, 1));
dlTransformParamsArr.add(new SimpleTransformParams(DLTransformType.NORMALISE_WAV, 0., 1, AudioData.ZSCORE));
genericModelParams.dlTransfromParams = dlTransformParamsArr; genericModelParams.dlTransfromParams = dlTransformParamsArr;
genericModelParams.dlTransfroms = DLTransformsFactory.makeDLTransforms((ArrayList<DLTransfromParams>)genericModelParams.dlTransfromParams); genericModelParams.dlTransfroms = DLTransformsFactory.makeDLTransforms((ArrayList<DLTransfromParams>)genericModelParams.dlTransfromParams);
//create the clicks. //create the clicks.
path = Paths.get(clicksPath); path = Paths.get(clicksPath);
ArrayList<GroupedRawData> clicks = importClicks(path.toAbsolutePath().normalize().toString(), SAMPLE_RATE); ArrayList<PredGroupedRawData> clicks = importClicks(path.toAbsolutePath().normalize().toString(), SAMPLE_RATE);
//prep the model //prep the model
genericModelWorker.prepModel(genericModelParams, null); genericModelWorker.prepModel(genericModelParams, null);
@ -61,20 +65,22 @@ public class ClickDLTest {
ArrayList<GroupedRawData> groupedData = new ArrayList<GroupedRawData>(); ArrayList<GroupedRawData> groupedData = new ArrayList<GroupedRawData>();
int i=0; for (int i=0; i<1; i++) {
float prediction = 0; float prediction = (float) clicks.get(i).getPrediction()[0];
groupedData.add(clicks.get(i)); //TODO for loop groupedData.add(clicks.get(i)); //TODO for loop
System.out.println("Waveform input: " + groupedData.get(i).getRawData().length + " " + groupedData.get(i).getRawData()[0].length); //System.out.println("Waveform input: " + groupedData.get(i).getRawData().length + " " + groupedData.get(i).getRawData()[0].length);
ArrayList<StandardPrediction> genericPrediction = genericModelWorker.runModel(groupedData,SAMPLE_RATE, 0);
float[] output = genericPrediction.get(i).getPrediction();
System.out.println(String.format("Click %d Predicted output: %.2f true output: %.2f passed: %b", clicks.get(i).getUID(),
output[0], prediction, output[0]>prediction*0.9 && output[0]<prediction*1.1));
ArrayList<StandardPrediction> genericPrediction = genericModelWorker.runModel(groupedData,SAMPLE_RATE, 0); }
float[] output = genericPrediction.get(0).getPrediction();
System.out.println(String.format("Click %d Predicted output: %.2f true output: %.2f passed: %b", clicks.get(i).getUID(),
output[0], prediction, output[0]>prediction*0.9 && output[0]<prediction*1.1));
} }
@ -82,7 +88,7 @@ public class ClickDLTest {
/** /**
* Import a bunch of clicks from a .mat file * Import a bunch of clicks from a .mat file
*/ */
public static ArrayList<GroupedRawData> importClicks(String filePath, float sR) { public static ArrayList<PredGroupedRawData> importClicks(String filePath, float sR) {
try { try {
Mat5File mfr = Mat5.readFromFile(filePath); Mat5File mfr = Mat5.readFromFile(filePath);
@ -91,9 +97,9 @@ public class ClickDLTest {
Struct mlArrayRetrived = mfr.getStruct( "clickpreds" ); Struct mlArrayRetrived = mfr.getStruct( "clickpreds" );
int numClicks= mlArrayRetrived.getNumCols(); int numClicks= mlArrayRetrived.getNumCols();
ArrayList<GroupedRawData> clicks = new ArrayList<GroupedRawData>(numClicks); ArrayList<PredGroupedRawData> clicks = new ArrayList<PredGroupedRawData>(numClicks);
GroupedRawData clickData; PredGroupedRawData clickData;
for (int i=0; i<numClicks; i++) { for (int i=0; i<numClicks; i++) {
Matrix clickWav= mlArrayRetrived.get("wave", i); Matrix clickWav= mlArrayRetrived.get("wave", i);
@ -107,10 +113,12 @@ public class ClickDLTest {
Matrix channelMap= mlArrayRetrived.get("channelMap", i); Matrix channelMap= mlArrayRetrived.get("channelMap", i);
Matrix startSample= mlArrayRetrived.get("startSample", i); Matrix startSample= mlArrayRetrived.get("startSample", i);
Matrix sampleDuration= mlArrayRetrived.get("sampleDuration", i); Matrix sampleDuration= mlArrayRetrived.get("sampleDuration", i);
Matrix pred= mlArrayRetrived.get("pred", i);
clickData = new GroupedRawData(clickmillis.getLong(0), channelMap.getInt(0), startSample.getLong(0), sampleDuration.getLong(0), sampleDuration.getInt(0)); clickData = new PredGroupedRawData(clickmillis.getLong(0), channelMap.getInt(0), startSample.getLong(0), sampleDuration.getLong(0), sampleDuration.getInt(0));
clickData.setUID(clickUID.getLong(0)); clickData.setUID(clickUID.getLong(0));
clickData.setRawData(clickwaveform); clickData.setRawData(clickwaveform);
clickData.setPrediction(new double[] {pred.getDouble(0), pred.getDouble(1)});
clicks.add(clickData); clicks.add(clickData);
} }
@ -124,5 +132,25 @@ public class ClickDLTest {
} }
} }
public static class PredGroupedRawData extends GroupedRawData {
private double[] prediction;
public double[] getPrediction() {
return prediction;
}
public void setPrediction(double[] prediction) {
this.prediction = prediction;
}
public PredGroupedRawData(long timeMilliseconds, int channelBitmap, long startSample, long duration, int samplesize) {
super(timeMilliseconds, channelBitmap, startSample, duration, samplesize);
}
}
} }

View File

@ -218,8 +218,7 @@ public class DelphinIDTest {
//the values for the whistle detector. //the values for the whistle detector.
double[][] pamguardWhistleImage = whistleScatter2Image(whistleValues); double[][] pamguardWhistleImage = whistleScatter2Image(whistleValues);
//System.out.println("Size python: " + compressedWhistleImage.length + " x " + compressedWhistleImage[0].length);
System.out.println("Size python: " + compressedWhistleImage.length + " x " + compressedWhistleImage[0].length);
float[][][] input = new float[1][][]; float[][][] input = new float[1][][];
input[0] = JamArr.doubleToFloat(compressedWhistleImage); input[0] = JamArr.doubleToFloat(compressedWhistleImage);
@ -255,7 +254,6 @@ public class DelphinIDTest {
System.out.println("DelphinID mode test end"); System.out.println("DelphinID mode test end");
} }

View File

@ -1,23 +1,10 @@
package wavFiles; package wavFiles;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
//import org.kc7bfi.jflac.util.ByteData;
import org.jflac.util.ByteData;
import clickDetector.WindowsFile; import clickDetector.WindowsFile;
import java.io.ByteArrayInputStream;
import java.util.Arrays;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
public class WavFile { public class WavFile {