Added a crude music player and fixed a lot of OpenAL stuff
- Game will now play all Vorbis files in music/ directory (at runtime) - Random order with random pauses (15 to 60 sec) - Force start by pressing M - Added AudioRegistry for performance - Speakers now can change data correctly - Added ResourceReaders - Classpath and Filesystem for now - Added local controls. Use with ControlTriggers.localOf(...) NB: No actual music files included (yet). Place them in music/ directory of the game directory (e.g. in <project>/run/music).
This commit is contained in:
parent
9d7f69892b
commit
c49fdfa5ff
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<Speaker> soundSpeakers = new ArrayList<>(SOUNDS_NUM);
|
||||
private static Speaker musicSpeaker;
|
||||
private static ArrayList<SoundType> 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<SoundType> {
|
||||
|
||||
private static final AudioRegistry INSTANCE = new AudioRegistry();
|
||||
|
||||
/**
|
||||
* @return the instance
|
||||
*/
|
||||
public static AudioRegistry getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -120,6 +120,7 @@ public class Speaker {
|
||||
}
|
||||
|
||||
public void setAudioData(int audioData) {
|
||||
stop();
|
||||
this.audioData = audioData;
|
||||
alSourcei(this.sourceData, AL_BUFFER, audioData);
|
||||
}
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<InputEvent> predicate;
|
||||
private final Consumer<InputEvent> action;
|
||||
|
||||
public ControlTriggerLocalLambda(
|
||||
String id,
|
||||
Predicate<InputEvent> predicate,
|
||||
Consumer<InputEvent> 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;
|
||||
}
|
||||
|
||||
}
|
@ -142,6 +142,96 @@ public class ControlTriggers {
|
||||
predicates
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
///
|
||||
///
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
public static ControlTriggerInputBased localOf(
|
||||
String id,
|
||||
Consumer<InputEvent> action,
|
||||
Predicate<InputEvent> predicate
|
||||
) {
|
||||
return new ControlTriggerLocalLambda(id, predicate, action);
|
||||
}
|
||||
|
||||
public static ControlTriggerInputBased localOf(
|
||||
String id,
|
||||
Runnable action,
|
||||
Predicate<InputEvent> predicate
|
||||
) {
|
||||
return localOf(
|
||||
id,
|
||||
input -> action.run(),
|
||||
predicate
|
||||
);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <I extends InputEvent> ControlTriggerInputBased localOf(
|
||||
String id,
|
||||
Class<I> inputType,
|
||||
Consumer<I> action,
|
||||
Predicate<I>... predicates
|
||||
) {
|
||||
return localOf(
|
||||
id,
|
||||
createCheckedAction(inputType, action),
|
||||
createCheckedCompoundPredicate(inputType, predicates)
|
||||
);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <I extends InputEvent> ControlTriggerInputBased localOf(
|
||||
String id,
|
||||
Class<I> inputType,
|
||||
Runnable action,
|
||||
Predicate<I>... predicates
|
||||
) {
|
||||
return localOf(
|
||||
id,
|
||||
inputType,
|
||||
input -> action.run(),
|
||||
predicates
|
||||
);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static ControlTriggerInputBased localOf(
|
||||
String id,
|
||||
Consumer<InputEvent> action,
|
||||
Predicate<InputEvent>... predicates
|
||||
) {
|
||||
return localOf(
|
||||
id,
|
||||
InputEvent.class,
|
||||
action,
|
||||
predicates
|
||||
);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <I extends InputEvent> ControlTriggerInputBased localOf(
|
||||
String id,
|
||||
Runnable action,
|
||||
Predicate<InputEvent>... predicates
|
||||
) {
|
||||
return of(
|
||||
id,
|
||||
input -> action.run(),
|
||||
predicates
|
||||
);
|
||||
}
|
||||
|
||||
private static <I extends InputEvent> BiConsumer<InputEvent, ControlData> createCheckedDataWriter(
|
||||
Class<I> inputType,
|
||||
@ -149,6 +239,13 @@ public class ControlTriggers {
|
||||
) {
|
||||
return (inputEvent, control) -> dataWriter.accept(inputType.cast(inputEvent), control);
|
||||
}
|
||||
|
||||
private static <I extends InputEvent> Consumer<InputEvent> createCheckedAction(
|
||||
Class<I> inputType,
|
||||
Consumer<I> action
|
||||
) {
|
||||
return inputEvent -> action.accept(inputType.cast(inputEvent));
|
||||
}
|
||||
|
||||
private static <I extends InputEvent> Predicate<InputEvent> createCheckedCompoundPredicate(
|
||||
Class<I> inputType,
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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() {
|
||||
|
@ -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) {
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package ru.windcorp.progressia.common.resource;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface ResourceReader {
|
||||
|
||||
InputStream read(String name);
|
||||
|
||||
}
|
@ -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) {
|
||||
|
152
src/main/java/ru/windcorp/progressia/test/TestMusicPlayer.java
Normal file
152
src/main/java/ru/windcorp/progressia/test/TestMusicPlayer.java
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<SoundType> 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<Path> 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user