source: trunk/src/org/apollo/util/TrackModelLoadManager.java@ 1102

Last change on this file since 1102 was 1102, checked in by davidb, 6 years ago

Reworking of the code-base to separate logic from graphics. This version of Expeditee now supports a JFX graphics as an alternative to SWING

File size: 5.3 KB
Line 
1package org.apollo.util;
2
3import java.io.File;
4import java.io.IOException;
5import java.util.HashSet;
6import java.util.Set;
7
8import javax.sound.sampled.UnsupportedAudioFileException;
9
10import org.apollo.audio.SampledTrackModel;
11import org.apollo.io.AudioIO;
12import org.apollo.io.LoadedAudioData;
13import org.apollo.mvc.Observer;
14import org.expeditee.core.BlockingRunnable;
15import org.expeditee.gio.EcosystemManager;
16import org.expeditee.items.widgets.HeavyDutyInteractiveWidget;
17import org.expeditee.items.widgets.WidgetCacheManager;
18
19/**
20 * Purpose: to avoid race conditions when loading track models from many threads.
21 *
22 * All sharing of track models is done here.
23 *
24 * Looked at disposed design patterns... but they become way to deep!
25 *
26 * @author Brook Novak
27 *
28 */
29public class TrackModelLoadManager {
30
31 private Set<TrackModelHandler> trackModelHandlers = new HashSet<TrackModelHandler>();
32
33 private static TrackModelLoadManager instance = new TrackModelLoadManager();
34
35 public static TrackModelLoadManager getInstance() {
36 return instance;
37 }
38
39 private TrackModelLoadManager() {
40 }
41
42
43 /**
44 * Don't go adding everything possible... only add a handler if the handlers lifetime is
45 * for the whole application, or is "disposable".
46 *
47 * @param handler
48 */
49 public void addTrackModelHandler(TrackModelHandler handler) {
50 assert(handler != null);
51 synchronized(trackModelHandlers) {
52 trackModelHandlers.add(handler);
53 }
54 }
55
56 /**
57 * Always remove to get rid of reference and keep memory finding routines fast
58 *
59 * @param handler
60 *
61 */
62 public void removeTrackModelHandler(TrackModelHandler handler) {
63 assert(handler != null);
64 synchronized(trackModelHandlers) {
65 trackModelHandlers.remove(handler);
66 }
67 }
68
69 /**
70 * Loads a SampledTrackModel. First it attempts to find is in memory, if fails then it
71 * will resort to loading from file.
72 *
73 * Note that if loaded from file and required conversions, the SampledTrackModel will
74 * be marked as being modified (requiring saving).
75 *
76 * @param filepath
77 * The filepath of the audio file to load. The SampledTrackModel will set its filename as
78 * this path value.
79 *
80 * @param checkExpediteeMemory
81 * If set to true, then it will search for SampledTrackModels in expeditee cache
82 * on the swing thread. Therefore MUST <b>NOT</b> BE ON THE SWINGTHREAD IF THIS IS SET TO TRUE.
83 *
84 * @param observer
85 * If given (can be null), then the observer will be notified with
86 * LOAD_STATUS_REPORT AudioSubjectChangedEvent events (on the calling thread).
87 * The state will be a float with the current percent (between 0.0 and 1.0 inclusive).
88 * The subject source will be this instance.
89 *
90 * @param localFilename
91 * The local filename to associate the loaded track with.
92 * Must not be null.
93 *
94 * @return
95 * Null iff cancelled.
96 *
97 * @throws IOException
98 * @throws UnsupportedAudioFileException
99 */
100 public synchronized SampledTrackModel load(
101 String filepath,
102 String localfilename,
103 Observer observer,
104 boolean checkExpediteeMemory) throws IOException, UnsupportedAudioFileException {
105
106 assert(localfilename != null);
107
108 // Check to see if already in memory
109 synchronized(trackModelHandlers) {
110 for (TrackModelHandler handler : trackModelHandlers) {
111 SampledTrackModel tm = handler.getSharedSampledTrackModel(localfilename);
112 if (tm != null) {
113 return tm;
114 }
115 }
116 }
117
118 if (checkExpediteeMemory) {
119 // MUST NOT BE ON SWING THREAD!
120 // THIS IS IMPORTANT FOR WHEN FRAMES HAVE BEEN CHECK AND THEY WHERE NOT LOADED AT
121 // THE TIME AND THUS CACHED WIDGETS NOT IN MEMORY, BUT LATER IS CACHED ...
122
123 CachedTrackModelLocator locator = new CachedTrackModelLocator(localfilename);
124
125 try {
126 EcosystemManager.getMiscManager().runOnGIOThread(locator);
127 } catch (Exception e) {
128 e.printStackTrace();
129 }
130
131 if (locator.located != null) {
132 return locator.located;
133 }
134
135 }
136
137
138 // If cannot find in memory, then attempt to load from file.
139 LoadedAudioData loadedAudio = AudioIO.loadAudioFile(new File(filepath), observer);
140
141 // Could have been cancelled
142 if (loadedAudio == null) return null;
143
144 // Create the track
145 SampledTrackModel track = new SampledTrackModel(
146 loadedAudio.getAudioBytes(),
147 loadedAudio.getAudioFormat(),
148 localfilename);
149
150 track.setFilepath(filepath);
151
152 // Set as modified if the audio bytes had to be converted
153 if (loadedAudio.wasConverted()) {
154 track.setAudioModifiedFlag(true);
155 }
156
157 return track;
158
159 }
160
161
162
163 /**
164 * Look in expeditee memory - this should be quick - will hold up the user
165 */
166 private class CachedTrackModelLocator extends BlockingRunnable
167 {
168 private String localfileName;
169 private SampledTrackModel located = null;
170
171 CachedTrackModelLocator(String localfileName) {
172 assert(localfileName != null);
173 this.localfileName = localfileName;
174 }
175
176 public void execute() {
177
178 // Exploit knowledge that all SampledTrack are Cached HDW
179 for (HeavyDutyInteractiveWidget hdw : WidgetCacheManager.getTransientWidgets()) {
180 if (hdw instanceof TrackModelHandler) {
181
182 SampledTrackModel strack = ((TrackModelHandler)hdw).getSharedSampledTrackModel(localfileName);
183
184 if (strack != null) {
185 assert(strack.getLocalFilename().equals(localfileName));
186
187 // found a match that is cahced
188 located = strack;
189 return;
190 }
191 }
192 }
193
194 }
195
196 }
197
198
199}
Note: See TracBrowser for help on using the repository browser.