Remove unnecessary data class

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-15 20:25:28 +01:00
parent 192b69f1d1
commit b3b909a9b6
6 changed files with 62 additions and 40 deletions

View File

@@ -1,3 +1,5 @@
import 'dart:typed_data';
import 'package:audioplayers/audioplayers.dart';
import 'package:wolf_3d_data_types/wolf_3d_data_types.dart';
import 'package:wolf_3d_synth/src/imf_renderer.dart';
@@ -5,20 +7,38 @@ import 'package:wolf_3d_synth/src/imf_renderer.dart';
class WolfAudio {
bool _isInitialized = false;
// --- Music State ---
final AudioPlayer _musicPlayer = AudioPlayer();
// --- SFX State ---
// A pool of players to allow overlapping sound effects.
static const int _maxSfxChannels = 8;
final List<AudioPlayer> _sfxPlayers = [];
int _currentSfxIndex = 0;
WolfensteinData? activeGame;
/// Initializes the audio engine.
/// Initializes the audio engine and pre-allocates the SFX pool.
Future<void> init() async {
if (_isInitialized) return;
try {
// audioplayers doesn't require complex global initialization like SoLoud,
// but setting the audio context can be useful for mobile platforms later.
// Set music player mode
await _musicPlayer.setPlayerMode(PlayerMode.mediaPlayer);
// Initialize the SFX pool
for (int i = 0; i < _maxSfxChannels; i++) {
final player = AudioPlayer();
// lowLatency mode is highly recommended for short game sounds
await player.setPlayerMode(PlayerMode.lowLatency);
await player.setReleaseMode(ReleaseMode.stop);
_sfxPlayers.add(player);
}
_isInitialized = true;
print("WolfAudio: AudioPlayers initialized successfully.");
print(
"WolfAudio: AudioPlayers initialized successfully with $_maxSfxChannels SFX channels.",
);
} catch (e) {
print("WolfAudio: Failed to initialize AudioPlayers - $e");
}
@@ -28,6 +48,13 @@ class WolfAudio {
void dispose() {
stopMusic();
_musicPlayer.dispose();
for (final player in _sfxPlayers) {
player.stop();
player.dispose();
}
_sfxPlayers.clear();
_isInitialized = false;
}
@@ -35,72 +62,73 @@ class WolfAudio {
// MUSIC MANAGEMENT
// ==========================================
/// Renders and plays a specific IMF music track.
Future<void> playMusic(ImfMusic track, {bool looping = true}) async {
if (!_isInitialized) return;
// Stop currently playing music to prevent overlap
await stopMusic();
try {
// Render hardware instructions into PCM and wrap in WAV
final pcmSamples = ImfRenderer.render(track);
final wavBytes = ImfRenderer.createWavFile(pcmSamples);
// Configure looping behavior
await _musicPlayer.setReleaseMode(
looping ? ReleaseMode.loop : ReleaseMode.stop,
);
// Play the generated WAV file directly from memory
await _musicPlayer.play(BytesSource(wavBytes));
} catch (e) {
print("WolfAudio: Error playing music track - $e");
}
}
/// Halts playback for the current track.
Future<void> stopMusic() async {
if (!_isInitialized) return;
await _musicPlayer.stop();
}
/// Pauses the current track.
Future<void> pauseMusic() async {
if (_isInitialized) {
await _musicPlayer.pause();
}
if (_isInitialized) await _musicPlayer.pause();
}
/// Resumes a paused track.
Future<void> resumeMusic() async {
if (_isInitialized) {
await _musicPlayer.resume();
}
if (_isInitialized) await _musicPlayer.resume();
}
Future<void> playMenuMusic() async {
final data = activeGame;
// We can't play if data isn't set or doesn't have enough tracks
if (data == null || data.music.length <= 1) return;
// Track 1 is the menu theme in both Shareware and Retail
await playMusic(data.music[1]);
}
/// Plays the specific track assigned to a WolfLevel.
Future<void> playLevelMusic(WolfLevel level) async {
final data = activeGame;
if (data == null || data.music.isEmpty) return;
final index = level.musicIndex;
if (index < data.music.length) {
await playMusic(data.music[index]);
} else {
print(
"WolfAudio: Warning - Track index $index out of bounds for level ${level.name}.",
);
print("WolfAudio: Warning - Track index $index out of bounds.");
}
}
// ==========================================
// SFX MANAGEMENT
// ==========================================
/// Plays a sound effect from a WAV byte array using the round-robin pool.
Future<void> playSfx(Uint8List wavBytes) async {
if (!_isInitialized) return;
try {
// Grab the next available player in the pool
final player = _sfxPlayers[_currentSfxIndex];
// Move to the next index, looping back to 0 if we hit the max
_currentSfxIndex = (_currentSfxIndex + 1) % _maxSfxChannels;
// Play the sound (this interrupts whatever this specific channel was playing)
await player.play(BytesSource(wavBytes));
} catch (e) {
print("WolfAudio: Error playing SFX - $e");
}
}
}