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