diff --git a/src/main/java/ru/windcorp/progressia/client/ClientProxy.java b/src/main/java/ru/windcorp/progressia/client/ClientProxy.java index e9ad7d3..1d154e7 100644 --- a/src/main/java/ru/windcorp/progressia/client/ClientProxy.java +++ b/src/main/java/ru/windcorp/progressia/client/ClientProxy.java @@ -32,6 +32,7 @@ import ru.windcorp.progressia.common.resource.ResourceManager; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.server.ServerState; import ru.windcorp.progressia.test.TestContent; +import ru.windcorp.progressia.test.TestMusicPlayer; public class ClientProxy implements Proxy { @@ -59,6 +60,8 @@ public class ClientProxy implements Proxy { ServerState.startServer(); ClientState.connectToLocalServer(); + + TestMusicPlayer.start(); } } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/AudioManager.java b/src/main/java/ru/windcorp/progressia/client/audio/AudioManager.java index 1647e29..49f2312 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/AudioManager.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/AudioManager.java @@ -23,6 +23,7 @@ import ru.windcorp.progressia.client.audio.backend.AudioReader; import ru.windcorp.progressia.client.audio.backend.Listener; import ru.windcorp.progressia.client.audio.backend.SoundType; import ru.windcorp.progressia.client.audio.backend.Speaker; +import ru.windcorp.progressia.common.resource.Resource; import static org.lwjgl.openal.AL11.*; import static org.lwjgl.openal.ALC10.*; @@ -40,7 +41,6 @@ public class AudioManager { private static List soundSpeakers = new ArrayList<>(SOUNDS_NUM); private static Speaker musicSpeaker; - private static ArrayList soundsBuffer = new ArrayList<>(); public static void initAL() { String defaultDeviceName = alcGetString( @@ -82,18 +82,6 @@ public class AudioManager { return speaker; } - private static SoundType findSoundType(String soundID) throws Exception { - for (SoundType s : soundsBuffer) { - if (s.getId().equals(soundID)) { - return s; - } - } - throw new Exception( - "ERROR: The selected sound is not loaded or" + - " not exists" - ); - } - public static Speaker initSpeaker(SoundType st) { Speaker speaker = getLastSpeaker(); try { @@ -103,21 +91,10 @@ public class AudioManager { } return speaker; } - - public static SoundType getSoundType(String id) { - SoundType st; - try { - st = findSoundType(id); - } catch (Exception ex) { - throw new RuntimeException(); - } - return st; - } - - public static Speaker initMusicSpeaker(String soundID) { + public static Speaker initMusicSpeaker(SoundType st) { try { - findSoundType(soundID).initSpeaker(musicSpeaker); + st.initSpeaker(musicSpeaker); } catch (Exception ex) { throw new RuntimeException(); } @@ -131,11 +108,11 @@ public class AudioManager { } } - public static void loadSound(String path, String id, AudioFormat format) { + public static void loadSound(Resource resource, String id, AudioFormat format) { if (format == AudioFormat.MONO) { - soundsBuffer.add(AudioReader.readAsMono(path, id)); + AudioRegistry.getInstance().register(AudioReader.readAsMono(resource, id)); } else { - soundsBuffer.add(AudioReader.readAsStereo(path, id)); + AudioRegistry.getInstance().register(AudioReader.readAsStereo(resource, id)); } } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/AudioRegistry.java b/src/main/java/ru/windcorp/progressia/client/audio/AudioRegistry.java new file mode 100644 index 0000000..3199622 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/audio/AudioRegistry.java @@ -0,0 +1,34 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program 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 + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ +package ru.windcorp.progressia.client.audio; + +import ru.windcorp.progressia.client.audio.backend.SoundType; +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; + +public class AudioRegistry extends NamespacedInstanceRegistry { + + private static final AudioRegistry INSTANCE = new AudioRegistry(); + + /** + * @return the instance + */ + public static AudioRegistry getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/audio/AudioSystem.java b/src/main/java/ru/windcorp/progressia/client/audio/AudioSystem.java index d41f6d4..24cc2de 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/AudioSystem.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/AudioSystem.java @@ -18,6 +18,8 @@ package ru.windcorp.progressia.client.audio; +import ru.windcorp.progressia.common.resource.ResourceManager; + public class AudioSystem { static public void initialize() { AudioManager.initAL(); @@ -28,7 +30,7 @@ public class AudioSystem { static void loadAudioData() { AudioManager.loadSound( - "assets/sounds/block_destroy_clap.ogg", + ResourceManager.getResource("assets/sounds/block_destroy_clap.ogg"), "Progressia:BlockDestroy", AudioFormat.MONO ); diff --git a/src/main/java/ru/windcorp/progressia/client/audio/Music.java b/src/main/java/ru/windcorp/progressia/client/audio/Music.java index d461d72..031b58e 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/Music.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/Music.java @@ -19,24 +19,33 @@ package ru.windcorp.progressia.client.audio; import glm.vec._3.Vec3; +import ru.windcorp.progressia.client.audio.backend.SoundType; +import ru.windcorp.progressia.client.audio.backend.Speaker; public class Music extends Sound { + + + public Music(SoundType soundType, int timeLength, float pitch, float gain) { + super(soundType, timeLength, new Vec3(), new Vec3(), pitch, gain); + } + + public Music(SoundType soundType) { + super(soundType); + } + + public Music(String id, int timeLength, float pitch, float gain) { + super(id, timeLength, new Vec3(), new Vec3(), pitch, gain); + } + public Music(String id) { super(id); } - public Music( - String id, - Vec3 velocity, - float pitch, - float gain - ) { - this(id); - super.velocity = velocity; - super.pitch = pitch; - super.gain = gain; + @Override + protected Speaker initSpeaker() { + return AudioManager.initMusicSpeaker(soundType); } @Override diff --git a/src/main/java/ru/windcorp/progressia/client/audio/Sound.java b/src/main/java/ru/windcorp/progressia/client/audio/Sound.java index 31dce8c..77f0c9e 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/Sound.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/Sound.java @@ -31,9 +31,13 @@ public class Sound { protected int timeLength = 0; protected SoundType soundType; + + public Sound(SoundType soundType) { + this.soundType = soundType; + } public Sound(String id) { - soundType = AudioManager.getSoundType(id); + this(AudioRegistry.getInstance().get(id)); } public Sound( @@ -50,9 +54,28 @@ public class Sound { this.pitch = pitch; this.gain = gain; } + + public Sound( + SoundType soundType, + int timeLength, + Vec3 position, + Vec3 velocity, + float pitch, + float gain + ) { + this(soundType); + this.position = position; + this.velocity = velocity; + this.pitch = pitch; + this.gain = gain; + } + + protected Speaker initSpeaker() { + return AudioManager.initSpeaker(soundType); + } public void play(boolean loop) { - Speaker speaker = AudioManager.initSpeaker(soundType); + Speaker speaker = initSpeaker(); speaker.setGain(gain); speaker.setPitch(pitch); speaker.setPosition(position); @@ -97,8 +120,8 @@ public class Sound { return pitch; } - public int getTimeLength() { - return soundType.getTimeLength(); + public double getDuration() { + return soundType.getDuration(); } } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/backend/AudioReader.java b/src/main/java/ru/windcorp/progressia/client/audio/backend/AudioReader.java index 2cbd1e2..9fa48e0 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/backend/AudioReader.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/backend/AudioReader.java @@ -33,13 +33,11 @@ public class AudioReader { } // TODO fix converting from mono-stereo - private static SoundType readAsSpecified(String path, String id, int format) { + private static SoundType readAsSpecified(Resource resource, String id, int format) { IntBuffer channelBuffer = BufferUtils.createIntBuffer(1); IntBuffer rateBuffer = BufferUtils.createIntBuffer(1); - Resource res = ResourceManager.getResource(path); - - ShortBuffer rawAudio = decodeVorbis(res, channelBuffer, rateBuffer); + ShortBuffer rawAudio = decodeVorbis(resource, channelBuffer, rateBuffer); return new SoundType( id, @@ -49,12 +47,12 @@ public class AudioReader { ); } - public static SoundType readAsMono(String path, String id) { - return readAsSpecified(path, id, AL_FORMAT_MONO16); + public static SoundType readAsMono(Resource resource, String id) { + return readAsSpecified(resource, id, AL_FORMAT_MONO16); } - public static SoundType readAsStereo(String path, String id) { - return readAsSpecified(path, id, AL_FORMAT_STEREO16); + public static SoundType readAsStereo(Resource resource, String id) { + return readAsSpecified(resource, id, AL_FORMAT_STEREO16); } private static ShortBuffer decodeVorbis( diff --git a/src/main/java/ru/windcorp/progressia/client/audio/backend/SoundType.java b/src/main/java/ru/windcorp/progressia/client/audio/backend/SoundType.java index 72b1219..cdb1954 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/backend/SoundType.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/backend/SoundType.java @@ -21,6 +21,9 @@ package ru.windcorp.progressia.client.audio.backend; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import java.nio.ShortBuffer; + +import org.lwjgl.openal.AL10; + import static org.lwjgl.openal.AL11.*; public class SoundType extends Namespaced { @@ -29,7 +32,7 @@ public class SoundType extends Namespaced { private int sampleRate; private int format; private int audioBuffer; - private int timeLength; + private double duration; public SoundType( String id, @@ -47,14 +50,14 @@ public class SoundType extends Namespaced { private void createAudioBuffer() { this.audioBuffer = alGenBuffers(); alBufferData(audioBuffer, format, rawAudio, sampleRate); - timeLength = rawAudio.limit() / sampleRate; + duration = rawAudio.limit() / (double) sampleRate / (format == AL10.AL_FORMAT_STEREO16 ? 2 : 1); } public void initSpeaker(Speaker speaker) { speaker.setAudioData(audioBuffer); } - public int getTimeLength() { - return timeLength; + public double getDuration() { + return duration; } } \ No newline at end of file diff --git a/src/main/java/ru/windcorp/progressia/client/audio/backend/Speaker.java b/src/main/java/ru/windcorp/progressia/client/audio/backend/Speaker.java index ea6b5ed..c649a6a 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/backend/Speaker.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/backend/Speaker.java @@ -120,6 +120,7 @@ public class Speaker { } public void setAudioData(int audioData) { + stop(); this.audioData = audioData; alSourcei(this.sourceData, AL_BUFFER, audioData); } diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLocalLambda.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLocalLambda.java new file mode 100644 index 0000000..b2ae739 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLocalLambda.java @@ -0,0 +1,53 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program 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 + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +package ru.windcorp.progressia.client.comms.controls; + +import java.util.function.Consumer; +import java.util.function.Predicate; + +import ru.windcorp.progressia.client.graphics.input.InputEvent; +import ru.windcorp.progressia.common.comms.controls.PacketControl; + +public class ControlTriggerLocalLambda extends ControlTriggerInputBased { + + private final Predicate predicate; + private final Consumer action; + + public ControlTriggerLocalLambda( + String id, + Predicate predicate, + Consumer action + ) { + super(id); + + this.predicate = predicate; + this.action = action; + } + + @Override + public PacketControl onInputEvent(InputEvent event) { + if (!predicate.test(event)) + return null; + + action.accept(event); + + return null; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java index 24ca620..2c0d61d 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java @@ -142,6 +142,96 @@ public class ControlTriggers { predicates ); } + + // + // + /// + /// + // + // + // + // + // + // + // + // + // + + public static ControlTriggerInputBased localOf( + String id, + Consumer action, + Predicate predicate + ) { + return new ControlTriggerLocalLambda(id, predicate, action); + } + + public static ControlTriggerInputBased localOf( + String id, + Runnable action, + Predicate predicate + ) { + return localOf( + id, + input -> action.run(), + predicate + ); + } + + @SafeVarargs + public static ControlTriggerInputBased localOf( + String id, + Class inputType, + Consumer action, + Predicate... predicates + ) { + return localOf( + id, + createCheckedAction(inputType, action), + createCheckedCompoundPredicate(inputType, predicates) + ); + } + + @SafeVarargs + public static ControlTriggerInputBased localOf( + String id, + Class inputType, + Runnable action, + Predicate... predicates + ) { + return localOf( + id, + inputType, + input -> action.run(), + predicates + ); + } + + @SafeVarargs + public static ControlTriggerInputBased localOf( + String id, + Consumer action, + Predicate... predicates + ) { + return localOf( + id, + InputEvent.class, + action, + predicates + ); + } + + @SafeVarargs + public static ControlTriggerInputBased localOf( + String id, + Runnable action, + Predicate... predicates + ) { + return of( + id, + input -> action.run(), + predicates + ); + } private static BiConsumer createCheckedDataWriter( Class inputType, @@ -149,6 +239,13 @@ public class ControlTriggers { ) { return (inputEvent, control) -> dataWriter.accept(inputType.cast(inputEvent), control); } + + private static Consumer createCheckedAction( + Class inputType, + Consumer action + ) { + return inputEvent -> action.accept(inputType.cast(inputEvent)); + } private static Predicate createCheckedCompoundPredicate( Class inputType, diff --git a/src/main/java/ru/windcorp/progressia/common/resource/ClasspathResourceReader.java b/src/main/java/ru/windcorp/progressia/common/resource/ClasspathResourceReader.java new file mode 100644 index 0000000..485efee --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/resource/ClasspathResourceReader.java @@ -0,0 +1,31 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program 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 + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ +package ru.windcorp.progressia.common.resource; + +import java.io.InputStream; + +import ru.windcorp.progressia.Progressia; + +public class ClasspathResourceReader implements ResourceReader { + + @Override + public InputStream read(String name) { + return Progressia.class.getClassLoader().getResourceAsStream(name); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/resource/FilesystemResourceReader.java b/src/main/java/ru/windcorp/progressia/common/resource/FilesystemResourceReader.java new file mode 100644 index 0000000..38b30ba --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/resource/FilesystemResourceReader.java @@ -0,0 +1,36 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program 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 + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ +package ru.windcorp.progressia.common.resource; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class FilesystemResourceReader implements ResourceReader { + + @Override + public InputStream read(String name) { + try { + return Files.newInputStream(Paths.get(name)); + } catch (IOException e) { + return null; + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/resource/Resource.java b/src/main/java/ru/windcorp/progressia/common/resource/Resource.java index 90acc5b..6cd4d32 100644 --- a/src/main/java/ru/windcorp/progressia/common/resource/Resource.java +++ b/src/main/java/ru/windcorp/progressia/common/resource/Resource.java @@ -30,19 +30,24 @@ import org.lwjgl.BufferUtils; import com.google.common.io.ByteStreams; import com.google.common.io.CharStreams; -import ru.windcorp.progressia.Progressia; import ru.windcorp.progressia.common.util.Named; import ru.windcorp.progressia.common.util.crash.CrashReports; public class Resource extends Named { + + private final ResourceReader resourceReader; - public Resource(String name) { + public Resource(String name, ResourceReader resourceReader) { super(name); + this.resourceReader = resourceReader; } public InputStream getInputStream() { - // TODO Do proper resource lookup - return Progressia.class.getClassLoader().getResourceAsStream(getName()); + return getResourceReader().read(getName()); + } + + public ResourceReader getResourceReader() { + return resourceReader; } public Reader getReader() { diff --git a/src/main/java/ru/windcorp/progressia/common/resource/ResourceManager.java b/src/main/java/ru/windcorp/progressia/common/resource/ResourceManager.java index 60b1698..33db64d 100644 --- a/src/main/java/ru/windcorp/progressia/common/resource/ResourceManager.java +++ b/src/main/java/ru/windcorp/progressia/common/resource/ResourceManager.java @@ -19,9 +19,16 @@ package ru.windcorp.progressia.common.resource; public class ResourceManager { + + private static final ResourceReader CLASSPATH_READER = new ClasspathResourceReader(); + private static final ResourceReader FILESYSTEM_READER = new FilesystemResourceReader(); public static Resource getResource(String name) { - return new Resource(name); + return new Resource(name, CLASSPATH_READER); + } + + public static Resource getFileResource(String name) { + return new Resource(name, FILESYSTEM_READER); } public static Resource getTextureResource(String name) { diff --git a/src/main/java/ru/windcorp/progressia/common/resource/ResourceReader.java b/src/main/java/ru/windcorp/progressia/common/resource/ResourceReader.java new file mode 100644 index 0000000..1f95f2c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/resource/ResourceReader.java @@ -0,0 +1,26 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program 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 + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ +package ru.windcorp.progressia.common.resource; + +import java.io.InputStream; + +public interface ResourceReader { + + InputStream read(String name); + +} diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index c7ff429..dad5496 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -287,6 +287,15 @@ public class TestContent { ) ); logic.register(ControlLogic.of("Test:PlaceTile", TestContent::onTilePlaceReceived)); + + triggers.register( + ControlTriggers.localOf( + "Test:StartNextMusic", + KeyEvent.class, + TestMusicPlayer::startNextNow, + KeyMatcher.of(GLFW.GLFW_KEY_M).matcher() + ) + ); } private static void register(BlockData x) { diff --git a/src/main/java/ru/windcorp/progressia/test/TestMusicPlayer.java b/src/main/java/ru/windcorp/progressia/test/TestMusicPlayer.java new file mode 100644 index 0000000..1674d5b --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/TestMusicPlayer.java @@ -0,0 +1,152 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program 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 + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ +package ru.windcorp.progressia.test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Random; + +import org.apache.logging.log4j.LogManager; + +import ru.windcorp.progressia.client.audio.AudioFormat; +import ru.windcorp.progressia.client.audio.AudioManager; +import ru.windcorp.progressia.client.audio.AudioRegistry; +import ru.windcorp.progressia.client.audio.Music; +import ru.windcorp.progressia.client.audio.Sound; +import ru.windcorp.progressia.client.audio.backend.SoundType; +import ru.windcorp.progressia.common.resource.ResourceManager; +import ru.windcorp.progressia.common.util.crash.CrashReports; + +public class TestMusicPlayer implements Runnable { + + private static final int MIN_SILENCE = 15 * 1000; // 15 seconds + private static final int MAX_SILENCE = 60 * 1000; // one minute + + private static TestMusicPlayer instance = null; + + private final List compositions = new ArrayList<>(); + + private final Random random = new Random(); + private long nextStart; + private Sound lastStarted = null; + + public TestMusicPlayer() { + this.nextStart = System.currentTimeMillis(); + + instance = this; + } + + public static void start() { + Thread thread = new Thread(new TestMusicPlayer(), "Music Thread"); + thread.setDaemon(true); + thread.start(); + } + + @Override + public void run() { + loadCompositions(); + + if (compositions.isEmpty()) { + LogManager.getLogger().warn("No music found"); + return; + } + + while (true) { + + try { + synchronized (this) { + while (true) { + long now = System.currentTimeMillis(); + if (nextStart > now) { + wait(nextStart - now); + } else { + break; + } + } + } + } catch (InterruptedException e) { + LogManager.getLogger().warn("Received interrupt in music thread, terminating thread..."); + return; + } + + startNextComposition(); + + } + } + + private void loadCompositions() { + try { + + Path directory = Paths.get("music"); + + if (!Files.isDirectory(directory)) { + Files.createDirectories(directory); + } + + Iterator it = Files.walk(directory).filter(Files::isRegularFile).iterator(); + int i = 0; + + while (it.hasNext()) { + String file = it.next().toString(); + if (!file.endsWith(".ogg") && !file.endsWith(".oga")) { + LogManager.getLogger().warn("Skipping " + file + ": not .ogg nor .oga"); + } + + String id = "Progressia:Music" + (i++); + + AudioManager.loadSound(ResourceManager.getFileResource(file.toString()), id, AudioFormat.STEREO); + SoundType composition = AudioRegistry.getInstance().get(id); + compositions.add(composition); + + LogManager.getLogger().info("Loaded " + file); + } + + } catch (IOException e) { + throw CrashReports.report(e, "Could not load music"); + } + } + + private synchronized void startNextComposition() { + int index = random.nextInt(compositions.size()); + SoundType composition = compositions.get(index); + + long now = System.currentTimeMillis(); + long durationInMs = (long) (composition.getDuration() * 1000); + long silence = random.nextInt(MAX_SILENCE - MIN_SILENCE) + MIN_SILENCE; + + nextStart = now + durationInMs + silence; + + lastStarted = new Music(composition); + lastStarted.play(false); + } + + public static void startNextNow() { + if (instance == null) return; + + synchronized (instance) { + instance.nextStart = System.currentTimeMillis(); + instance.notifyAll(); + } + } + +}