Feat: more predictable projet load behavior
This commit is contained in:
@@ -25,6 +25,8 @@ struct ProjectFile {
|
|||||||
sample_paths: Vec<PathBuf>,
|
sample_paths: Vec<PathBuf>,
|
||||||
#[serde(default = "default_tempo")]
|
#[serde(default = "default_tempo")]
|
||||||
tempo: f64,
|
tempo: f64,
|
||||||
|
#[serde(default)]
|
||||||
|
playing_patterns: Vec<(usize, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_tempo() -> f64 {
|
fn default_tempo() -> f64 {
|
||||||
@@ -38,6 +40,7 @@ impl From<&Project> for ProjectFile {
|
|||||||
banks: project.banks.clone(),
|
banks: project.banks.clone(),
|
||||||
sample_paths: project.sample_paths.clone(),
|
sample_paths: project.sample_paths.clone(),
|
||||||
tempo: project.tempo,
|
tempo: project.tempo,
|
||||||
|
playing_patterns: project.playing_patterns.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,6 +51,7 @@ impl From<ProjectFile> for Project {
|
|||||||
banks: file.banks,
|
banks: file.banks,
|
||||||
sample_paths: file.sample_paths,
|
sample_paths: file.sample_paths,
|
||||||
tempo: file.tempo,
|
tempo: file.tempo,
|
||||||
|
playing_patterns: file.playing_patterns,
|
||||||
};
|
};
|
||||||
project.normalize();
|
project.normalize();
|
||||||
project
|
project
|
||||||
|
|||||||
@@ -450,6 +450,8 @@ pub struct Project {
|
|||||||
pub sample_paths: Vec<PathBuf>,
|
pub sample_paths: Vec<PathBuf>,
|
||||||
#[serde(default = "default_tempo")]
|
#[serde(default = "default_tempo")]
|
||||||
pub tempo: f64,
|
pub tempo: f64,
|
||||||
|
#[serde(default)]
|
||||||
|
pub playing_patterns: Vec<(usize, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_tempo() -> f64 {
|
fn default_tempo() -> f64 {
|
||||||
@@ -462,6 +464,7 @@ impl Default for Project {
|
|||||||
banks: (0..MAX_BANKS).map(|_| Bank::default()).collect(),
|
banks: (0..MAX_BANKS).map(|_| Bank::default()).collect(),
|
||||||
sample_paths: Vec::new(),
|
sample_paths: Vec::new(),
|
||||||
tempo: default_tempo(),
|
tempo: default_tempo(),
|
||||||
|
playing_patterns: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/app.rs
24
src/app.rs
@@ -527,10 +527,15 @@ impl App {
|
|||||||
self.load_step_to_editor();
|
self.load_step_to_editor();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(&mut self, path: PathBuf, link: &LinkState) {
|
pub fn save(&mut self, path: PathBuf, link: &LinkState, snapshot: &SequencerSnapshot) {
|
||||||
self.save_editor_to_step();
|
self.save_editor_to_step();
|
||||||
self.project_state.project.sample_paths = self.audio.config.sample_paths.clone();
|
self.project_state.project.sample_paths = self.audio.config.sample_paths.clone();
|
||||||
self.project_state.project.tempo = link.tempo();
|
self.project_state.project.tempo = link.tempo();
|
||||||
|
self.project_state.project.playing_patterns = snapshot
|
||||||
|
.active_patterns
|
||||||
|
.iter()
|
||||||
|
.map(|p| (p.bank, p.pattern))
|
||||||
|
.collect();
|
||||||
match model::save(&self.project_state.project, &path) {
|
match model::save(&self.project_state.project, &path) {
|
||||||
Ok(final_path) => {
|
Ok(final_path) => {
|
||||||
self.ui
|
self.ui
|
||||||
@@ -547,12 +552,27 @@ impl App {
|
|||||||
match model::load(&path) {
|
match model::load(&path) {
|
||||||
Ok(project) => {
|
Ok(project) => {
|
||||||
let tempo = project.tempo;
|
let tempo = project.tempo;
|
||||||
|
let playing = project.playing_patterns.clone();
|
||||||
|
|
||||||
self.project_state.project = project;
|
self.project_state.project = project;
|
||||||
self.editor_ctx.step = 0;
|
self.editor_ctx.step = 0;
|
||||||
self.load_step_to_editor();
|
self.load_step_to_editor();
|
||||||
self.compile_all_steps(link);
|
self.compile_all_steps(link);
|
||||||
self.mark_all_patterns_dirty();
|
self.mark_all_patterns_dirty();
|
||||||
link.set_tempo(tempo);
|
link.set_tempo(tempo);
|
||||||
|
|
||||||
|
self.playback.clear_queues();
|
||||||
|
self.variables.lock().unwrap().clear();
|
||||||
|
self.dict.lock().unwrap().clear();
|
||||||
|
|
||||||
|
for (bank, pattern) in playing {
|
||||||
|
self.playback.queued_changes.push(StagedChange {
|
||||||
|
change: PatternChange::Start { bank, pattern },
|
||||||
|
quantization: crate::model::LaunchQuantization::Immediate,
|
||||||
|
sync_mode: crate::model::SyncMode::Reset,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
self.ui.set_status(format!("Loaded: {}", path.display()));
|
self.ui.set_status(format!("Loaded: {}", path.display()));
|
||||||
self.project_state.file_path = Some(path);
|
self.project_state.file_path = Some(path);
|
||||||
}
|
}
|
||||||
@@ -1103,7 +1123,7 @@ impl App {
|
|||||||
}
|
}
|
||||||
self.project_state.mark_dirty(bank, pattern);
|
self.project_state.mark_dirty(bank, pattern);
|
||||||
}
|
}
|
||||||
AppCommand::Save(path) => self.save(path, link),
|
AppCommand::Save(path) => self.save(path, link, snapshot),
|
||||||
AppCommand::Load(path) => self.load(path, link),
|
AppCommand::Load(path) => self.load(path, link),
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
|
|||||||
@@ -258,6 +258,7 @@ fn handle_modal_input(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
|
|||||||
match mode {
|
match mode {
|
||||||
FileBrowserMode::Save => ctx.dispatch(AppCommand::Save(path)),
|
FileBrowserMode::Save => ctx.dispatch(AppCommand::Save(path)),
|
||||||
FileBrowserMode::Load => {
|
FileBrowserMode::Load => {
|
||||||
|
let _ = ctx.seq_cmd_tx.send(SeqCommand::StopAll);
|
||||||
ctx.dispatch(AppCommand::Load(path));
|
ctx.dispatch(AppCommand::Load(path));
|
||||||
load_project_samples(ctx);
|
load_project_samples(ctx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,4 +28,9 @@ impl PlaybackState {
|
|||||||
pub fn toggle(&mut self) {
|
pub fn toggle(&mut self) {
|
||||||
self.playing = !self.playing;
|
self.playing = !self.playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear_queues(&mut self) {
|
||||||
|
self.staged_changes.clear();
|
||||||
|
self.queued_changes.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user