Download Jar. Uses 4758K of libraries. Click here for Pure Java version (10442L/77K).
1 | !7 |
2 | |
3 | static int songDuration, seekValue; |
4 | static long songBytes; |
5 | static int position; |
6 | static File mp3; |
7 | static BasicPlayer player; |
8 | static Int seekTo; |
9 | static volatile byte[] lastPCMData; |
10 | |
11 | static JFrame frame; |
12 | static new JSlider seeker; |
13 | static new JLabel text; |
14 | static JTable table; |
15 | static JTable lastPlayed; |
16 | static JButton btnPause; |
17 | |
18 | p { |
19 | print("hello"); |
20 | swing { |
21 | substanceLAF("Moderate"); |
22 | |
23 | // Fixing the classpath for Java Sound (MP3 + OGG) |
24 | fixContextClassLoader(); |
25 | |
26 | table = tableWithToolTips(); |
27 | lastPlayed = tableWithToolTips(); |
28 | } |
29 | |
30 | updateLastPlayed(); |
31 | searchLibrary(); |
32 | |
33 | swing { |
34 | onDoubleClickOrEnter(table, voidfunc(int row) { |
35 | play(fileFromTable(table, row)); |
36 | }); |
37 | |
38 | onDoubleClickOrEnter(lastPlayed, voidfunc(int row) { |
39 | play(fileFromTable(lastPlayed, row)); |
40 | }); |
41 | |
42 | // init seeker |
43 | seeker.setMajorTickSpacing(10000); // 10 seconds |
44 | seeker.setMinorTickSpacing(10000); // 10 seconds |
45 | seeker.setPaintTicks(true); |
46 | seeker.setMaximum(1); |
47 | seeker.setValue(0); |
48 | seeker.setEnabled(false); |
49 | seeker.addChangeListener(new ChangeListener { |
50 | public void stateChanged(ChangeEvent e) { |
51 | bool adjusting = seeker.getValueIsAdjusting(); |
52 | if (adjusting) |
53 | seekTo = seeker.getValue(); |
54 | else if (seekTo != null) { |
55 | seek(seekTo); |
56 | seekTo = null; |
57 | } |
58 | } |
59 | }); |
60 | |
61 | frame = showFrame( |
62 | centerAndNorth(jtabs( |
63 | "Library", tableWithSearcher(table), |
64 | "Last played", tableWithSearcher(lastPlayed)), |
65 | centerAndSouth( |
66 | centerAndEast(seeker, text), |
67 | hgrid( |
68 | jbutton("play again", "playAgain"), |
69 | btnPause = jbutton("pause", "pause"), |
70 | jbutton("upload", "upload"), |
71 | jbutton("assistance", "assistance")) |
72 | ))); |
73 | frame.pack(); |
74 | setFrameIconLater(frame, "#1003635"); |
75 | setFrameWidth(frame, 500); |
76 | exitOnFrameClose(frame); // To immediately stop playback |
77 | |
78 | titlePopupMenu(frame, |
79 | voidfunc(JPopupMenu menu) { |
80 | menu.add(jmenuItem("Rescan Library", r { searchLibrary() })); |
81 | }); |
82 | |
83 | hideConsole(); |
84 | |
85 | player = makeBasicMP3Player(); |
86 | |
87 | player.addBasicPlayerListener(new BasicPlayerListener { |
88 | public void opened(Object stream, Map properties) { |
89 | for (Object key : properties.keySet()) |
90 | print("opened: " + key + "=" + properties.get(key)); |
91 | |
92 | // Try to find duration of song |
93 | final Number bytes = (Number) properties.get("audio.length.bytes"); |
94 | long microseconds = 0; |
95 | O duration = properties.get("duration"); |
96 | |
97 | if (duration instanceof Number) |
98 | microseconds = ((Number) duration).longValue(); |
99 | else pcall { |
100 | long frames = asLong(properties.get("audio.length.frames")); |
101 | long fps = asLong(properties.get("audio.framerate.fps")); |
102 | microseconds = frames*1000000/fps; |
103 | } |
104 | |
105 | final long _microseconds = microseconds; |
106 | |
107 | awt { |
108 | songDuration = (int) (_microseconds / 1000); |
109 | seeker.setMaximum(songDuration); |
110 | seeker.setEnabled(true); |
111 | seeker.setMajorTickSpacing(10000); // 10 seconds |
112 | updateText(); |
113 | songBytes = bytes.longValue(); |
114 | } |
115 | } |
116 | |
117 | public void progress(int bytesread, final long microseconds, byte[] pcmdata, Map properties) { |
118 | lastPCMData = pcmdata; |
119 | awt { |
120 | if (!seeker.getValueIsAdjusting()) { |
121 | int ms = (int) (microseconds / 1000) + seekValue; |
122 | seeker.setValue(ms); |
123 | position = ms; |
124 | updateText(); |
125 | } |
126 | } |
127 | } |
128 | |
129 | public void stateUpdated(BasicPlayerEvent event) { |
130 | awt { |
131 | updateStateStuff(); |
132 | } |
133 | } |
134 | |
135 | public void setController(BasicController controller) {} |
136 | }); |
137 | |
138 | makeBot("Music Player."); |
139 | } |
140 | } |
141 | |
142 | svoid searchLibrary { |
143 | thread "Searching Music..." { |
144 | dataToTable_uneditable(table, musicFilesTable(findMusicFiles())); |
145 | } |
146 | } |
147 | |
148 | svoid play(File f) { |
149 | if (f == null) ret; |
150 | mp3 = f; |
151 | setFrameTitle(frame, f.getName() + " - " + getProgramTitle()); |
152 | logStructure(getProgramFile("#1003634", "player.log"), litlist(now(), "Playing", f.getAbsolutePath())); |
153 | play(); |
154 | updateLastPlayed(); |
155 | } |
156 | |
157 | svoid playAgain() ctex { |
158 | if (isPaused()) |
159 | player.resume(); |
160 | else { |
161 | logStructure(getProgramFile("#1003634", "player.log"), litlist(now(), "Playing again")); |
162 | play(); |
163 | } |
164 | } |
165 | |
166 | svoid play() ctex { |
167 | seekValue = 0; |
168 | player.open(mp3); |
169 | player.play(); |
170 | } |
171 | |
172 | sbool isPlaying() { |
173 | ret player.getStatus() == player.PLAYING; |
174 | } |
175 | |
176 | sbool isPaused() { |
177 | ret player.getStatus() == player.PAUSED; |
178 | } |
179 | |
180 | svoid pause() ctex { |
181 | if (isPaused()) |
182 | player.resume(); |
183 | else |
184 | player.pause(); |
185 | } |
186 | |
187 | svoid updateStateStuff { |
188 | btnPause.setText(isPaused() ? "resume" : "pause"); |
189 | } |
190 | |
191 | svoid updateText { |
192 | text.setText(formatMinuteAndSeconds(position/1000) + " / " + formatMinuteAndSeconds(songDuration/1000)); |
193 | } |
194 | |
195 | svoid seek(int milliseconds) { |
196 | if (mp3 == null) ret; |
197 | long bytes = (long) (milliseconds*((double) songBytes)/songDuration); |
198 | print("ms=" + milliseconds + ", songBytes=" + songBytes + ", duration=" + songDuration + ", bytes=" + bytes); |
199 | |
200 | pcall { |
201 | seekValue = milliseconds; |
202 | player.open(mp3); |
203 | player.seek(bytes); |
204 | player.play(); |
205 | } |
206 | } |
207 | |
208 | static L<File> findLastPlayed() { |
209 | new L<File> l; |
210 | new Set<S> seen; |
211 | for (S s : reversedList(scanLog("#1003634", "player.log"))) pcall { |
212 | L line = unstructureList(s); |
213 | if (eq(get(line, 1), "Playing")) { |
214 | S file = getString(line, 2); |
215 | if (seen.add(file)) |
216 | l.add(new File(file)); |
217 | } |
218 | } |
219 | ret l; |
220 | } |
221 | |
222 | static void updateLastPlayed() { |
223 | dataToTable_uneditable(lastPlayed, musicFilesTable(findLastPlayed())); |
224 | } |
225 | |
226 | static File fileFromTable(JTable table, int row) { |
227 | SS map = getTableLineAsMap(table, row); |
228 | File f = new File(map.get("Location"), map.get("Name")); |
229 | if (!f.exists()) print("Oops, file not found: " + f.getAbsolutePath()); |
230 | ret f; |
231 | } |
232 | |
233 | static void upload() { |
234 | thread "Uploading" { |
235 | loading { |
236 | uploadFileToPhoneServer(mp3); |
237 | } |
238 | } |
239 | } |
240 | |
241 | answer { |
242 | if "play again" { |
243 | if (mp3 == null) ret "No song"; |
244 | swingLater(r { playAgain(); }); |
245 | ret "OK"; |
246 | } |
247 | if "are you playing" ret yn(isPlaying()); |
248 | if "are you paused" ret yn(isPaused()); |
249 | if "play file *" { |
250 | awt { play(new File(m.unq(0))); } |
251 | ret "OK"; |
252 | } |
253 | if "get file" ret structure(mp3); |
254 | if "pcm data" ret structure(lastPCMData); |
255 | if "pcm data * " ret lastPCMData == null ? "null" : structure(subArray(lastPCMData, 0, min(lastPCMData.length, m.psi(0)))); |
256 | } |
257 | |
258 | svoid assistance { |
259 | assist(); |
260 | } |
Began life as a copy of #1003634
download show line numbers debug dex old transpilations
Travelled to 19 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, ddnzoavkxhuk, gwrvuhgaqvyk, hszllmzzlmie, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, nbgitpuheiab, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, sawdedvomwva, tslmcundralx, tvejysmllsmz, vouqrxazstgt, vqftxbmjmmzu
No comments. add comment
Snippet ID: | #1003779 |
Snippet name: | Music Player v3 |
Eternal ID of this version: | #1003779/6 |
Text MD5: | 044167b141c34b39cba793c44de8c95b |
Transpilation MD5: | 7c8e705adc9157c0b7a0def7be10f1e3 |
Author: | stefan |
Category: | javax |
Type: | JavaX source code (desktop) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2018-05-22 02:07:38 |
Source code size: | 6705 bytes / 260 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 959 / 4161 |
Version history: | 5 change(s) |
Referenced in: | [show references] |