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 @SuppressWarnings("UnnecessaryBoxing") 092 public void layoutFrame() { 093 super.layoutFrame(); 094 JPanel p; 095 096 p = new JPanel(); 097 p.setLayout(new FlowLayout()); 098 p.add(assignedBufferLabel); 099 p.add(assignedBuffer); 100 main.add(p); 101 102 p = new JPanel(); 103 p.setLayout(new FlowLayout()); 104 p.setBorder(BorderFactory.createCompoundBorder( 105 BorderFactory.createTitledBorder(Bundle.getMessage("LabelLoop")), 106 BorderFactory.createEmptyBorder(5, 5, 5, 5))); 107 p.add(loopMinLabel); 108 loopMin.setPreferredSize(new JTextField(8).getPreferredSize()); 109 loopMin.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1)); 110 loopMin.addChangeListener((ChangeEvent e) -> { 111 loopMax.setValue( 112 ((Integer) loopMin.getValue() 113 < (Integer) loopMax.getValue()) 114 ? loopMax.getValue() 115 : loopMin.getValue()); 116 }); 117 p.add(loopMin); 118 p.add(loopMaxLabel); 119 loopMax.setPreferredSize(new JTextField(8).getPreferredSize()); 120 loopMax.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1)); 121 loopMax.addChangeListener((ChangeEvent e) -> { 122 loopMin.setValue( 123 ((Integer) loopMax.getValue() 124 < (Integer) loopMin.getValue()) 125 ? loopMax.getValue() 126 : loopMin.getValue()); 127 }); 128 p.add(loopMax); 129 loopInfinite.addChangeListener((ChangeEvent e) -> { 130 loopMin.setEnabled(!loopInfinite.isSelected()); 131 loopMax.setEnabled(!loopInfinite.isSelected()); 132 }); 133 p.add(loopInfinite); 134 main.add(p); 135 136// p = new JPanel(); p.setLayout(new FlowLayout()); 137// p.setBorder(BorderFactory.createCompoundBorder( 138// BorderFactory.createTitledBorder(Bundle.getMessage("LabelLoopDelay")), 139// BorderFactory.createEmptyBorder(5, 5, 5, 5))); 140// p.add(loopMinDelayLabel); 141// loopMinDelay.setPreferredSize(new JTextField(8).getPreferredSize()); 142// loopMinDelay.setModel(new SpinnerNumberModel(0,0,Integer.MAX_VALUE,1)); 143// loopMinDelay.addChangeListener(new ChangeListener() { 144// public void stateChanged(ChangeEvent e) { 145// loopMaxDelay.setValue( 146// ((Integer)loopMinDelay.getValue() 147// <(Integer)loopMaxDelay.getValue()) 148// ?loopMaxDelay.getValue() 149// :loopMinDelay.getValue()); 150// } 151// }); 152// p.add(loopMinDelay); 153// p.add(loopMaxDelayLabel); 154// loopMaxDelay.setPreferredSize(new JTextField(8).getPreferredSize()); 155// loopMaxDelay.setModel(new SpinnerNumberModel(0,0,Integer.MAX_VALUE,1)); 156// loopMaxDelay.addChangeListener(new ChangeListener() { 157// public void stateChanged(ChangeEvent e) { 158// loopMinDelay.setValue( 159// ((Integer)loopMaxDelay.getValue() 160// <(Integer)loopMinDelay.getValue()) 161// ?loopMaxDelay.getValue() 162// :loopMinDelay.getValue()); 163// } 164// }); 165// p.add(loopMaxDelay); 166// p.add(loopDelayUnitsLabel); 167// main.add(p); 168// 169 p = new JPanel(); 170 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); 171 p.setBorder(BorderFactory.createCompoundBorder( 172 BorderFactory.createTitledBorder(Bundle.getMessage("LabelPosition")), 173 BorderFactory.createEmptyBorder(5, 5, 5, 5))); 174 p.add(position); 175 p.add(positionRelative); 176 main.add(p); 177 178 main.add(velocity); 179 main.add(gain); 180 main.add(pitch); 181 182 p = new JPanel(); 183 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); 184 p.setBorder(BorderFactory.createCompoundBorder( 185 BorderFactory.createTitledBorder(Bundle.getMessage("LabelDistances")), 186 BorderFactory.createEmptyBorder(5, 5, 5, 5))); 187 188 JPanel p2; 189 p2 = new JPanel(); 190 p2.setLayout(new FlowLayout()); 191 p2.add(refDistanceLabel); 192 refDistance.setPreferredSize(new JTextField(8).getPreferredSize()); 193 refDistance.setModel( 194 new SpinnerNumberModel(Float.valueOf(0f), Float.valueOf(0f), Float.valueOf(Audio.MAX_DISTANCE), Float.valueOf(FLT_PRECISION))); 195 refDistance.setEditor(new JSpinner.NumberEditor(refDistance, "0.00")); 196 refDistance.addChangeListener((ChangeEvent e) -> { 197 maxDistance.setValue( 198 ((Float) refDistance.getValue() 199 < (Float) maxDistance.getValue()) 200 ? maxDistance.getValue() 201 : refDistance.getValue()); 202 }); 203 p2.add(refDistance); 204 205 p2.add(maxDistanceLabel); 206 maxDistance.setPreferredSize(new JTextField(8).getPreferredSize()); 207 maxDistance.setModel( 208 new SpinnerNumberModel(Float.valueOf(0f), Float.valueOf(0f), Float.valueOf(Audio.MAX_DISTANCE), Float.valueOf(FLT_PRECISION))); 209 maxDistance.setEditor(new JSpinner.NumberEditor(maxDistance, "0.00")); 210 maxDistance.addChangeListener((ChangeEvent e) -> { 211 refDistance.setValue( 212 ((Float) maxDistance.getValue() 213 < (Float) refDistance.getValue()) 214 ? maxDistance.getValue() 215 : refDistance.getValue()); 216 }); 217 p2.add(maxDistance); 218 p2.add(distancesLabel); 219 p.add(p2); 220 221 p2 = new JPanel(); 222 p2.setLayout(new FlowLayout()); 223 p2.add(rollOffFactorLabel); 224 rollOffFactor.setPreferredSize(new JTextField(8).getPreferredSize()); 225 rollOffFactor.setModel( 226 new SpinnerNumberModel(Float.valueOf(0f), Float.valueOf(0f), Float.valueOf(Audio.MAX_DISTANCE), Float.valueOf(FLT_PRECISION))); 227 rollOffFactor.setEditor(new JSpinner.NumberEditor(rollOffFactor, "0.00")); 228 p2.add(rollOffFactor); 229 p.add(p2); 230 main.add(p); 231 232 p = new JPanel(); 233 p.setLayout(new FlowLayout()); 234 p.setBorder(BorderFactory.createCompoundBorder( 235 BorderFactory.createTitledBorder(Bundle.getMessage("LabelFadeTimes")), 236 BorderFactory.createEmptyBorder(5, 5, 5, 5))); 237 238 p.add(fadeInTimeLabel); 239 fadeInTime.setPreferredSize(new JTextField(8).getPreferredSize()); 240 fadeInTime.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1)); 241 p.add(fadeInTime); 242 243 p.add(fadeOutTimeLabel); 244 fadeOutTime.setPreferredSize(new JTextField(8).getPreferredSize()); 245 fadeOutTime.setModel(new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1)); 246 p.add(fadeOutTime); 247 248 p.add(fadeTimeUnitsLabel); 249 main.add(p); 250 251 p = new JPanel(); 252 JButton apply; 253 p.add(apply = new JButton(Bundle.getMessage("ButtonApply"))); 254 apply.addActionListener((ActionEvent e) -> { 255 applyPressed(e); 256 }); 257 JButton ok; 258 p.add(ok = new JButton(Bundle.getMessage("ButtonOK"))); 259 ok.addActionListener((ActionEvent e) -> { 260 applyPressed(e); 261 frame.dispose(); 262 }); 263 JButton cancel; 264 p.add(cancel = new JButton(Bundle.getMessage("ButtonCancel"))); 265 cancel.addActionListener((ActionEvent e) -> { 266 frame.dispose(); 267 }); 268 frame.getContentPane().add(p); 269 } 270 271 /** 272 * Populate the Edit Source frame with default values. 273 */ 274 @Override 275 public void resetFrame() { 276 synchronized (lock) { 277 sysName.setText(PREFIX + nextCounter()); 278 } 279 userName.setText(null); 280 assignedBuffer.setSelectedIndex(0); 281 loopInfinite.setSelected(false); 282 loopMin.setValue(AudioSource.LOOP_NONE); 283 loopMax.setValue(AudioSource.LOOP_NONE); 284// loopMinDelay.setValue(0); 285// loopMaxDelay.setValue(0); 286 position.setValue(new Vector3f(0, 0, 0)); 287 positionRelative.setSelected(false); 288 velocity.setValue(new Vector3f(0, 0, 0)); 289 gain.setValue(1.0f); 290 pitch.setValue(1.0f); 291 refDistance.setValue(1.0f); 292 maxDistance.setValue(Audio.MAX_DISTANCE); 293 rollOffFactor.setValue(1.0f); 294 fadeInTime.setValue(1000); 295 fadeOutTime.setValue(1000); 296 297 this.newSource = true; 298 } 299 300 /** 301 * Populate the Edit Source frame with current values. 302 */ 303 @Override 304 public void populateFrame(Audio a) { 305 if (!(a instanceof AudioSource)) { 306 throw new IllegalArgumentException(a.getSystemName() + " is not an AudioSource object"); 307 } 308 super.populateFrame(a); 309 AudioSource s = (AudioSource) a; 310 AudioManager am = InstanceManager.getDefault(jmri.AudioManager.class); 311 String ab = s.getAssignedBufferName(); 312 Audio b = am.getAudio(ab); 313 if (b != null) { 314 assignedBuffer.setSelectedItem(b.getUserName() == null ? ab : b.getUserName()); 315 } 316 loopInfinite.setSelected((s.getMinLoops() == AudioSource.LOOP_CONTINUOUS)); 317 loopMin.setValue(loopInfinite.isSelected() ? 0 : s.getMinLoops()); 318 loopMax.setValue(loopInfinite.isSelected() ? 0 : s.getMaxLoops()); 319 // loopMinDelay.setValue(s.getMinLoopDelay()); 320 // loopMaxDelay.setValue(s.getMaxLoopDelay()); 321 position.setValue(s.getPosition()); 322 positionRelative.setSelected(s.isPositionRelative()); 323 velocity.setValue(s.getVelocity()); 324 gain.setValue(s.getGain()); 325 pitch.setValue(s.getPitch()); 326 refDistance.setValue(s.getReferenceDistance()); 327 maxDistance.setValue(s.getMaximumDistance()); 328 rollOffFactor.setValue(s.getRollOffFactor()); 329 fadeInTime.setValue(s.getFadeIn()); 330 fadeOutTime.setValue(s.getFadeOut()); 331 332 this.newSource = false; 333 } 334 335 public void updateBufferList() { 336 AudioManager am = InstanceManager.getDefault(jmri.AudioManager.class); 337 assignedBuffer.removeAllItems(); 338 assignedBuffer.addItem(Bundle.getMessage("SelectBufferFromList")); 339 am.getNamedBeanSet(Audio.BUFFER).stream().forEach((s) -> { 340 Audio a = am.getAudio(s.getSystemName()); 341 if (a != null) { 342 String u = a.getUserName(); 343 if (u != null) { 344 assignedBuffer.addItem(u); 345 } else { 346 assignedBuffer.addItem(s.getSystemName()); 347 } 348 } else { 349 assignedBuffer.addItem(s.getSystemName()); 350 } 351 }); 352 } 353 354 private void applyPressed(ActionEvent e) { 355 String sName = sysName.getText(); 356 if (entryError(sName, PREFIX, "" + counter)) { 357 return; 358 } 359 String user = userName.getText(); 360 if (user.equals("")) { 361 user = null; 362 } 363 AudioSource s; 364 try { 365 AudioManager am = InstanceManager.getDefault(jmri.AudioManager.class); 366 try { 367 s = (AudioSource) am.provideAudio(sName); 368 } catch (IllegalArgumentException ex) { 369 throw new AudioException("Problem creating source"); 370 } 371 if ((user != null) && (newSource) && (am.getByUserName(user) != null)) { 372 am.deregister(s); 373 synchronized (lock) { 374 prevCounter(); 375 } 376 throw new AudioException("Duplicate user name - please modify"); 377 } 378 s.setUserName(user); 379 if (assignedBuffer.getSelectedIndex() > 0) { 380 String sel = (String) assignedBuffer.getSelectedItem(); 381 if (sel != null) { 382 Audio a = am.getAudio(sel); 383 if (a != null) { 384 s.setAssignedBuffer(a.getSystemName()); 385 } 386 } 387 } 388 s.setMinLoops(loopInfinite.isSelected() ? AudioSource.LOOP_CONTINUOUS : (Integer) loopMin.getValue()); 389 s.setMaxLoops(loopInfinite.isSelected() ? AudioSource.LOOP_CONTINUOUS : (Integer) loopMax.getValue()); 390 // s.setMinLoopDelay((Integer) loopMinDelay.getValue()); 391 // s.setMaxLoopDelay((Integer) loopMaxDelay.getValue()); 392 s.setPosition(position.getValue()); 393 s.setPositionRelative(positionRelative.isSelected()); 394 s.setVelocity(velocity.getValue()); 395 s.setGain(gain.getValue()); 396 s.setPitch(pitch.getValue()); 397 s.setReferenceDistance((Float) refDistance.getValue()); 398 s.setMaximumDistance((Float) maxDistance.getValue()); 399 s.setRollOffFactor((Float) rollOffFactor.getValue()); 400 s.setFadeIn((Integer) fadeInTime.getValue()); 401 s.setFadeOut((Integer) fadeOutTime.getValue()); 402 403 // Notify changes 404 model.fireTableDataChanged(); 405 } catch (AudioException ex) { 406 JOptionPane.showMessageDialog(null, ex.getMessage(), Bundle.getMessage("AudioCreateErrorTitle"), JOptionPane.ERROR_MESSAGE); 407 } 408 } 409 410 private static int nextCounter() { 411 return counter++; 412 } 413 414 private static void prevCounter() { 415 counter--; 416 } 417 418 //private static final Logger log = LoggerFactory.getLogger(AudioSourceFrame.class); 419 420}