diff --git a/pom.xml b/pom.xml
index a9d058fe..c0cf6d17 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
PAMGuard is compatible - with Tethys 3.0 or - later. + with Tethys 3.1 or + later available for download from Zenodo. +
++ + Tethys is a freely available open source temporal-spatial database for metadata related to acoustic recordings. The database is intended to house diff --git a/src/soundPlayback/PlaybackProcess.java b/src/soundPlayback/PlaybackProcess.java index 6d488ef9..96bbc3be 100644 --- a/src/soundPlayback/PlaybackProcess.java +++ b/src/soundPlayback/PlaybackProcess.java @@ -71,6 +71,7 @@ public class PlaybackProcess extends PamInstantProcess { // super.prepareProcess(); // System.out.println("Playback prepare process"); prepareProcess(getSourceSampleRate()); + remainDelayMillis = 0; } public boolean prepareProcess(double sourceSampleRate) { @@ -204,7 +205,10 @@ public class PlaybackProcess extends PamInstantProcess { @Override synchronized public void newData(PamObservable o, PamDataUnit arg) { - if (playbackControl.playbackSystem == null) return; + if (playbackControl.playbackSystem == null) { + runSpeedLimit(o, arg); + return; + } int channel = PamUtils.getSingleChannel(arg.getChannelBitmap()); int pos = channelPos[channel]; // System.out.printf("Channel %d, pos %d\n", channel, pos); @@ -233,6 +237,7 @@ public class PlaybackProcess extends PamInstantProcess { boolean playOK = playbackControl.playbackSystem.playData(playUnits, 1); if (!playOK) { playWarning.setWarning("PlaybackProcess: playData return error", 2); + runSpeedLimit(o, arg); noteNewSettings(); // forces full reset of playback } else { @@ -255,6 +260,43 @@ public class PlaybackProcess extends PamInstantProcess { // } } + double remainDelayMillis = 0; + /** + * Modern desktops won't show a soundcard if no headphones are connected + * or plugged in. e.g. the ones in the teachinglab at work. In this case it's + * almost impossible to run the tutorials since everything happens so fast. + * So this function will cause a small delay before returning when no + * devices are present. + * @param o + * @param arg + */ + private void runSpeedLimit(PamObservable o, PamDataUnit arg) { + Double dataMillis = arg.getDurationInMilliseconds(); + if (dataMillis == null) { + return; + } + double speed = playbackControl.playbackParameters.getPlaybackSpeed(); + double delay = dataMillis / speed; + int intDelay = (int) Math.floor(delay); + /* + * Be a bit anal and deal with non integer bits by randomly chosing + * to add an extra milli or not. + */ + double remainder = delay - intDelay; + remainDelayMillis += remainder; + while (remainDelayMillis > 1) { + intDelay++; + remainDelayMillis--; + } + if (intDelay > 0) { + try { + Thread.sleep(intDelay); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + private RawDataUnit[] preprocessData(RawDataUnit[] inputDataUnits) { int isNull = 0; RawDataUnit[] outUnits = new RawDataUnit[inputDataUnits.length]; diff --git a/src/soundPlayback/SoundCardPlaybackBase.java b/src/soundPlayback/SoundCardPlaybackBase.java index de167b22..7618d2e4 100644 --- a/src/soundPlayback/SoundCardPlaybackBase.java +++ b/src/soundPlayback/SoundCardPlaybackBase.java @@ -94,10 +94,9 @@ public class SoundCardPlaybackBase { // give up if there are no mixers on the system return false; } - if (deviceNumber >= mixerinfos.size()) { + if (deviceNumber >= mixerinfos.size() || deviceNumber < 0) { deviceNumber = 0;// reset to default device. } - Mixer.Info thisMixerInfo = mixerinfos.get(deviceNumber); currentMixer = AudioSystem.getMixer(thisMixerInfo); if (currentMixer.getSourceLineInfo().length <= 0){