basic save load
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user