/* * Copyright 2008-2013, ETH Zürich, Samuel Welten, Michael Kuhn, Tobias Langner, * Sandro Affentranger, Lukas Bossard, Michael Grob, Rahul Jain, * Dominic Langenegger, Sonia Mayor Alonso, Roger Odermatt, Tobias Schlueter, * Yannick Stucki, Sebastian Wendland, Samuel Zehnder, Samuel Zihlmann, * Samuel Zweifel * * This file is part of Jukefox. * * Jukefox is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or any later version. Jukefox is * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * Jukefox. If not, see <http://www.gnu.org/licenses/>. */ package ch.ethz.dcg.jukefox.controller.player.playbackcontroller; import java.util.LinkedHashMap; import java.util.Map; import ch.ethz.dcg.jukefox.commons.utils.Log; public class GaplessTimeMeasures { public static final String TAG = GaplessTimeMeasures.class.getSimpleName(); public static final int TIME_MEASUREMENT_ITEMS = 3; public static final int UNREALISTIC_GAP_THRESHOLD = 1000; private Long tempSong1TimeMeasured; private Long tempSong1Position; private Long tempSong1Duration; private LinkedHashMap<Integer, TimeMeasurement> timeMeasurements; private int id = 0; private int currentGapTime; private int autoGapRemoveTime; private int manualGapRemoveTime; public GaplessTimeMeasures(int autoGapRemoveTime, int manualGapRemoveTime) { this.autoGapRemoveTime = autoGapRemoveTime; this.manualGapRemoveTime = manualGapRemoveTime; timeMeasurements = new LinkedHashMap<Integer, TimeMeasurement>(0, 0.75f, false) { private static final long serialVersionUID = 1L; @Override public boolean removeEldestEntry(Map.Entry<Integer, TimeMeasurement> eldest) { if (this.size() > TIME_MEASUREMENT_ITEMS) { return true; } else { return false; } } }; TimeMeasurement tm = new TimeMeasurement(autoGapRemoveTime); timeMeasurements.put(id, tm); id++; computeGapTime(); } public void setSong1Times(long song1TimeMeasured, long song1Position, long song1Duration) { this.tempSong1TimeMeasured = song1TimeMeasured; this.tempSong1Position = song1Position; this.tempSong1Duration = song1Duration; } public void setSong2Times(long song2TimeMeasured, long song2Position, int gapOffset) { if (tempSong1Duration == null || tempSong1Position == null || tempSong1TimeMeasured == null) { Log.w(TAG, "Song2 time set before Song1 time was set! Not using time measurement"); return; } TimeMeasurement tm = new TimeMeasurement(tempSong1TimeMeasured, tempSong1Position, tempSong1Duration, song2TimeMeasured, song2Position, gapOffset); tm.print(); this.tempSong1TimeMeasured = null; this.tempSong1Position = null; this.tempSong1Duration = null; if (Math.abs(tm.getGap()) > UNREALISTIC_GAP_THRESHOLD || tm.getGap() < 0) { Log.w(TAG, "Not using gap timing because it's unrealistic: " + tm.getGap()); // System.out.println("Not using gap timing because it's unrealistic: " + tm.getGap()); return; } timeMeasurements.put(id, tm); int lastGapCorrection = currentGapTime; computeGapTime(); autoGapRemoveTime = currentGapTime; Log.v(TAG, "Last gap size: " + tm.getGap() + ", gap correction was: " + lastGapCorrection); // System.out.println("Last gap size: " + tm.getGap() + ", gap correction was: " + lastGapCorrection); id++; } private void computeGapTime() { if (timeMeasurements.size() == 0) { currentGapTime = 0; return; } int mean = 0; for (TimeMeasurement t : timeMeasurements.values()) { mean += t.getGap(); } currentGapTime = mean / timeMeasurements.size(); } public int getGapTime() { return currentGapTime; } private class TimeMeasurement { private final long song1TimeMeasured; private final long song1Duration; private final long song1Position; private final long song2TimeMeasured; private final long song2Position; private final int gapOffset; private final int gap; public TimeMeasurement(long song1TimeMeasured, long song1Position, long song1Duration, long song2TimeMeasured, long song2Position, int gapOffset) { this.song1Duration = song1Duration; this.song1TimeMeasured = song1TimeMeasured; this.song1Position = song1Position; this.song2TimeMeasured = song2TimeMeasured; this.song2Position = song2Position; this.gapOffset = gapOffset; gap = computeGap(); } public TimeMeasurement(int gap) { this.song1Duration = 0; this.song1TimeMeasured = 0; this.song1Position = 0; this.song2TimeMeasured = 0; this.song2Position = 0; this.gapOffset = 0; this.gap = gap; } public void print() { Log.v(TAG, "Song1Position: " + song1Position); Log.v(TAG, "Song1Duration: " + song1Duration); Log.v(TAG, "Song1Time: " + song1TimeMeasured); Log.v(TAG, "TimeDiff: " + (song2TimeMeasured - song1TimeMeasured)); Log.v(TAG, "song2Pos: " + song2Position); } public int getGap() { return gap; } private int computeGap() { int remaining = (int) (song1Duration - song1Position); int songGap = (int) (remaining + song2Position); int totalGap = (int) (song2TimeMeasured - song1TimeMeasured) + gapOffset; return totalGap - songGap; } } public int getAutoGapRemoveTime() { return autoGapRemoveTime; } public int getManualGapRemoveTime() { return manualGapRemoveTime; } }