!759 static int songDuration, seekValue; static long songBytes; static int position; static File mp3; static BasicPlayer player; static Int seekTo; static JFrame frame; static new JSlider seeker; static new JLabel text; static new JTable table; static new JTable lastPlayed; static L tableData, lastPlayedData; p-awt { substanceLAF("Moderate"); // Fixing the classpath for Java Sound (MP3 + OGG) fixContextClassLoader(); thread "Searching Music..." { updateLastPlayed(); tableData = findMusicFiles(); dataToTable_uneditable(table, musicFilesTable(tableData)); } onDoubleClick(table, voidfunc(int row) { play(tableData.get(row)); }); onDoubleClick(lastPlayed, voidfunc(int row) { play(lastPlayedData.get(row)); }); // init seeker seeker.setMajorTickSpacing(10000); // 10 seconds seeker.setMinorTickSpacing(10000); // 10 seconds seeker.setPaintTicks(true); seeker.setMaximum(1); seeker.setValue(0); seeker.setEnabled(false); seeker.addChangeListener(new ChangeListener { public void stateChanged(ChangeEvent e) { bool adjusting = seeker.getValueIsAdjusting(); if (adjusting) seekTo = seeker.getValue(); else if (seekTo != null) { seek(seekTo); seekTo = null; } } }); frame = showFrame( centerAndNorth(jtabs( "Library", table, "Last played", lastPlayed), centerAndSouth( centerAndEast(seeker, text), hgrid(jbutton("play again", "playAgain")) ))); frame.pack(); setFrameIconLater(frame, "#1003635"); setFrameWidth(frame, 500); exitOnFrameClose(frame); // To immediately stop playback hideConsole(); player = makeBasicMP3Player(); player.addBasicPlayerListener(new BasicPlayerListener { public void opened(Object stream, Map properties) { for (Object key : properties.keySet()) print("opened: " + key + "=" + properties.get(key)); // Try to find duration of song final Number bytes = (Number) properties.get("audio.length.bytes"); long microseconds = 0; O duration = properties.get("duration"); if (duration instanceof Number) microseconds = ((Number) duration).longValue(); else pcall { long frames = asLong(properties.get("audio.length.frames")); long fps = asLong(properties.get("audio.framerate.fps")); microseconds = frames*1000000/fps; } final long _microseconds = microseconds; awt { songDuration = (int) (_microseconds / 1000); seeker.setMaximum(songDuration); seeker.setEnabled(true); seeker.setMajorTickSpacing(10000); // 10 seconds updateText(); songBytes = bytes.longValue(); } } public void progress(int bytesread, final long microseconds, byte[] pcmdata, Map properties) { awt { if (!seeker.getValueIsAdjusting()) { int ms = (int) (microseconds / 1000) + seekValue; seeker.setValue(ms); position = ms; updateText(); } } } public void stateUpdated(BasicPlayerEvent event) { awt { updateStateStuff(); } } public void setController(BasicController controller) {} }); } svoid play(File f) { if (f == null) ret; mp3 = f; setFrameTitle(frame, f.getName() + " - " + getProgramTitle()); logStructure("player.log", litlist(now(), "Playing", f.getAbsolutePath())); play(); updateLastPlayed(); } svoid playAgain { logStructure("player.log", litlist(now(), "Playing again")); play(); } svoid play() ctex { seekValue = 0; player.open(mp3); player.play(); } svoid updateStateStuff {} svoid updateText { text.setText(formatMinuteAndSeconds(position/1000) + " / " + formatMinuteAndSeconds(songDuration/1000)); } svoid seek(int milliseconds) { if (mp3 == null) ret; long bytes = (long) (milliseconds*((double) songBytes)/songDuration); print("ms=" + milliseconds + ", songBytes=" + songBytes + ", duration=" + songDuration + ", bytes=" + bytes); pcall { seekValue = milliseconds; player.open(mp3); player.seek(bytes); player.play(); } } static L findLastPlayed() { new L l; new Set seen; for (S s : reversedList(scanLog("player.log"))) pcall { L line = unstructureList(s); if (eq(get(line, 1), "Playing")) { S file = getString(line, 2); if (seen.add(file)) l.add(new File(file)); } } ret l; } static void updateLastPlayed() { dataToTable_uneditable(lastPlayed, musicFilesTable(lastPlayedData = findLastPlayed())); }