annotate src/uk/ac/qmul/eecs/depic/daw/gui/AudioTrack.java @ 4:473da40f3d39 tip

added html formatting to Daw/package-info.java
author Fiore Martin <f.martin@qmul.ac.uk>
date Thu, 25 Feb 2016 17:50:09 +0000
parents 629262395647
children
rev   line source
f@0 1 /*
f@0 2 Cross-Modal DAW Prototype - Prototype of a simple Cross-Modal Digital Audio Workstation.
f@0 3
f@0 4 Copyright (C) 2015 Queen Mary University of London (http://depic.eecs.qmul.ac.uk/)
f@0 5
f@0 6 This program is free software: you can redistribute it and/or modify
f@0 7 it under the terms of the GNU General Public License as published by
f@0 8 the Free Software Foundation, either version 3 of the License, or
f@0 9 (at your option) any later version.
f@0 10
f@0 11 This program is distributed in the hope that it will be useful,
f@0 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
f@0 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
f@0 14 GNU General Public License for more details.
f@0 15
f@0 16 You should have received a copy of the GNU General Public License
f@0 17 along with this program. If not, see <http://www.gnu.org/licenses/>.
f@0 18 */
f@0 19 package uk.ac.qmul.eecs.depic.daw.gui;
f@0 20
f@0 21 import java.awt.Color;
f@0 22 import java.awt.Dimension;
f@0 23 import java.awt.Graphics;
f@0 24 import java.awt.Graphics2D;
f@0 25 import java.awt.Point;
f@0 26 import java.awt.Rectangle;
f@0 27 import java.awt.event.ActionEvent;
f@0 28 import java.awt.event.ActionListener;
f@0 29 import java.awt.geom.Line2D;
f@0 30 import java.awt.geom.Point2D;
f@0 31
f@0 32 import javax.swing.JPanel;
f@0 33 import javax.swing.Timer;
f@0 34 import javax.swing.event.ChangeEvent;
f@0 35 import javax.swing.event.ChangeListener;
f@0 36
f@0 37 import uk.ac.qmul.eecs.depic.daw.Automation;
f@0 38 import uk.ac.qmul.eecs.depic.daw.Chunk;
f@0 39 import uk.ac.qmul.eecs.depic.daw.Daw;
f@0 40 import uk.ac.qmul.eecs.depic.daw.Selection;
f@0 41 import uk.ac.qmul.eecs.depic.daw.SoundType;
f@0 42 import uk.ac.qmul.eecs.depic.daw.SoundWave;
f@0 43 import uk.ac.qmul.eecs.depic.daw.SoundWaveEvent;
f@0 44 import uk.ac.qmul.eecs.depic.daw.SoundWaveListener;
f@0 45 import uk.ac.qmul.eecs.depic.daw.Wave;
f@0 46 import uk.ac.qmul.eecs.depic.daw.haptics.HapticViewPort;
f@0 47 import uk.ac.qmul.eecs.depic.patterns.Sequence;
f@0 48 import uk.ac.qmul.eecs.depic.patterns.SequenceMapping;
f@0 49
f@0 50 /**
f@1 51 * An audio track widget.
f@0 52 *
f@0 53 *
f@0 54 *
f@0 55 * This class has the following bound properties :
f@0 56 * <ul>
f@0 57 * <li><b>scaleFactor:</b> the scale factor of each pixel of the sound wave representation. The bigger the
f@0 58 * scale factor, the lower the resolution. a scale factor ranges from 1, highest resolution supported by
f@0 59 * the {@code SoundWave} instance, to the max scale factor supported by the backing {@code SoundWave} model - {@code int}</li>
f@0 60 * <li><b>cursorPos:</b> the position of the cursor - {@code int} </li>
f@0 61 * <li><b>mouseDragSelection:</b> the range of the selection on this track as the user drags the mouse - {@code SelectionRange} </li>
f@0 62 * <li><b><preferredSize:</b> the preferred size - {@code Dimension}
f@0 63 * </ul>
f@0 64 *
f@0 65 *
f@0 66 *
f@0 67 */
f@0 68 public class AudioTrack extends JPanel implements SoundWaveListener {
f@0 69 private static final long serialVersionUID = 1L;
f@0 70
f@0 71 public static final int MAX_TRACK_HEIGHT = 130;
f@0 72 public static final int MAX_TRACK_WIDTH = Integer.MAX_VALUE;
f@0 73
f@0 74 public static final Color WAVE_COLOR = new Color(7,47,140);
f@0 75 public static final Color CURSOR_COLOR = new Color(44,47,56);
f@0 76 public static final Color SELECTION_COLOR = new Color(218,218,240);
f@0 77 public static final Color OVERLAY_BG_COLOR = new Color(222,222,235);
f@0 78 public static final Color VIEW_PORT_COLOR = Color.GREEN;
f@0 79
f@0 80 /* these fields are used by friend classes *
f@0 81 * they're final to protect them from being changed */
f@0 82 final AudioTrackInput trackInteraction;
f@0 83 final AudioTrackSonification trackSonification;
f@0 84
f@0 85 private SequenceGraph automationGraph;
f@0 86 private SequenceGraph peakMeterGraph;
f@0 87 private final CursorUpdaterOnPlay clipInteraction;
f@0 88 protected SoundWave soundWave;
f@0 89
f@0 90 private HapticViewPort hapticViewPort;
f@0 91
f@0 92 private Selection currentSelection;
f@0 93 private int scaleFactor; // bound property
f@0 94 private int cursorPos; // bound property
f@0 95 private float secondsPerPixel;
f@0 96 private boolean showHapticViewPort;
f@0 97 boolean showAutomationSound;
f@0 98 boolean showPeakLevelSound;
f@0 99 private boolean showDbWave;
f@0 100
f@0 101 public AudioTrack(SoundWave soundWave){
f@0 102 if(soundWave == null)
f@0 103 throw new IllegalArgumentException("soundWave cannot be null");
f@0 104
f@0 105 this.soundWave = soundWave;
f@0 106 soundWave.addSoundWaveListener(this);
f@0 107
f@0 108
f@0 109 setBackground(Color.WHITE);
f@0 110
f@0 111 scaleFactor = 1;
f@0 112 currentSelection = new Selection(0,scaleFactor);
f@0 113
f@0 114 /* set up sequence graphs */
f@0 115 ChangeListener sequenceGraphListener = new ChangeListener(){
f@0 116 @Override
f@0 117 public void stateChanged(ChangeEvent e) {
f@0 118 repaint();
f@0 119 }
f@0 120 };
f@0 121
f@0 122 automationGraph = new SequenceGraph(Color.WHITE, getSize());
f@0 123 automationGraph.addChangeListener(sequenceGraphListener);
f@0 124 peakMeterGraph = new SequenceGraph(Color.GRAY, getSize());
f@0 125 peakMeterGraph.addChangeListener(sequenceGraphListener);
f@0 126
f@0 127 clipInteraction = new CursorUpdaterOnPlay();
f@0 128 trackInteraction = new AudioTrackInput(this);
f@0 129 trackSonification = new AudioTrackSonification(this);
f@0 130 hapticViewPort = new HapticViewPort(1);
f@0 131
f@0 132 setMaximumSize(new Dimension(MAX_TRACK_WIDTH,MAX_TRACK_HEIGHT));
f@0 133 //setMinimumSize(new Dimension(100,TRACK_HEIGHT));
f@0 134 setPreferredSize(new Dimension(0,MAX_TRACK_HEIGHT));
f@0 135
f@0 136 this.setFocusable(true);
f@0 137
f@0 138 addPropertyChangeListener(trackSonification);
f@0 139 addMouseListener(trackInteraction);
f@0 140 addMouseMotionListener(trackInteraction);
f@0 141 addKeyListener(trackInteraction);
f@0 142 }
f@0 143
f@0 144 @Override
f@0 145 public void update(SoundWaveEvent evt) { // FIXME fare file closed
f@0 146 String evtType = evt.getType();
f@0 147 if(SoundWaveEvent.OPEN.equals(evtType)) {
f@0 148 SoundWave wave = evt.getSource();
f@0 149 hapticViewPort.setTrackSize(wave.getChunkNum()); // FIXME check
f@0 150 _setScaleFactor(wave.getScaleFactor());
f@0 151 setCursorPos(0);
f@0 152 } else if(SoundWaveEvent.SCALE_FACTOR_CHANGED.equals(evtType)){
f@0 153 _setScaleFactor((Integer)evt.getArgs());
f@0 154 }else if (SoundWaveEvent.SELECTION_CHANGED.equals(evtType)){
f@0 155 Selection oldSelection = currentSelection;
f@0 156 currentSelection = (Selection)evt.getArgs();
f@0 157 /* update the mouse interaction object accordingly */
f@0 158 trackInteraction.setMouseSelection(currentSelection.getStart(), currentSelection.getEnd());
f@0 159 firePropertyChange("mouseDragSelection",oldSelection,currentSelection);
f@0 160 repaint();
f@0 161
f@0 162 }else if(SoundWaveEvent.POSITION_CHANGED.equals(evtType)){
f@0 163 /* update the position according to the Selection object returned by evt.getArgs() *
f@0 164 * the selection is open. The Selection's scale factor is also taken into account *
f@0 165 * when calculating the new position. In particular the ratio between the *
f@0 166 * selction's scale factor and this object current scale factor */
f@0 167 setCursorPos((Integer)evt.getArgs());
f@0 168
f@0 169
f@0 170 }else if(SoundWaveEvent.START.equals(evtType) ||
f@0 171 SoundWaveEvent.STOP.equals(evtType) ||
f@0 172 SoundWaveEvent.PAUSE.equals(evtType)){
f@0 173 clipInteraction.update(evt);
f@0 174 }else if (SoundWaveEvent.AUTOMATION_CHANGED.equals(evtType)){
f@0 175 Automation automation = (Automation)evt.getArgs();
f@0 176
f@0 177 /* if it's an automation different from NONE, paint the overlay: make the bg darker */
f@0 178 if(Automation.NONE_AUTOMATION.equals(automation)){
f@0 179 setBackground(Color.WHITE);
f@0 180 automationGraph.removeChangeListener(trackSonification);
f@0 181 }else{
f@0 182 setBackground(OVERLAY_BG_COLOR);
f@0 183 }
f@0 184
f@0 185 /* resize automation graph, if currently showing any */
f@0 186 automationGraph.setMillisecPerPixel(evt.getSource().getMillisecPerChunk());
f@0 187 automationGraph.setColor(automation.getColor());
f@0 188 automationGraph.setSize(getSize());
f@0 189 automationGraph.setSequence(automation);
f@0 190 automationGraph.addChangeListener(trackSonification);
f@0 191
f@0 192 }else if(SoundWaveEvent.CLOSE.equals(evtType) ||
f@0 193 SoundWaveEvent.CUT.equals(evtType) ||
f@0 194 SoundWaveEvent.PASTE.equals(evtType) ||
f@0 195 SoundWaveEvent.INSERT.equals(evtType)){
f@0 196 hapticViewPort.setTrackSize(evt.getSource().getChunkNum());
f@0 197 repaint();
f@0 198 }else if(SoundWaveEvent.PEAK_METER.equals(evtType)){
f@0 199
f@0 200 peakMeterGraph.setMillisecPerPixel(evt.getSource().getMillisecPerChunk());
f@0 201 peakMeterGraph.setSize(getSize());
f@0 202 /* listens to the changes, so it will repaint after setSequence */
f@0 203 peakMeterGraph.setSequence((Sequence)evt.getArgs());
f@0 204
f@0 205 }
f@0 206 }
f@0 207
f@0 208 @Override
f@0 209 public void paintComponent(Graphics g){
f@0 210 super.paintComponent(g);
f@0 211 Graphics2D g2 = (Graphics2D)g;
f@0 212 Color oldColor = g2.getColor();
f@0 213
f@0 214 /* get height and width. needed for painting */
f@0 215 int height = getHeight();
f@0 216 int width = getWidth();
f@0 217
f@0 218 /* paint the selection grey background*/
f@0 219 Selection mouseSelection = trackInteraction.getMouseSelection();
f@0 220 if(!mouseSelection.isOpen()){
f@0 221 g2.setColor(SELECTION_COLOR);
f@0 222 g2.fillRect(mouseSelection.getStart(), 0, Math.abs(mouseSelection.getStart()-mouseSelection.getEnd()), height);
f@0 223 }
f@0 224
f@0 225 /* paint the central line */
f@0 226 g2.setColor(CURSOR_COLOR);
f@0 227 g2.draw(new Line2D.Float(0f, height/2,width,height/2));
f@0 228
f@0 229 /* paint the sound wave, if any */
f@0 230 if(soundWave != null ){
f@0 231 Wave wave = showDbWave ? soundWave.getDbWave() : soundWave;
f@0 232 g2.setColor(WAVE_COLOR);
f@0 233 int horizontalPixel = 0;
f@0 234 for(int i=0; i<wave.getChunkNum(); i++){
f@0 235 Chunk chunk = wave.getChunkAt(i);
f@0 236 g2.draw(new Line2D.Float(
f@0 237 horizontalPixel,
f@0 238 normToHeightConvert(chunk.getNormStart()),
f@0 239 horizontalPixel,
f@0 240 normToHeightConvert(chunk.getNormEnd())));
f@0 241 horizontalPixel++;
f@0 242 }
f@0 243 }
f@0 244
f@0 245 paintHapticViewPort(g2, width, height);
f@0 246 /* paint the sequence graphs, if any */
f@0 247 automationGraph.draw(g);
f@0 248 peakMeterGraph.draw(g);
f@0 249
f@0 250
f@0 251 g2.setColor(CURSOR_COLOR);
f@0 252 /* draw cursor */
f@0 253 g2.drawLine(cursorPos, 0, cursorPos, height);
f@0 254
f@0 255 if(mouseSelection.isOpen()){
f@0 256 /* paints one line as the selection has no length */
f@0 257 g2.drawLine(mouseSelection.getStart(), 0, mouseSelection.getStart(), height);
f@0 258 }else{
f@0 259 /* paint the selection left and right boundaries */
f@0 260 /* draw the boundaries of the selection with CURSOR_COLOR */
f@0 261 g2.drawLine(mouseSelection.getStart(), 0, mouseSelection.getStart(), height);
f@0 262 g2.drawLine(mouseSelection.getEnd(), 0, mouseSelection.getEnd(), height);
f@0 263 }
f@0 264 g2.setColor(oldColor);
f@0 265 }
f@0 266
f@0 267 protected void paintHapticViewPort(Graphics g2, int width, int height){
f@0 268 if(!showHapticViewPort)
f@0 269 return;
f@0 270
f@0 271 Color oldColor = g2.getColor();
f@0 272 g2.setColor(VIEW_PORT_COLOR);
f@0 273
f@0 274 int leftBound = hapticViewPort.getPosition(0.0f);
f@0 275 if(leftBound == 0) // make it visible if it's at 0
f@0 276 leftBound = 1;
f@0 277
f@0 278 g2.drawLine(leftBound-1, height/4, leftBound-1, height*3/4);
f@0 279 g2.drawLine(leftBound, 0, leftBound, height); // little bar on the left to give the idea of direction
f@0 280 int rightBound = hapticViewPort.getPosition(1.0f);
f@0 281 g2.drawLine(rightBound, 0, rightBound, height);// little bar on the right to give the idea of direction
f@0 282 g2.drawLine(rightBound+1, height/4, rightBound+1, height*3/4);
f@0 283 g2.setColor(oldColor);
f@0 284 }
f@0 285
f@0 286 public SoundWave getSoundWave(){
f@0 287 return soundWave;
f@0 288 }
f@0 289
f@0 290 public int getScaleFactor() {
f@0 291 return scaleFactor;
f@0 292 }
f@0 293
f@0 294 public void setScaleFactor(int factor) {
f@0 295 /* sets the scale factor in the SoundWave to scaleFactor *
f@0 296 * _setScaleFactor will be called right after as a SoundWaveEvent *
f@0 297 * will be triggered by SoundWave. see update() */
f@0 298 soundWave.setScaleFactor(factor);
f@0 299 }
f@0 300
f@0 301 /* implements scaleFactor body. It's called by update() after the model's scale factor
f@0 302 * gets changed */
f@0 303 private void _setScaleFactor(int factor) {
f@0 304 if(factor < 1 || factor > getSoundWave().getMaxScaleFactor() ){
f@0 305 Daw.getSoundEngineFactory().getSharedSonification().play(SoundType.ERROR);
f@0 306 return;
f@0 307 }
f@0 308
f@0 309 int oldScaleFactor = scaleFactor;
f@0 310 scaleFactor = factor;
f@0 311
f@0 312 secondsPerPixel = soundWave.getMillisecPerChunk()/1000;
f@0 313
f@0 314 /* update haptic view port */
f@0 315 hapticViewPort.setScaleFactor(scaleFactor);
f@0 316
f@0 317 /* resize the selection after zooming in/out */
f@0 318 Selection oldSelection = currentSelection;
f@0 319 int start = (int) (oldSelection.getStart() * Math.pow(2,oldScaleFactor - factor));
f@0 320 if(oldSelection.isOpen())
f@0 321 currentSelection = new Selection(start,factor);
f@0 322 else{
f@0 323 int end = (int) (oldSelection.getEnd() * Math.pow(2,oldScaleFactor - factor));
f@0 324 currentSelection = new Selection(start,end,factor);
f@0 325 }
f@0 326
f@0 327 /* if the selection is open, it will be painted as a one-pixel selection */
f@0 328 trackInteraction.setMouseSelection(currentSelection.getStart(), currentSelection.getEnd());
f@0 329
f@0 330 /* make listeners aware the mouse selection has changed */
f@0 331 firePropertyChange("mouseDragSelection",oldSelection,currentSelection);
f@0 332
f@0 333 setPreferredSize(new Dimension(soundWave.getChunkNum()+30,MAX_TRACK_HEIGHT));
f@0 334 revalidate();
f@0 335
f@0 336 setCursorPos(soundWave.getCurrentChunkPosition());
f@0 337 /* update the sequences */
f@0 338 automationGraph.setSize(getSize());
f@0 339 automationGraph.setMillisecPerPixel(AudioTrack.this.soundWave.getMillisecPerChunk());
f@0 340 automationGraph.updateSequence();
f@0 341
f@0 342 peakMeterGraph.setSize(getSize());
f@0 343 peakMeterGraph.setMillisecPerPixel(AudioTrack.this.soundWave.getMillisecPerChunk());
f@0 344 peakMeterGraph.updateSequence();
f@0 345
f@0 346 repaint();
f@0 347 firePropertyChange("scaleFactor", oldScaleFactor, scaleFactor);
f@0 348 }
f@0 349
f@0 350 public Selection getSelection(){
f@0 351 return currentSelection;
f@0 352 }
f@0 353
f@0 354 /**
f@0 355 * Doesn't change the cursor position of the underlying soundwave
f@0 356 * @param position
f@0 357 */
f@0 358 public void setCursorPos(int position) {
f@0 359 int oldCursorPos = cursorPos;
f@0 360 cursorPos = position;
f@0 361
f@0 362 repaint();
f@0 363 scrollRectToVisible(new Rectangle(new Point(position,0)));
f@0 364 firePropertyChange("cursorPos", oldCursorPos, position);
f@0 365 }
f@0 366
f@0 367 public int getCursorPos(){
f@0 368 return cursorPos;
f@0 369 }
f@0 370
f@0 371 public float getSecondsPerPixel(){
f@0 372 return secondsPerPixel;
f@0 373 }
f@0 374
f@0 375 public SequenceGraph getAutomationGraph(){
f@0 376 return automationGraph;
f@0 377 }
f@0 378
f@0 379 public SequenceGraph getPeakLevelGraph(){
f@0 380 return peakMeterGraph;
f@0 381 }
f@0 382
f@0 383 /**
f@0 384 * Makes it available to {@code Rule} class to notify listeners after changing
f@0 385 * the mouseDragSelection.
f@0 386 *
f@0 387 * @param property the programmatic name of the property that was changed
f@0 388 * @param oldValue the old value of the property
f@0 389 * @param newValue the new value of the property
f@0 390 */
f@0 391 @Override
f@0 392 protected void firePropertyChange(String property, Object oldValue, Object newValue){
f@0 393 super.firePropertyChange(property, oldValue, newValue);
f@0 394 }
f@0 395
f@0 396 public HapticViewPort getHapticViewPort(){
f@0 397 return hapticViewPort;
f@0 398 }
f@0 399
f@0 400 public void showHapticViewPort(boolean show){
f@0 401 showHapticViewPort = show;
f@0 402 repaint();
f@0 403 }
f@0 404
f@0 405 public void showAutomationSound(boolean show){
f@0 406 showAutomationSound = show;
f@0 407
f@0 408 SequenceMapping sonificationSeqMapping = Daw.getSoundEngineFactory().getSharedSonification()
f@0 409 .getSequenceMapping(SoundType.AUTOMATION);
f@0 410 if(show){
f@0 411 sonificationSeqMapping.renderCurveAt(
f@0 412 soundWave.getSequence(),
f@0 413 soundWave.getMillisecPerChunk() * cursorPos,
f@0 414 SequenceMapping.DURATION_INF);
f@0 415 }else{
f@0 416 sonificationSeqMapping.renderCurveAt(null, 0.0f, SequenceMapping.DURATION_STOP);
f@0 417 }
f@0 418
f@0 419 }
f@0 420
f@0 421 public void showPeakLevelSound(boolean show){
f@0 422 showPeakLevelSound = show;
f@0 423
f@0 424 SequenceMapping sonificationSeqMapping = Daw.getSoundEngineFactory().getSharedSonification()
f@0 425 .getSequenceMapping(SoundType.PEAK_LEVEL);
f@0 426 if(show){
f@0 427 sonificationSeqMapping.renderCurveAt(
f@0 428 soundWave.getDbWave().getSequence(),
f@0 429 soundWave.getMillisecPerChunk() * cursorPos,
f@0 430 SequenceMapping.DURATION_INF);
f@0 431 }else{
f@0 432 sonificationSeqMapping.renderCurveAt(null, 0.0f, SequenceMapping.DURATION_STOP);
f@0 433 }
f@0 434 }
f@0 435
f@0 436 public void showDbWave(boolean show){
f@0 437 showDbWave = show;
f@0 438 repaint();
f@0 439 }
f@0 440
f@0 441
f@0 442 public int normToWidthconvert(float f){
f@0 443 return hapticViewPort.getPosition(f);
f@0 444 }
f@0 445 /**
f@0 446 *
f@0 447 * @param s a value sample value ranging from Short.MIN_VALUE to Short.MAX_VALUE
f@0 448 * @param height the height of the graphic component where the track is to be drawn
f@0 449 * @return the Y value in the graphic component resulted from mapping the sample to the graphic component height
f@0 450 */
f@0 451 public int normToHeightConvert(float f){
f@0 452 /* in a JPanel pixel y coordinate increases from top to bottom, whereas the *
f@0 453 * in the signed short PCM format y value increased from bottom to top *
f@0 454 * so the sign of the value is reversed to match it with the JPanel space */
f@0 455 int height = getHeight();
f@0 456 return height - (int)( f *height);
f@0 457 }
f@0 458
f@0 459 /**
f@0 460 * Returns a point in the {@code Automation} coordinates - x = length in millis,
f@0 461 * y = range of the automation - corresponding to the point on {@code track}
f@0 462 * which has coordinates {@code (mouseX, mouseY) }
f@0 463 *
f@0 464 *
f@0 465 * @param track
f@0 466 * @param mouseX the {@code x} coordinate of the point on {@code track}
f@0 467 * @param mouseY the {@code y} coordinate of the point on {@code track}
f@0 468 * @return the point in the {@code Automation} coordinates corresponding to (mouseX,mouseY)
f@0 469 * or {@code null} if mouseX is bigger than the automation length (in chunks of the track's {@code SoundWave})
f@0 470 * or mouseY is bigger than the track's height, or if either is lower than zero.
f@0 471 *
f@0 472 */
f@0 473 public static Point2D.Float getAutomationCoord(AudioTrack track, int mouseX, int mouseY ){
f@0 474 SoundWave wave = track.getSoundWave();
f@0 475 Automation autom = wave.getParametersControl().getCurrentAutomation();
f@0 476
f@0 477 /* get height and width of the track panel */
f@0 478 float height = track.getSize().height;
f@0 479
f@0 480 float width = track.getSoundWave().getChunkNum();
f@0 481
f@0 482 if(mouseX >= width || mouseY > height || mouseX < 0 || mouseY < 0 ){
f@0 483 return null;
f@0 484 }
f@0 485
f@0 486 /* calculate the automation x (a.k.a. position over time) from *
f@0 487 * the mouse click according following relation: *
f@0 488 * mouse x / width of the panel = automation x position / length of sample */
f@0 489 float automationX = (float)(autom.getLen()*(mouseX/width));
f@0 490 /* calculate the automation y (a.k.a. value int he parameter range) from *
f@0 491 * the mouse click according following relation: *
f@0 492 * mouse y / height of the panel = automation y position / value range *
f@0 493 * since in swing y has 0 at the top the y value is reversed height-mouseY */
f@0 494 float automationY = (float)(autom.getRange().lenght() *((height-mouseY)/height));
f@0 495 return new Point2D.Float(automationX,automationY+autom.getRange().getStart());
f@0 496 }
f@0 497
f@0 498
f@0 499
f@0 500 private class CursorUpdaterOnPlay implements ActionListener {
f@0 501 private static final int REFRESH_DELAY = 50;
f@0 502 Timer timer = new Timer(REFRESH_DELAY,this);;
f@0 503
f@0 504 public void update(SoundWaveEvent evt) {
f@0 505 if(SoundWaveEvent.START.equals(evt.getType())){
f@0 506 timer.start();
f@0 507 }else if(SoundWaveEvent.STOP.equals(evt.getType()) ||
f@0 508 SoundWaveEvent.PAUSE.equals(evt.getType())){
f@0 509 timer.stop();
f@0 510 }
f@0 511 }
f@0 512
f@0 513 @Override
f@0 514 public void actionPerformed(ActionEvent e) {
f@0 515 int cursorPos = Math.round(soundWave.getTransportControl().getPlayPosition()/soundWave.getMillisecPerChunk());
f@0 516 setCursorPos(cursorPos);
f@0 517 }
f@0 518 } // class ClipInteraction
f@0 519
f@0 520 }