diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/metronome/MetronomePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/metronome/MetronomePlugin.java index 9a0b709aab..9c2bad4654 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/metronome/MetronomePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/metronome/MetronomePlugin.java @@ -25,21 +25,32 @@ */ package net.runelite.client.plugins.metronome; +import net.runelite.api.events.ConfigChanged; +import net.runelite.client.eventbus.Subscribe; import com.google.inject.Provides; + import javax.inject.Inject; + import net.runelite.api.Client; import net.runelite.api.SoundEffectID; import net.runelite.api.events.GameTick; import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.FloatControl; +import java.io.File; + @PluginDescriptor( - name = "Metronome", - description = "Play a sound on a specified tick to aid in efficient skilling", - tags = {"skilling", "tick", "timers"}, - enabledByDefault = false + name = "Metronome extended", + description = "Play sounds in a customisable pattern", + tags = {"skilling", "tick", "timers"}, + enabledByDefault = false ) public class MetronomePlugin extends Plugin { @@ -50,7 +61,9 @@ public class MetronomePlugin extends Plugin private MetronomePluginConfiguration config; private int tickCounter = 0; - private boolean shouldTock = false; + private int tockCounter = 0; + private Clip tickClip; + private Clip tockClip; @Provides MetronomePluginConfiguration provideConfig(ConfigManager configManager) @@ -58,6 +71,88 @@ public class MetronomePlugin extends Plugin return configManager.getConfig(MetronomePluginConfiguration.class); } + private Clip GetAudioClip(String path) + { + File audioFile = new File(path); + if (audioFile.exists()) + { + AudioInputStream audioStream = null; + try + { + audioStream = AudioSystem.getAudioInputStream(audioFile); + } + catch (Exception e) + { + return null; + } + AudioFormat audioFormat = audioStream.getFormat(); + DataLine.Info audioInfo = new DataLine.Info(Clip.class, audioFormat); + try + { + Clip audioClip = AudioSystem.getClip(); + audioClip.open(audioStream); + FloatControl gainControl = (FloatControl) audioClip.getControl(FloatControl.Type.MASTER_GAIN); + float gainValue = (((float) config.volume()) * 40f / 100f) - 35f; + gainControl.setValue(gainValue); + return audioClip; + } + catch (Exception e) + { + return null; + } + } + return null; + } + + @Override + protected void startUp() + { + tickClip = GetAudioClip(config.tickPath()); + tockClip = GetAudioClip(config.tockPath()); + } + + @Override + protected void shutDown() + { + if (tickClip != null) + { + tickClip.close(); + } + if (tockClip != null) + { + tockClip.close(); + } + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getKey().equals("volume")) + { + float gainValue = (((float) config.volume()) * 40f / 100f) - 35f; + FloatControl gainControlTick = (FloatControl) tickClip.getControl(FloatControl.Type.MASTER_GAIN); + gainControlTick.setValue(gainValue); + FloatControl gainControlTock = (FloatControl) tockClip.getControl(FloatControl.Type.MASTER_GAIN); + gainControlTock.setValue(gainValue); + } + if (event.getKey().equals("tickSoundFilePath")) + { + if (tickClip != null) + { + tickClip.close(); + } + tickClip = GetAudioClip(config.tickPath()); + } + if (event.getKey().equals("tockSoundFilePath")) + { + if (tockClip != null) + { + tockClip.close(); + } + tockClip = GetAudioClip(config.tockPath()); + } + } + @Subscribe public void onGameTick(GameTick tick) { @@ -66,17 +161,40 @@ public class MetronomePlugin extends Plugin return; } - if (++tickCounter % config.tickCount() == 0) + if ((++tickCounter + config.tickOffset()) % config.tickCount() == 0) { - if (config.enableTock() && shouldTock) + if (++tockCounter % config.tockNumber() == 0 & config.enableTock()) { - client.playSoundEffect(SoundEffectID.GE_DECREMENT_PLOP); + if (tockClip == null) + { + client.playSoundEffect(SoundEffectID.GE_INCREMENT_PLOP); + } + else + { + if (tockClip.isRunning()) + { + tockClip.stop(); + } + tockClip.setFramePosition(0); + tockClip.start(); + } } else { - client.playSoundEffect(SoundEffectID.GE_INCREMENT_PLOP); + if (tickClip == null) + { + client.playSoundEffect(SoundEffectID.GE_DECREMENT_PLOP); + } + else + { + if (tickClip.isRunning()) + { + tickClip.stop(); + } + tickClip.setFramePosition(0); + tickClip.start(); + } } - shouldTock = !shouldTock; } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/metronome/MetronomePluginConfiguration.java b/runelite-client/src/main/java/net/runelite/client/plugins/metronome/MetronomePluginConfiguration.java index cb2ff60889..cfd573b98a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/metronome/MetronomePluginConfiguration.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/metronome/MetronomePluginConfiguration.java @@ -28,15 +28,15 @@ package net.runelite.client.plugins.metronome; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Range; -@ConfigGroup("metronome") +@ConfigGroup("metronomeExtended") public interface MetronomePluginConfiguration extends Config { @ConfigItem( - keyName = "tickCount", - name = "Tick count", - description = "Configures the tick on which a sound will be played", - position = 2 + keyName = "tickCount", + name = "Tick count", + description = "Configures the number of game ticks between metronome sounds" ) default int tickCount() { @@ -44,13 +44,66 @@ public interface MetronomePluginConfiguration extends Config } @ConfigItem( - keyName = "enableTock", - name = "Enable tock (alternating) sound", - description = "Toggles whether to play two alternating sounds", - position = 3 + keyName = "enableTock", + name = "Enable tock (alternating) sound", + description = "Toggles whether to play \"tock\" sounds" ) default boolean enableTock() { return false; } + + @ConfigItem( + keyName = "tockNumber", + name = "Tock every nth \"tick\"", + description = "Configures how many \"ticks\" between each \"tock\"" + ) + default int tockNumber() + { + return 2; + } + + @ConfigItem( + keyName = "tickOffset", + name = "Offset", + description = "Amount of ticks to offset the metronome (only useful for \"tocks\")" + ) + default int tickOffset() + { + return 0; + } + + @ConfigItem( + keyName = "tickSoundFilePath", + name = "Tick .wav file path", + description = "The path to the file to be used for \"tick\" sounds (short .wav only)" + ) + default String tickPath() + { + return ""; + } + + @ConfigItem( + keyName = "tockSoundFilePath", + name = "Tock .wav file path", + description = "The path to the file to be used for \"tock\" sounds (short .wav only)" + ) + default String tockPath() + { + return ""; + } + + @Range( + min = 0, + max = 100 + ) + @ConfigItem( + keyName = "volume", + name = "Volume modification", + description = "Configures tick/tock volume; only effects custom sounds." + ) + default int volume() + { + return 35; + } }