mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2024-10-31 19:44:20 +00:00
song state save/restore
This commit is contained in:
parent
a4f0d8dfa4
commit
510439d9ec
|
@ -9,7 +9,7 @@ use crate::engine_constants::EngineConstants;
|
|||
use crate::ggez::{Context, filesystem, GameResult};
|
||||
use crate::ggez::GameError::AudioError;
|
||||
use crate::sound::organya::Song;
|
||||
use crate::sound::playback::PlaybackEngine;
|
||||
use crate::sound::playback::{PlaybackEngine, SavedPlaybackState};
|
||||
use crate::sound::wave_bank::SoundBank;
|
||||
use crate::str;
|
||||
|
||||
|
@ -101,20 +101,39 @@ impl SoundManager {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(song_name) = SONGS.get(song_id) {
|
||||
if song_id == 0 {
|
||||
log::info!("Stopping BGM");
|
||||
|
||||
self.current_song_id = 0;
|
||||
self.tx.send(PlaybackMessage::Stop)?;
|
||||
} else if let Some(song_name) = SONGS.get(song_id) {
|
||||
let org = organya::Song::load_from(filesystem::open(ctx, ["/base/Org/", &song_name.to_lowercase(), ".org"].join(""))?)?;
|
||||
log::info!("Playing song: {}", song_name);
|
||||
log::info!("Playing BGM: {}", song_name);
|
||||
|
||||
self.current_song_id = song_id;
|
||||
self.tx.send(PlaybackMessage::PlaySong(org));
|
||||
self.tx.send(PlaybackMessage::PlaySong(Box::new(org)))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn save_state(&mut self) -> GameResult {
|
||||
self.tx.send(PlaybackMessage::SaveState)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn restore_state(&mut self) -> GameResult {
|
||||
self.tx.send(PlaybackMessage::RestoreState)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
enum PlaybackMessage {
|
||||
Stop,
|
||||
PlaySong(Song),
|
||||
PlaySong(Box<Song>),
|
||||
SaveState,
|
||||
RestoreState,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
|
@ -130,7 +149,7 @@ fn run<T>(rx: Receiver<PlaybackMessage>, bank: SoundBank,
|
|||
let sample_rate = config.sample_rate.0 as f32;
|
||||
let channels = config.channels as usize;
|
||||
let mut state = PlaybackState::Stopped;
|
||||
let mut new_song: Option<Song> = None;
|
||||
let mut saved_state: Option<SavedPlaybackState> = None;
|
||||
let mut engine = PlaybackEngine::new(Song::empty(), &bank);
|
||||
|
||||
log::info!("Audio format: {} {}", sample_rate, channels);
|
||||
|
@ -148,7 +167,7 @@ fn run<T>(rx: Receiver<PlaybackMessage>, bank: SoundBank,
|
|||
move |data: &mut [T], _: &cpal::OutputCallbackInfo| {
|
||||
match rx.try_recv() {
|
||||
Ok(PlaybackMessage::PlaySong(song)) => {
|
||||
engine.start_song(song, &bank);
|
||||
engine.start_song(*song, &bank);
|
||||
|
||||
for i in &mut buf[0..frames] { *i = 0x8080 };
|
||||
frames = engine.render_to(&mut buf);
|
||||
|
@ -156,6 +175,21 @@ fn run<T>(rx: Receiver<PlaybackMessage>, bank: SoundBank,
|
|||
|
||||
state = PlaybackState::Playing;
|
||||
}
|
||||
Ok(PlaybackMessage::SaveState) => {
|
||||
saved_state = Some(engine.get_state());
|
||||
}
|
||||
Ok(PlaybackMessage::RestoreState) => {
|
||||
if saved_state.is_some() {
|
||||
engine.set_state(saved_state.clone().unwrap(), &bank);
|
||||
saved_state = None;
|
||||
|
||||
for i in &mut buf[0..frames] { *i = 0x8080 };
|
||||
frames = engine.render_to(&mut buf);
|
||||
index = 0;
|
||||
|
||||
state = PlaybackState::Playing;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,20 @@ pub struct PlaybackEngine {
|
|||
pub loops: usize,
|
||||
}
|
||||
|
||||
pub struct PlaybackState {
|
||||
pub struct SavedPlaybackState {
|
||||
song: Organya,
|
||||
play_pos: i32,
|
||||
}
|
||||
|
||||
impl Clone for SavedPlaybackState {
|
||||
fn clone(&self) -> SavedPlaybackState {
|
||||
SavedPlaybackState {
|
||||
song: self.song.clone(),
|
||||
play_pos: self.play_pos,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlaybackEngine {
|
||||
pub fn new(song: Organya, samples: &SoundBank) -> Self {
|
||||
|
||||
|
@ -98,14 +107,14 @@ impl PlaybackEngine {
|
|||
self.frames_per_tick = (sample_rate / 1000) * self.song.time.wait as usize;
|
||||
}
|
||||
|
||||
pub fn get_state(&self) -> PlaybackState {
|
||||
PlaybackState {
|
||||
pub fn get_state(&self) -> SavedPlaybackState {
|
||||
SavedPlaybackState {
|
||||
song: self.song.clone(),
|
||||
play_pos: self.play_pos,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_state(&mut self, state: PlaybackState, samples: &SoundBank) {
|
||||
pub fn set_state(&mut self, state: SavedPlaybackState, samples: &SoundBank) {
|
||||
self.start_song(state.song, samples);
|
||||
self.play_pos = state.play_pos;
|
||||
}
|
||||
|
|
|
@ -628,14 +628,25 @@ impl TextScriptVM {
|
|||
OpCode::CMU => {
|
||||
let song_id = read_cur_varint(&mut cursor)? as usize;
|
||||
state.sound_manager.play_song(song_id, &state.constants, ctx)?;
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::FMU => {
|
||||
state.sound_manager.save_state()?;
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::RMU => {
|
||||
state.sound_manager.restore_state()?;
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
// unimplemented opcodes
|
||||
// Zero operands
|
||||
OpCode::AEp | OpCode::CAT | OpCode::CIL | OpCode::CPS |
|
||||
OpCode::CRE | OpCode::CSS | OpCode::ESC | OpCode::FLA | OpCode::FMU |
|
||||
OpCode::CRE | OpCode::CSS | OpCode::ESC | OpCode::FLA |
|
||||
OpCode::INI | OpCode::LDP | OpCode::MLP | OpCode::MNA |
|
||||
OpCode::RMU | OpCode::SAT | OpCode::SLP | OpCode::SPS |
|
||||
OpCode::SAT | OpCode::SLP | OpCode::SPS |
|
||||
OpCode::STC | OpCode::SVP | OpCode::TUR | OpCode::WAS | OpCode::ZAM => {
|
||||
log::warn!("unimplemented opcode: {:?}", op);
|
||||
|
||||
|
@ -751,7 +762,7 @@ impl TextScript {
|
|||
|
||||
/// Compiles a decrypted text script data into internal bytecode.
|
||||
pub fn compile(data: &[u8], strict: bool) -> GameResult<TextScript> {
|
||||
println!("data: {}", String::from_utf8_lossy(data));
|
||||
log::debug!("data: {}", String::from_utf8_lossy(data));
|
||||
|
||||
let mut event_map = HashMap::new();
|
||||
let mut iter = data.iter().copied().peekable();
|
||||
|
@ -778,7 +789,6 @@ impl TextScript {
|
|||
|
||||
let bytecode = TextScript::compile_event(&mut iter, strict)?;
|
||||
log::info!("Successfully compiled event #{} ({} bytes generated).", event_num, bytecode.len());
|
||||
println!("{:x?}", &bytecode);
|
||||
event_map.insert(event_num, bytecode);
|
||||
}
|
||||
b'\r' | b'\n' | b' ' | b'\t' => {
|
||||
|
|
Loading…
Reference in a new issue