001package jmri.jmrit.audio.swing; 002 003import java.awt.FlowLayout; 004import java.awt.event.ActionEvent; 005import javax.swing.BorderFactory; 006import javax.swing.BoxLayout; 007import javax.swing.JButton; 008import javax.swing.JCheckBox; 009import javax.swing.JComboBox; 010import javax.swing.JLabel; 011import javax.swing.JOptionPane; 012import javax.swing.JPanel; 013import javax.swing.JSpinner; 014import javax.swing.JTextField; 015import javax.swing.SpinnerNumberModel; 016import javax.swing.event.ChangeEvent; 017import javax.vecmath.Vector3f; 018import jmri.Audio; 019import jmri.AudioException; 020import jmri.AudioManager; 021import jmri.InstanceManager; 022import jmri.jmrit.audio.AudioSource; 023import jmri.jmrit.beantable.AudioTableAction.AudioTableDataModel; 024 025/** 026 * Defines a GUI for editing AudioSource objects. 027 * 028 * <hr> 029 * This file is part of JMRI. 030 * <p> 031 * JMRI is free software; you can redistribute it and/or modify it under the 032 * terms of version 2 of the GNU General Public License as published by the Free 033 * Software Foundation. See the "COPYING" file for a copy of this license. 034 * <p> 035 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 036 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 037 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 038 * 039 * @author Matthew Harris copyright (c) 2009 040 */ 041public class AudioSourceFrame extends AbstractAudioFrame { 042 043 private static int counter = 1; 044 045 private boolean newSource; 046 047 private final Object lock = new Object(); 048 049 // UI components for Add/Edit Source 050 JLabel assignedBufferLabel = new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("LabelAssignedBuffer"))); 051 JComboBox<String> assignedBuffer = new JComboBox<>(); 052 JLabel loopMinLabel = new JLabel(Bundle.getMessage("LabelLoopMin")); 053 JSpinner loopMin = new JSpinner(); 054 JLabel loopMaxLabel = new JLabel(Bundle.getMessage("LabelLoopMax")); 055 JSpinner loopMax = new JSpinner(); 056 // JLabel loopMinDelayLabel = new JLabel(Bundle.getMessage("LabelLoopMin")); 057 // JSpinner loopMinDelay = new JSpinner(); 058 // JLabel loopMaxDelayLabel = new JLabel(Bundle.getMessage("LabelLoopMax")); 059 // JSpinner loopMaxDelay = new JSpinner(); 060 // JLabel loopDelayUnitsLabel = new JLabel(Bundle.getMessage("UnitMS")); 061 JCheckBox loopInfinite = new JCheckBox(Bundle.getMessage("LabelLoopInfinite")); 062 JPanelVector3f position = new JPanelVector3f("", 063 Bundle.getMessage("UnitUnits")); 064 JCheckBox positionRelative = new JCheckBox(Bundle.getMessage("LabelPositionRelative")); 065 JPanelVector3f velocity = new JPanelVector3f(Bundle.getMessage("LabelVelocity"), 066 Bundle.getMessage("UnitU/S")); 067 JPanelSliderf gain = new JPanelSliderf(Bundle.getMessage("LabelGain"), 0.0f, 1.0f, 5, 4); 068 JPanelSliderf pitch = new JPanelSliderf(Bundle.getMessage("LabelPitch"), 0.5f, 2.0f, 6, 5); 069 JLabel refDistanceLabel = new JLabel(Bundle.getMessage("LabelReferenceDistance")); 070 JSpinner refDistance = new JSpinner(); 071 JLabel maxDistanceLabel = new JLabel(Bundle.getMessage("LabelMaximumDistance")); 072 JSpinner maxDistance = new JSpinner(); 073 JLabel distancesLabel = new JLabel(Bundle.getMessage("UnitUnits")); 074 JLabel rollOffFactorLabel = new JLabel(Bundle.getMessage("LabelRollOffFactor")); 075 JSpinner rollOffFactor = new JSpinner(); 076 JLabel fadeInTimeLabel = new JLabel(Bundle.getMessage("LabelFadeIn")); 077 JSpinner fadeInTime = new JSpinner(); 078 JLabel fadeOutTimeLabel = new JLabel(Bundle.getMessage("LabelFadeOut")); 079 JSpinner fadeOutTime = new JSpinner(); 080 JLabel fadeTimeUnitsLabel = new JLabel(Bundle.getMessage("UnitMS")); 081 082 private final static String PREFIX = "IAS"; 083 084 @SuppressWarnings("OverridableMethodCallInConstructor") 085 public AudioSourceFrame(String title, AudioTableDataModel model) { 086 super(title, model); 087 layoutFrame(); 088 } 089 090 @Override 091 public void layoutFrame() { 092 super.layoutFrame(); 093 JPanel p; 094 095 p = new JPanel(); 096 p.setLayout(new FlowLayout()); 097 p.add(assignedBufferLabel); 098 p.add(assignedBuffer); 099 main.add(p); 100 101 p = new JPanel(); 102 p.setLayout(new FlowLayout()); 103 p.setBorder(BorderFactory.createCompoundBorder( 104 BorderFactory.createTitledBorder(Bundle.getMessage("LabelLoop")), 105 BorderFactory.createEmptyBorder(5, 5, 5, 5))); 106 p.add(loopMinLabel); 107 loopMin.setPreferredSize(new JTextField(8).getPreferredSize()); 108 loopMin.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1)); 109 loopMin.addChangeListener((ChangeEvent e) -> { 110 loopMax.setValue( 111 ((Integer) loopMin.getValue() 112 < (Integer) loopMax.getValue()) 113 ? loopMax.getValue() 114 : loopMin.getValue()); 115 }); 116 p.add(loopMin); 117 p.add(loopMaxLabel); 118 loopMax.setPreferredSize(new JTextField(8).getPreferredSize()); 119 loopMax.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1)); 120 loopMax.addChangeListener((ChangeEvent e) -> { 121 loopMin.setValue( 122 ((Integer) loopMax.getValue() 123 < (Integer) loopMin.getValue()) 124 ? loopMax.getValue() 125 : loopMin.getValue()); 126 }); 127 p.add(loopMax); 128 loopInfinite.addChangeListener((ChangeEvent e) -> { 129 loopMin.setEnabled(!loopInfinite.isSelected()); 130 loopMax.setEnabled(!loopInfinite.isSelected()); 131 }); 132 p.add(loopInfinite); 133 main.add(p); 134 135// p = new JPanel(); p.setLayout(new FlowLayout()); 136// p.setBorder(BorderFactory.createCompoundBorder( 137// BorderFactory.createTitledBorder(Bundle.getMessage("LabelLoopDelay")), 138// BorderFactory.createEmptyBorder(5, 5, 5, 5))); 139// p.add(loopMinDelayLabel); 140// loopMinDelay.setPreferredSize(new JTextField(8).getPreferredSize()); 141// loopMinDelay.setModel(new SpinnerNumberModel(0,0,Integer.MAX_VALUE,1)); 142// loopMinDelay.addChangeListener(new ChangeListener() { 143// public void stateChanged(ChangeEvent e) { 144// loopMaxDelay.setValue( 145// ((Integer)loopMinDelay.getValue() 146// <(Integer)loopMaxDelay.getValue()) 147// ?loopMaxDelay.getValue() 148// :loopMinDelay.getValue()); 149// } 150// }); 151// p.add(loopMinDelay); 152// p.add(loopMaxDelayLabel); 153// loopMaxDelay.setPreferredSize(new JTextField(8).getPreferredSize()); 154// loopMaxDelay.setModel(new SpinnerNumberModel(0,0,Integer.MAX_VALUE,1)); 155// loopMaxDelay.addChangeListener(new ChangeListener() { 156// public void stateChanged(ChangeEvent e) { 157// loopMinDelay.setValue( 158// ((Integer)loopMaxDelay.getValue() 159// <(Integer)loopMinDelay.getValue()) 160// ?loopMaxDelay.getValue() 161// :loopMinDelay.getValue()); 162// } 163// }); 164// p.add(loopMaxDelay); 165// p.add(loopDelayUnitsLabel); 166// main.add(p); 167// 168 p = new JPanel(); 169 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); 170 p.setBorder(BorderFactory.createCompoundBorder( 171 BorderFactory.createTitledBorder(Bundle.getMessage("LabelPosition")), 172 BorderFactory.createEmptyBorder(5, 5, 5, 5))); 173 p.add(position); 174 p.add(positionRelative); 175 main.add(p); 176 177 main.add(velocity); 178 main.add(gain); 179 main.add(pitch); 180 181 p = new JPanel(); 182 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); 183 p.setBorder(BorderFactory.createCompoundBorder( 184 BorderFactory.createTitledBorder(Bundle.getMessage("LabelDistances")), 185 BorderFactory.createEmptyBorder(5, 5, 5, 5))); 186 187 JPanel p2; 188 p2 = new JPanel(); 189 p2.setLayout(new FlowLayout()); 190 p2.add(refDistanceLabel); 191 refDistance.setPreferredSize(new JTextField(8).getPreferredSize()); 192 refDistance.setModel( 193 new SpinnerNumberModel(Float.valueOf(0f), Float.valueOf(0f), Float.valueOf(Audio.MAX_DISTANCE), Float.valueOf(FLT_PRECISION))); 194 refDistance.setEditor(new JSpinner.NumberEditor(refDistance, "0.00")); 195 refDistance.addChangeListener((ChangeEvent e) -> { 196 maxDistance.setValue( 197 ((Float) refDistance.getValue() 198 < (Float) maxDistance.getValue()) 199 ? maxDistance.getValue() 200 : refDistance.getValue()); 201 }); 202 p2.add(refDistance); 203 204 p2.add(maxDistanceLabel); 205 maxDistance.setPreferredSize(new JTextField(8).getPreferredSize()); 206 maxDistance.setModel( 207 new SpinnerNumberModel(Float.valueOf(0f), Float.valueOf(0f), Float.valueOf(Audio.MAX_DISTANCE), Float.valueOf(FLT_PRECISION))); 208 maxDistance.setEditor(new JSpinner.NumberEditor(maxDistance, "0.00")); 209 maxDistance.addChangeListener((ChangeEvent e) -> { 210 refDistance.setValue( 211 ((Float) maxDistance.getValue() 212 < (Float) refDistance.getValue()) 213 ? maxDistance.getValue() 214 : refDistance.getValue()); 215 }); 216 p2.add(maxDistance); 217 p2.add(distancesLabel); 218 p.add(p2); 219 220 p2 = new JPanel(); 221 p2.setLayout(new FlowLayout()); 222 p2.add(rollOffFactorLabel); 223 rollOffFactor.setPreferredSize(new JTextField(8).getPreferredSize()); 224 rollOffFactor.setModel( 225 new SpinnerNumberModel(Float.valueOf(0f), Float.valueOf(0f), Float.valueOf(Audio.MAX_DISTANCE), Float.valueOf(FLT_PRECISION))); 226 rollOffFactor.setEditor(new JSpinner.NumberEditor(rollOffFactor, "0.00")); 227 p2.add(rollOffFactor); 228 p.add(p2); 229 main.add(p); 230 231 p = new JPanel(); 232 p.setLayout(new FlowLayout()); 233 p.setBorder(BorderFactory.createCompoundBorder( 234 BorderFactory.createTitledBorder(Bundle.getMessage("LabelFadeTimes")), 235 BorderFactory.createEmptyBorder(5, 5, 5, 5))); 236 237 p.add(fadeInTimeLabel); 238 fadeInTime.setPreferredSize(new JTextField(8).getPreferredSize()); 239 fadeInTime.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1)); 240 p.add(fadeInTime); 241 242 p.add(fadeOutTimeLabel); 243 fadeOutTime.setPreferredSize(new JTextField(8).getPreferredSize()); 244 fadeOutTime.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1)); 245 p.add(fadeOutTime); 246 247 p.add(fadeTimeUnitsLabel); 248 main.add(p); 249 250 p = new JPanel(); 251 JButton apply; 252 p.add(apply = new JButton(Bundle.getMessage("ButtonApply"))); 253 apply.addActionListener((ActionEvent e) -> { 254 applyPressed(e); 255 }); 256 JButton ok; 257 p.add(ok = new JButton(Bundle.getMessage("ButtonOK"))); 258 ok.addActionListener((ActionEvent e) -> { 259 applyPressed(e); 260 frame.dispose(); 261 }); 262 JButton cancel; 263 p.add(cancel = new JButton(Bundle.getMessage("ButtonCancel"))); 264 cancel.addActionListener((ActionEvent e) -> { 265 frame.dispose(); 266 }); 267 frame.getContentPane().add(p); 268 } 269 270 /** 271 * Populate the Edit Source frame with default values. 272 */ 273 @Override 274 public void resetFrame() { 275 synchronized (lock) { 276 sysName.setText(PREFIX + nextCounter()); 277 } 278 userName.setText(null); 279 assignedBuffer.setSelectedIndex(0); 280 loopInfinite.setSelected(false); 281 loopMin.setValue(AudioSource.LOOP_NONE); 282 loopMax.setValue(AudioSource.LOOP_NONE); 283// loopMinDelay.setValue(0); 284// loopMaxDelay.setValue(0); 285 position.setValue(new Vector3f(0, 0, 0)); 286 positionRelative.setSelected(false); 287 velocity.setValue(new Vector3f(0, 0, 0)); 288 gain.setValue(1.0f); 289 pitch.setValue(1.0f); 290 refDistance.setValue(1.0f); 291 maxDistance.setValue(Audio.MAX_DISTANCE); 292 rollOffFactor.setValue(1.0f); 293 fadeInTime.setValue(1000); 294 fadeOutTime.setValue(1000); 295 296 this.newSource = true; 297 } 298 299 /** 300 * Populate the Edit Source frame with current values. 301 */ 302 @Override 303 public void populateFrame(Audio a) { 304 if (!(a instanceof AudioSource)) { 305 throw new IllegalArgumentException(a.getSystemName() + " is not an AudioSource object"); 306 } 307 super.populateFrame(a); 308 AudioSource s = (AudioSource) a; 309 AudioManager am = InstanceManager.getDefault(jmri.AudioManager.class); 310 String ab = s.getAssignedBufferName(); 311 Audio b = am.getAudio(ab); 312 if (b != null) { 313 assignedBuffer.setSelectedItem(b.getUserName() == null ? ab : b.getUserName()); 314 } 315 loopInfinite.setSelected((s.getMinLoops() == AudioSource.LOOP_CONTINUOUS)); 316 loopMin.setValue(loopInfinite.isSelected() ? 0 : s.getMinLoops()); 317 loopMax.setValue(loopInfinite.isSelected() ? 0 : s.getMaxLoops()); 318 // loopMinDelay.setValue(s.getMinLoopDelay()); 319 // loopMaxDelay.setValue(s.getMaxLoopDelay()); 320 position.setValue(s.getPosition()); 321 positionRelative.setSelected(s.isPositionRelative()); 322 velocity.setValue(s.getVelocity()); 323 gain.setValue(s.getGain()); 324 pitch.setValue(s.getPitch()); 325 refDistance.setValue(s.getReferenceDistance()); 326 maxDistance.setValue(s.getMaximumDistance()); 327 rollOffFactor.setValue(s.getRollOffFactor()); 328 fadeInTime.setValue(s.getFadeIn()); 329 fadeOutTime.setValue(s.getFadeOut()); 330 331 this.newSource = false; 332 } 333 334 public void updateBufferList() { 335 AudioManager am = InstanceManager.getDefault(jmri.AudioManager.class); 336 assignedBuffer.removeAllItems(); 337 assignedBuffer.addItem(Bundle.getMessage("SelectBufferFromList")); 338 am.getNamedBeanSet(Audio.BUFFER).stream().forEach((s) -> { 339 Audio a = am.getAudio(s.getSystemName()); 340 if (a != null) { 341 String u = a.getUserName(); 342 if (u != null) { 343 assignedBuffer.addItem(u); 344 } else { 345 assignedBuffer.addItem(s.getSystemName()); 346 } 347 } else { 348 assignedBuffer.addItem(s.getSystemName()); 349 } 350 }); 351 } 352 353 private void applyPressed(ActionEvent e) { 354 String sName = sysName.getText(); 355 if (entryError(sName, PREFIX, "" + counter)) { 356 return; 357 } 358 String user = userName.getText(); 359 if (user.equals("")) { 360 user = null; 361 } 362 AudioSource s; 363 try { 364 AudioManager am = InstanceManager.getDefault(jmri.AudioManager.class); 365 try { 366 s = (AudioSource) am.provideAudio(sName); 367 } catch (IllegalArgumentException ex) { 368 throw new AudioException("Problem creating source"); 369 } 370 if ((user != null) && (newSource) && (am.getByUserName(user) != null)) { 371 am.deregister(s); 372 synchronized (lock) { 373 prevCounter(); 374 } 375 throw new AudioException("Duplicate user name - please modify"); 376 } 377 s.setUserName(user); 378 if (assignedBuffer.getSelectedIndex() > 0) { 379 String sel = (String) assignedBuffer.getSelectedItem(); 380 if (sel != null) { 381 Audio a = am.getAudio(sel); 382 if (a != null) { 383 s.setAssignedBuffer(a.getSystemName()); 384 } 385 } 386 } 387 s.setMinLoops(loopInfinite.isSelected() ? AudioSource.LOOP_CONTINUOUS : (Integer) loopMin.getValue()); 388 s.setMaxLoops(loopInfinite.isSelected() ? AudioSource.LOOP_CONTINUOUS : (Integer) loopMax.getValue()); 389 // s.setMinLoopDelay((Integer) loopMinDelay.getValue()); 390 // s.setMaxLoopDelay((Integer) loopMaxDelay.getValue()); 391 s.setPosition(position.getValue()); 392 s.setPositionRelative(positionRelative.isSelected()); 393 s.setVelocity(velocity.getValue()); 394 s.setGain(gain.getValue()); 395 s.setPitch(pitch.getValue()); 396 s.setReferenceDistance((Float) refDistance.getValue()); 397 s.setMaximumDistance((Float) maxDistance.getValue()); 398 s.setRollOffFactor((Float) rollOffFactor.getValue()); 399 s.setFadeIn((Integer) fadeInTime.getValue()); 400 s.setFadeOut((Integer) fadeOutTime.getValue()); 401 402 // Notify changes 403 model.fireTableDataChanged(); 404 } catch (AudioException ex) { 405 JOptionPane.showMessageDialog(null, ex.getMessage(), Bundle.getMessage("AudioCreateErrorTitle"), JOptionPane.ERROR_MESSAGE); 406 } 407 } 408 409 private static int nextCounter() { 410 return counter++; 411 } 412 413 private static void prevCounter() { 414 counter--; 415 } 416 417 //private static final Logger log = LoggerFactory.getLogger(AudioSourceFrame.class); 418 419}