From 000af5dca2805d68affe5ac1bd9f1e7ec778e7e6 Mon Sep 17 00:00:00 2001 From: AShiningRay Date: Mon, 24 Feb 2025 20:10:43 -0300 Subject: [PATCH] Manager: Cap the playTone() duration to a minimum of 50ms. Some Karma Studios games use a ludicrously low value of 10ms for its notes, which is barely enough for Java to start playing them, so use a baseline of 50ms so that in all cases, they're audible. Related to #50. --- src/javax/microedition/media/Manager.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/javax/microedition/media/Manager.java b/src/javax/microedition/media/Manager.java index 6698312b..25c4368a 100644 --- a/src/javax/microedition/media/Manager.java +++ b/src/javax/microedition/media/Manager.java @@ -178,23 +178,31 @@ public static void playTone(int note, int duration, int volume) throws MediaExce if(Mobile.useCustomMidi && !hasLoadedToneSynth) { dedicatedTonePlayer.loadAllInstruments(customSoundfont); hasLoadedToneSynth = true; } dedicatedToneChannel = dedicatedTonePlayer.getChannels()[0]; + dedicatedToneChannel.programChange(80); // Set it to use the square wave instrument, just so all tones formats are using the same } catch (MidiUnavailableException e) { Mobile.log(Mobile.LOG_ERROR, Manager.class.getPackage().getName() + "." + Manager.class.getSimpleName() + ": " + "Couldn't open Tone Player: " + e.getMessage()); return;} } + else + { + for (int stopNote = 0; stopNote <= 127; stopNote++) { dedicatedToneChannel.noteOff(note);} + } + + // Notes that are too short can't even be heard in FreeJ2ME (some Karma Studios games use 10ms for sound, which is barely enough time for the media to start playing). A reasonable minimum duration is 50ms. + if(duration < 50) { Mobile.log(Mobile.LOG_DEBUG, Manager.class.getPackage().getName() + "." + Manager.class.getSimpleName() + ": " + "Tone duration too short (" + duration + " ms), changing to the 50ms min."); } + final int effectiveDuration = (duration < 50 ? 50 : duration); - dedicatedToneChannel.programChange(80); // Set it to use the square wave instrument, just so all tones formats are using the same /* * There's no need to calculate the note frequency as per the MIDP Manager docs, * they are pretty much the note numbers used by Java's Built-in MIDI library. * Just play the note straight away, mapping the volume from 0-100 to 0-127. */ dedicatedToneChannel.controlChange(7, volume * 127 / 100); - dedicatedToneChannel.noteOn(note, duration); // Make the decay just long enough for the note not to fade shorter than expected + dedicatedToneChannel.noteOn(note, effectiveDuration); // Make the decay just long enough for the note not to fade shorter than expected /* Since it has to be non-blocking, wait for the specified duration in a separate Thread before stopping the note. */ new Thread(() -> { - try { Thread.sleep(duration); } + try { Thread.sleep(effectiveDuration); } catch (InterruptedException e) { Mobile.log(Mobile.LOG_ERROR, Manager.class.getPackage().getName() + "." + Manager.class.getSimpleName() + ": " + "Failed to keep playing note for its specified duration: " + e.getMessage()); } dedicatedToneChannel.noteOff(note); }).start();