basic save load

This commit is contained in:
2025-09-27 01:13:01 -05:00
parent d11dc271af
commit ba7fda2b5c
9 changed files with 257 additions and 41 deletions
+2
View File
@@ -1,6 +1,7 @@
use std::ops::RangeInclusive;
use eframe::egui;
use eframe::egui::{Color32, Context, Id, PointerButton, Pos2, Rangef, RichText, Sense, Ui, Vec2, Widget};
use serde::{Deserialize, Serialize};
use crate::noise::NoteType;
use crate::scale::Scale;
use crate::tenori::LOOP_LENGTH;
@@ -17,6 +18,7 @@ impl NoteType {
}
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Grid {
pub note_type: NoteType,
pub volume: f32,
+40 -15
View File
@@ -1,28 +1,53 @@
use std::fs;
use std::ops::RangeInclusive;
use eframe::egui;
use eframe::egui::{Context, TopBottomPanel};
use crate::noise::NoteType;
use crate::saveload::PersistedTenori;
use crate::Tenori;
impl Tenori {
pub fn menu(&mut self, ctx: &Context) {
TopBottomPanel::top("menu_panel").show(ctx, |ui| {
egui::MenuBar::new().ui(ui, |ui| {
if ui.button("Square").clicked() {
self.add_window(NoteType::Square)
}
if ui.button("Sine").clicked() {
self.add_window(NoteType::Sine)
}
if ui.button("Triangle").clicked() {
self.add_window(NoteType::Triangle)
}
if ui.button("Sawtooth").clicked() {
self.add_window(NoteType::Sawtooth)
}
if ui.button("Noise").clicked() {
self.add_window(NoteType::Noise)
}
ui.menu_button("File", |ui| {
if ui.button("Save").clicked() &&
let Ok(serialized) = toml::to_string(&PersistedTenori::from(&*self)) &&
let Some(path) = rfd::FileDialog::new().add_filter("Tenori files", &["tenori"]).set_file_name("song.tenori").save_file() {
match fs::write(path, serialized) {
Ok(_) => {}
Err(e) => { dbg!(e); }
}
}
if ui.button("Load").clicked() &&
let Some(path) = rfd::FileDialog::new().add_filter("Tenori files", &["tenori"]).pick_file() &&
let Ok(serialized) = fs::read_to_string(path) &&
let Ok(persisted) = toml::from_str::<PersistedTenori>(serialized.as_str()) {
self.grids = persisted.grids;
self.tempo = persisted.tempo;
self.playing = false;
self.timer = 0.0;
}
});
ui.menu_button("Add track", |ui| {
if ui.button("Square").clicked() {
self.add_window(NoteType::Square)
}
if ui.button("Sine").clicked() {
self.add_window(NoteType::Sine)
}
if ui.button("Triangle").clicked() {
self.add_window(NoteType::Triangle)
}
if ui.button("Sawtooth").clicked() {
self.add_window(NoteType::Sawtooth)
}
if ui.button("Noise").clicked() {
self.add_window(NoteType::Noise)
}
});
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.add(egui::Slider::new(&mut self.tempo, RangeInclusive::new(20, 180)));
+2 -1
View File
@@ -3,6 +3,7 @@ mod tenori;
mod grid;
mod noise;
mod scale;
mod saveload;
use std::time::Duration;
use eframe::{App, Frame};
@@ -21,7 +22,7 @@ impl App for Tenori {
fn update(&mut self, ctx: &Context, frame: &mut Frame) {
let play = self.tick();
let cursor = self.ratio();
self.menu(&ctx);
self.menu(ctx);
for g in self.grids.iter_mut() {
g.show(ctx, cursor)
}
+2 -1
View File
@@ -1,8 +1,9 @@
use std::time::Duration;
use rodio::mixer::Mixer;
use rodio::Source;
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum NoteType {
Sine,
Triangle,
+18
View File
@@ -0,0 +1,18 @@
use serde::{Deserialize, Serialize};
use crate::grid::Grid;
use crate::tenori::Tenori;
#[derive(Serialize, Deserialize)]
pub struct PersistedTenori {
pub tempo: u32,
pub grids: Vec<Grid>
}
impl From<&Tenori> for PersistedTenori {
fn from(value: &Tenori) -> Self {
Self {
tempo: value.tempo,
grids: value.grids.iter().map(Grid::clone).collect()
}
}
}
+2 -1
View File
@@ -1,6 +1,7 @@
use eframe::egui::RichText;
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Scale {
CMajor,
CMinor,
+1 -1
View File
@@ -10,7 +10,7 @@ pub struct Tenori {
pub tempo: u32,
// A count _in beats_ of where we are in the loop
timer: f32,
pub timer: f32,
/// Whether or not we're playing; false == paused
pub playing: bool,