feat(io): MusicController + MusicBackend (testable music logic)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
package thb.jeanluc.adventure.io;
|
||||
|
||||
/** Raw audio operations — the only part that touches sound hardware. */
|
||||
public interface MusicBackend {
|
||||
|
||||
/** Fade the current track out, then start {@code track} (looping) and fade in to {@code gainDb}. */
|
||||
void fadeTo(String track, float gainDb);
|
||||
|
||||
/** Fade the current track out and stop. */
|
||||
void fadeOut();
|
||||
|
||||
/** Set the playback volume immediately. */
|
||||
void setGainDb(float gainDb);
|
||||
|
||||
/** Stop playback and release resources. */
|
||||
void shutdown();
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package thb.jeanluc.adventure.io;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Frontend-agnostic music decision logic. Idempotent per track (never restarts
|
||||
* the same track), fades to silence on a null/blank track, and honours the
|
||||
* {@link MusicLevel} (OFF disables playback). Delegates raw operations to a
|
||||
* {@link MusicBackend}.
|
||||
*/
|
||||
public final class MusicController {
|
||||
|
||||
private final MusicBackend backend;
|
||||
private MusicLevel level = MusicLevel.MEDIUM;
|
||||
private String current; // currently selected track, or null = silence
|
||||
|
||||
public MusicController(MusicBackend backend) {
|
||||
this.backend = backend;
|
||||
}
|
||||
|
||||
/** Called per turn with the current room's music field (may be null/blank). */
|
||||
public void room(String track) {
|
||||
if (!level.isOn()) {
|
||||
return;
|
||||
}
|
||||
String next = (track == null || track.isBlank()) ? null : track;
|
||||
if (Objects.equals(next, current)) {
|
||||
return;
|
||||
}
|
||||
current = next;
|
||||
if (next == null) {
|
||||
backend.fadeOut();
|
||||
} else {
|
||||
backend.fadeTo(next, level.gainDb());
|
||||
}
|
||||
}
|
||||
|
||||
/** Applies a new music level (volume / off). */
|
||||
public void level(MusicLevel newLevel) {
|
||||
this.level = newLevel;
|
||||
if (!newLevel.isOn()) {
|
||||
backend.fadeOut();
|
||||
current = null; // turning back on replays on the next room() call
|
||||
} else {
|
||||
backend.setGainDb(newLevel.gainDb());
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
backend.shutdown();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user