[315] | 1 | package org.apollo.gui;
|
---|
| 2 |
|
---|
| 3 | import java.util.LinkedList;
|
---|
| 4 | import java.util.List;
|
---|
| 5 |
|
---|
| 6 | import org.apollo.audio.ApolloPlaybackMixer;
|
---|
| 7 | import org.apollo.audio.ApolloSubjectChangedEvent;
|
---|
| 8 | import org.apollo.audio.structure.OverdubbedFrame;
|
---|
| 9 | import org.apollo.audio.util.MultiTrackPlaybackController;
|
---|
| 10 | import org.apollo.audio.util.PlaybackClock;
|
---|
| 11 | import org.apollo.audio.util.Timeline;
|
---|
| 12 | import org.apollo.audio.util.PlaybackClock.PlaybackClockListener;
|
---|
| 13 | import org.apollo.mvc.Observer;
|
---|
| 14 | import org.apollo.mvc.Subject;
|
---|
| 15 | import org.apollo.mvc.SubjectChangedEvent;
|
---|
| 16 | import org.apollo.util.AudioMath;
|
---|
| 17 | import org.apollo.widgets.FramePlayer;
|
---|
[1102] | 18 | import org.expeditee.core.Colour;
|
---|
| 19 | import org.expeditee.core.Stroke;
|
---|
| 20 | import org.expeditee.core.bounds.AxisAlignedBoxBounds;
|
---|
| 21 | import org.expeditee.gio.EcosystemManager;
|
---|
| 22 | import org.expeditee.gio.GraphicsManager;
|
---|
[315] | 23 | import org.expeditee.gui.Browser;
|
---|
[1102] | 24 | import org.expeditee.gui.DisplayController;
|
---|
[315] | 25 | import org.expeditee.gui.Frame;
|
---|
| 26 |
|
---|
| 27 | /**
|
---|
| 28 | * Renders playback bars while the multi playback controller is playing.
|
---|
| 29 | * Depending on which frame the user is on etc...
|
---|
| 30 | *
|
---|
| 31 | * @author Brook Novak
|
---|
| 32 | *
|
---|
| 33 | */
|
---|
| 34 | public class FramePlaybackBarRenderer implements PlaybackClockListener, Observer {
|
---|
| 35 |
|
---|
| 36 | /** Relative to the current multi-track groups root frame. */
|
---|
| 37 | private long currentMSPosition = 0;
|
---|
| 38 |
|
---|
[365] | 39 | //private long liveFrameOffset = 0;
|
---|
| 40 |
|
---|
[315] | 41 | private List<Integer> pixelPositions = new LinkedList<Integer>();
|
---|
| 42 | private String pixelPositionsParent = null; // framename
|
---|
| 43 |
|
---|
| 44 | private Timeline currentTimeline = null;
|
---|
| 45 |
|
---|
| 46 | private PlaybackFrameBarUpdator updator = new PlaybackFrameBarUpdator();
|
---|
| 47 |
|
---|
| 48 | private static final int BAR_STROKE_THICKNESS = 2;
|
---|
[1102] | 49 | private static final Stroke BAR_STROKE = new Stroke(BAR_STROKE_THICKNESS);
|
---|
| 50 | private static final Colour BAR_COLOR = Colour.DARK_GREY;
|
---|
[315] | 51 |
|
---|
| 52 | private static FramePlaybackBarRenderer instance = new FramePlaybackBarRenderer();
|
---|
| 53 |
|
---|
| 54 | private FramePlaybackBarRenderer() {
|
---|
| 55 | MultiTrackPlaybackController.getInstance().addObserver(this);
|
---|
| 56 | //DisplayIO.addDisplayIOObserver(this);
|
---|
| 57 | FrameLayoutDaemon.getInstance().addObserver(this);
|
---|
| 58 | }
|
---|
| 59 |
|
---|
| 60 | public static FramePlaybackBarRenderer getInstance() {
|
---|
| 61 | return instance;
|
---|
| 62 | }
|
---|
| 63 |
|
---|
| 64 | /**
|
---|
| 65 | * {@inheritDoc}
|
---|
| 66 | */
|
---|
| 67 | public Subject getObservedSubject() {
|
---|
| 68 | return null;
|
---|
| 69 | }
|
---|
| 70 |
|
---|
| 71 | /**
|
---|
| 72 | * {@inheritDoc}
|
---|
| 73 | */
|
---|
| 74 | public void setObservedSubject(Subject parent) {
|
---|
| 75 | }
|
---|
| 76 |
|
---|
| 77 | /**
|
---|
| 78 | * {@inheritDoc}
|
---|
| 79 | */
|
---|
| 80 | public void modelChanged(Subject source, SubjectChangedEvent event) {
|
---|
| 81 |
|
---|
| 82 | if (source == FrameLayoutDaemon.getInstance()) {
|
---|
| 83 | currentTimeline = FrameLayoutDaemon.getInstance().getLastComputedTimeline();
|
---|
| 84 |
|
---|
| 85 | updator.run();
|
---|
| 86 | // Asumming refresh will occur
|
---|
| 87 |
|
---|
| 88 | return;
|
---|
| 89 | }
|
---|
| 90 |
|
---|
| 91 | switch (event.getID()) {
|
---|
| 92 | case ApolloSubjectChangedEvent.PLAYBACK_STARTED:
|
---|
[365] | 93 |
|
---|
| 94 | /*liveFrameOffset = ApolloPlaybackMixer.getInstance().getLiveFramePosition();
|
---|
| 95 | if (liveFrameOffset < 0) liveFrameOffset = 0;
|
---|
| 96 | System.out.println("liveFrameOffset=" + liveFrameOffset);*/
|
---|
| 97 |
|
---|
[315] | 98 | PlaybackClock.getInstance().addPlaybackClockListener(this);
|
---|
| 99 | break;
|
---|
| 100 |
|
---|
| 101 | case ApolloSubjectChangedEvent.PLAYBACK_STOPPED:
|
---|
| 102 | PlaybackClock.getInstance().removePlaybackClockListener(this);
|
---|
| 103 |
|
---|
| 104 | if (MultiTrackPlaybackController.getInstance().isMarkedAsPaused() &&
|
---|
| 105 | FramePlayer.FRAME_PLAYERMASTER_CHANNEL_ID.equals(
|
---|
| 106 | MultiTrackPlaybackController.getInstance().getCurrentMasterChannelID())) {
|
---|
| 107 |
|
---|
| 108 | currentMSPosition = AudioMath.framesToMilliseconds(
|
---|
| 109 | MultiTrackPlaybackController.getInstance().getLastSuspendedFrame(),
|
---|
| 110 | ApolloPlaybackMixer.getInstance().getLiveAudioFormat());
|
---|
| 111 |
|
---|
| 112 | updator.run();
|
---|
| 113 |
|
---|
| 114 | } else {
|
---|
| 115 | invalidate();
|
---|
| 116 | currentMSPosition = -1;
|
---|
| 117 | pixelPositions.clear();
|
---|
| 118 | }
|
---|
| 119 |
|
---|
[1102] | 120 | DisplayController.requestRefresh(true);
|
---|
[315] | 121 |
|
---|
| 122 |
|
---|
| 123 | break;
|
---|
| 124 |
|
---|
| 125 | case ApolloSubjectChangedEvent.PAUSE_MARK_CHANGED:
|
---|
| 126 |
|
---|
| 127 |
|
---|
| 128 | invalidate();
|
---|
| 129 | currentMSPosition = -1;
|
---|
| 130 | pixelPositions.clear();
|
---|
[1102] | 131 | DisplayController.requestRefresh(true);
|
---|
[315] | 132 |
|
---|
| 133 | break;
|
---|
| 134 | }
|
---|
| 135 |
|
---|
| 136 |
|
---|
| 137 | }
|
---|
| 138 |
|
---|
[1102] | 139 | private void invalidate()
|
---|
| 140 | {
|
---|
[315] | 141 | if (Browser._theBrowser == null) return;
|
---|
| 142 |
|
---|
[1102] | 143 | int height = EcosystemManager.getGraphicsManager().getWindowSize().getHeight();
|
---|
[315] | 144 |
|
---|
| 145 | for (Integer n : pixelPositions) {
|
---|
[1102] | 146 | DisplayController.invalidateArea(new AxisAlignedBoxBounds(n - 1, 0, BAR_STROKE_THICKNESS + 2, height));
|
---|
[315] | 147 | }
|
---|
| 148 | }
|
---|
| 149 |
|
---|
[1102] | 150 | public void paint()
|
---|
| 151 | {
|
---|
[315] | 152 | if (Browser._theBrowser == null) return;
|
---|
| 153 |
|
---|
[1102] | 154 | Frame currentFrame = DisplayController.getCurrentFrame();
|
---|
[315] | 155 |
|
---|
| 156 | if (currentFrame == null || currentFrame.getName() == null || pixelPositionsParent == null ||
|
---|
| 157 | !currentFrame.getName().equals(pixelPositionsParent)) return;
|
---|
| 158 |
|
---|
[1102] | 159 | int height = EcosystemManager.getGraphicsManager().getWindowSize().getHeight();
|
---|
[315] | 160 |
|
---|
[1102] | 161 | GraphicsManager gm = EcosystemManager.getGraphicsManager();
|
---|
[315] | 162 |
|
---|
| 163 | for (Integer n : pixelPositions) {
|
---|
[1102] | 164 | gm.drawLine(n, 0, n, height, BAR_COLOR, BAR_STROKE);
|
---|
[315] | 165 | }
|
---|
| 166 | }
|
---|
| 167 |
|
---|
| 168 | /**
|
---|
| 169 | * {@inheritDoc}
|
---|
| 170 | */
|
---|
| 171 | public void onTick(long framePosition, long msPosition) {
|
---|
| 172 |
|
---|
| 173 | if (framePosition < 0) return; // let stop event handle it
|
---|
| 174 |
|
---|
[365] | 175 | //framePosition -= liveFrameOffset;
|
---|
| 176 |
|
---|
[315] | 177 | // Convert the audio mixers frame position to the multiplaybacks frame position
|
---|
| 178 |
|
---|
| 179 | int fpos = (int)(framePosition
|
---|
| 180 | - MultiTrackPlaybackController.getInstance().getLastInitiationFrame()
|
---|
| 181 | + MultiTrackPlaybackController.getInstance().getLastStartFrame());
|
---|
[365] | 182 |
|
---|
[315] | 183 | // Clamp
|
---|
| 184 | if (fpos > MultiTrackPlaybackController.getInstance().getLastEndFrame())
|
---|
| 185 | fpos = MultiTrackPlaybackController.getInstance().getLastEndFrame();
|
---|
| 186 |
|
---|
| 187 | currentMSPosition = AudioMath.framesToMilliseconds(
|
---|
| 188 | fpos,
|
---|
| 189 | ApolloPlaybackMixer.getInstance().getLiveAudioFormat());
|
---|
| 190 |
|
---|
| 191 | // Notes: the clock will queue a refresh for the frame after this
|
---|
| 192 | // event proccesses ...
|
---|
[1102] | 193 | EcosystemManager.getMiscManager().runOnGIOThread(updator);
|
---|
[315] | 194 | }
|
---|
| 195 |
|
---|
| 196 | /**
|
---|
| 197 | * Note: refreshing is up to caller
|
---|
| 198 | *
|
---|
| 199 | * @author Brook Novak
|
---|
| 200 | */
|
---|
[1102] | 201 | private class PlaybackFrameBarUpdator implements Runnable
|
---|
| 202 | {
|
---|
[315] | 203 | public void run() {
|
---|
| 204 |
|
---|
| 205 | if (currentMSPosition == -1 || currentTimeline == null) return;
|
---|
| 206 |
|
---|
[1102] | 207 | Frame currentFrame = DisplayController.getCurrentFrame();
|
---|
[315] | 208 |
|
---|
| 209 | if (currentFrame == null || currentFrame.getName() == null) return;
|
---|
| 210 |
|
---|
| 211 | OverdubbedFrame od = MultiTrackPlaybackController.getInstance().getCurrentODFrame();
|
---|
| 212 | if (od == null) return;
|
---|
| 213 |
|
---|
| 214 | // Invalidate old positions
|
---|
| 215 | invalidate();
|
---|
| 216 | pixelPositions.clear();
|
---|
| 217 |
|
---|
| 218 | long firstInitTime = od.getFirstInitiationTime();
|
---|
| 219 |
|
---|
| 220 | List<Integer> msPositions = od.getMSPositions(
|
---|
| 221 | currentFrame.getName(),
|
---|
| 222 | currentMSPosition + firstInitTime);
|
---|
| 223 |
|
---|
| 224 | // Convert ms positions to pixel positions according to the current timeline
|
---|
| 225 | for (Integer n : msPositions) {
|
---|
| 226 | pixelPositions.add(new Integer(currentTimeline.getXAtMSTime(n + currentTimeline.getFirstInitiationTime())));
|
---|
| 227 | }
|
---|
| 228 |
|
---|
| 229 | pixelPositionsParent = currentFrame.getName();
|
---|
| 230 |
|
---|
| 231 | // Invalidate new positions
|
---|
| 232 | invalidate();
|
---|
| 233 | }
|
---|
| 234 | }
|
---|
| 235 |
|
---|
| 236 |
|
---|
| 237 |
|
---|
| 238 | }
|
---|