Files
Polymusic/src/music.rs

404 lines
13 KiB
Rust

use crate::message::Message;
use crate::polygon_draw::*;
use crate::utils::string_to_polygon;
use serde::{Deserialize, Serialize};
use kira::{sound::static_sound::StaticSoundData, AudioManager};
use iced::event::Status;
use iced::mouse::Cursor;
use iced::widget::canvas::{Event, Geometry};
use iced::{keyboard, Vector};
use iced::{
mouse::{self, ScrollDelta},
Size,
};
use iced::widget::canvas;
use iced::widget::canvas::Stroke;
use iced::widget::canvas::Style;
use iced::{Color, Rectangle, Renderer, Theme};
use std::f32::consts::PI;
use std::mem::swap;
use std::time::Duration;
#[derive(Serialize, Deserialize)]
pub struct Music {
pub poly_frame: Vec<(f32, PolygonFrame)>,
pub nb_sec_for_rev: f32,
pub file_name: String,
pub length: f32,
#[serde(skip)]
teta: f32,
#[serde(skip)]
pub current_delta: f32,
#[serde(skip)]
point_removed: Vec<(f32, PolygonFrame)>,
}
impl Music {
fn find_poly_frame(&mut self, delta: f32) -> &mut PolygonFrame {
if let Some(i) = self
.poly_frame
.windows(2)
.position(|w| w[0].0 <= delta && delta < w[1].0)
{
&mut self.poly_frame[i].1
} else {
&mut self.poly_frame.last_mut().unwrap().1
}
}
fn find_index_frame(&mut self, delta: f32) -> usize {
if let Some(i) = self
.poly_frame
.windows(2)
.position(|w| w[0].0 <= delta && delta < w[1].0)
{
i
} else {
self.poly_frame.len() - 1
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~PUBLIC~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pub fn current_frame(&self, delta: f32) -> &PolygonFrame {
if let Some(i) = self
.poly_frame
.windows(2)
.position(|w| w[0].0 <= delta && delta < w[1].0)
{
&self.poly_frame[i].1
} else {
&self.poly_frame.last().unwrap().1
}
}
pub fn default() -> Music {
Music {
poly_frame: vec![(0.0, PolygonFrame::default())],
nb_sec_for_rev: 1.0,
file_name: "Default File Name".to_string(),
length: 60.0,
teta: 0.,
current_delta: 0.,
point_removed: vec![],
}
}
pub fn update_frame(&mut self) {
for (_, p) in &mut self.poly_frame {
p.update();
}
}
pub fn fix_teta(&mut self, delta: f32) {
let new_teta = delta % self.nb_sec_for_rev * 2.0 * PI / self.nb_sec_for_rev;
self.teta = new_teta;
}
pub fn apply_tick(&mut self, delta: f32, time_btw: Duration, audio_manager: &mut AudioManager) {
let teta_temp = self.teta;
self.teta +=
2.0 * PI * (1.0 / self.nb_sec_for_rev) * (time_btw.as_millis() as f32 / 1_000.0);
self.teta %= 2.0 * PI;
let currrent_teta = self.teta;
let current_frame = self.find_poly_frame(delta);
current_frame.teta = currrent_teta;
let sound_to_play = current_frame.all_sound_to_play_btw(teta_temp, current_frame.teta);
for sound in sound_to_play {
audio_manager
.play(sound.clone())
.expect("Error to play sound");
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~SET~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pub fn set_sound(
&mut self,
delta: f32,
index: usize,
sound: StaticSoundData,
sound_name: String,
) -> String {
let current_frame = self.find_poly_frame(delta);
current_frame.polygons[index].sound = sound;
let out = current_frame.polygons[index].sound_name.clone();
current_frame.polygons[index].sound_name = sound_name;
out
}
pub fn set_teta(&mut self, delta: f32, index: usize, teta: f32) -> f32 {
let out = self.find_poly_frame(delta).polygons[index].global_teta;
self.find_poly_frame(delta).polygons[index].global_teta = teta;
out
}
pub fn set_color(&mut self, delta: f32, index: usize, color: Color) -> Color {
let current_frame = self.find_poly_frame(delta);
let out = current_frame.polygons[index].color.clone();
current_frame.polygons[index].color = color;
out
}
pub fn set_color_picker(&mut self, delta: f32, i: usize, b: bool) {
let current_frame = self.find_poly_frame(delta);
current_frame.polygons[i].show_color_picker = b;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ADD/REMOVE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pub fn add_point(&mut self, delta: f32) {
let pos = self
.poly_frame
.binary_search_by(|(d, _)| d.partial_cmp(&delta).unwrap())
.unwrap_or_else(|e| e);
self.poly_frame
.insert(pos, (delta, self.current_frame(delta).clone()));
}
pub fn add_point_old(&mut self) {
if let Some(pair) = self.point_removed.pop() {
let pos = self
.poly_frame
.binary_search_by(|(d, _)| d.partial_cmp(&pair.0).unwrap())
.unwrap_or_else(|e| e);
self.poly_frame.insert(pos, pair);
}
}
pub fn remove_point(&mut self, delta: f32) {
let i = self.find_index_frame(delta);
if i != 0 {
self.point_removed.push(self.poly_frame[i].clone());
self.poly_frame.remove(i);
}
}
pub fn add_polygon(&mut self, delta: f32, polygon_name: String) {
let current_frame = self.find_poly_frame(delta);
let mut poly = string_to_polygon(polygon_name);
poly.update();
current_frame.polygons.push(poly);
}
pub fn add_polygon_from(&mut self, delta: f32, polygon: Polygon) {
let current_frame = self.find_poly_frame(delta);
current_frame.polygons.push(polygon);
}
pub fn remove_polygon(&mut self, delta: f32, i: usize) -> Polygon {
let pf = self.find_poly_frame(delta);
let mut i = i;
if i == usize::MAX {
i = pf.polygons.len() - 1
}
let out = pf.polygons[i].clone();
pf.polygons.remove(i);
out
}
pub fn slide_to_left(&mut self, delta: f32) {
let i = self.find_index_frame(delta);
if i > 0 {
let (left, right) = self.poly_frame.split_at_mut(i);
swap(&mut left[i - 1].1, &mut right[0].1);
}
}
pub fn slide_to_right(&mut self, delta: f32) {
let i = self.find_index_frame(delta);
if i < self.poly_frame.len() - 1 {
let (left, right) = self.poly_frame.split_at_mut(i + 1);
swap(&mut left[i].1, &mut right[0].1);
}
}
}
#[derive(Default, Debug)]
pub struct StateMusic {
mouse_left: bool,
ctrl: bool,
zoom: f32,
offset: f32,
}
impl canvas::Program<Message> for Music {
// No internal state
type State = StateMusic;
fn draw(
&self,
state: &Self::State,
renderer: &Renderer,
_theme: &Theme,
bounds: Rectangle,
_cursor: mouse::Cursor,
) -> Vec<canvas::Geometry> {
let mut geo_small_frame: Vec<Geometry> = vec![];
let mut geo_cursor: Vec<Geometry> = vec![];
let frame = canvas::Frame::new(renderer, bounds.size());
let global_width = bounds.width * state.zoom;
let mut toggle_color = true;
let padding = 8.;
let w = global_width - (padding * 2.);
for (delta, polyframe) in &self.poly_frame {
let x = delta / self.length * w + 8. - state.offset;
let mut back_frame = canvas::Frame::new(
renderer,
Size {
width: global_width.clamp(0.0, bounds.width),
height: bounds.height,
},
);
back_frame.fill_rectangle(
iced::Point { x: x, y: 0.0 },
Size {
width: global_width,
height: bounds.height,
},
if toggle_color {
Color::from_rgb8(27, 60, 83)
} else {
Color::from_rgb8(69, 104, 130)
},
);
geo_small_frame.push(back_frame.into_geometry());
toggle_color = !toggle_color;
let mut small_frame = canvas::Frame::new(
renderer,
Size {
width: global_width.clamp(0.0, bounds.width),
height: bounds.height,
},
);
small_frame.translate(Vector {
x: x + (bounds.height / 10.),
y: (bounds.height / 10.),
});
polyframe.draw_in_frame(
&mut small_frame,
Size {
width: (8. * bounds.height) / 10.,
height: (8. * bounds.height) / 10.,
},
);
geo_small_frame.push(small_frame.into_geometry());
}
let x = self.current_delta / self.length * w + 8. - state.offset;
let mut frame_cursor = canvas::Frame::new(renderer, bounds.size());
frame_cursor.stroke_rectangle(
iced::Point::new(x, 0.),
iced::Size {
width: 0.,
height: bounds.height,
},
Stroke {
width: 4.0,
style: Style::Solid(Color::from_rgba(1.0, 0.0, 0.0, 1.)),
..Stroke::default()
},
);
frame_cursor.stroke_rectangle(
iced::Point {
x: -state.offset,
y: 0.0,
},
iced::Size {
width: global_width,
height: bounds.height,
},
Stroke {
width: 16.0,
style: Style::Solid(Color::from_rgb8(207, 74, 28)),
..Stroke::default()
},
);
geo_cursor.push(frame_cursor.into_geometry());
//vec_geo.push(frame.into_geometry());
// Then, we produce the geometry
let mut out = vec![frame.into_geometry()];
out.append(&mut geo_small_frame);
out.append(&mut geo_cursor);
out
}
fn update(
&self,
state: &mut Self::State,
event: Event,
bounds: Rectangle,
cursor: Cursor,
) -> (Status, Option<Message>) {
//eprintln!("event = {:?}", event);
if let Event::Keyboard(keyboard_event) = &event {
match keyboard_event {
keyboard::Event::ModifiersChanged(m) => {
state.ctrl = m.control();
}
_ => (),
}
}
if let Event::Mouse(mouse_event) = event {
match mouse_event {
mouse::Event::ButtonPressed(mouse::Button::Left) => {
state.mouse_left = true;
if let Some(position) = cursor.position_in(bounds) {
let pos_x =
(position.x + state.offset - 8.0) / (bounds.width * state.zoom - 16.);
let delta = (pos_x * self.length).clamp(0., self.length);
return (
Status::Captured,
Some(crate::message::Message::ClickedOnTimeLine(delta)),
);
}
}
mouse::Event::ButtonReleased(mouse::Button::Left) => state.mouse_left = false,
mouse::Event::CursorMoved { position: _ } => {
if let Some(position) = cursor.position_in(bounds)
&& state.mouse_left
{
let pos_x =
(position.x + state.offset - 8.0) / (bounds.width * state.zoom - 16.);
let delta = (pos_x * self.length).clamp(0., self.length);
return (Status::Captured, Some(Message::ClickedOnTimeLine(delta)));
}
}
mouse::Event::WheelScrolled { delta: d } => {
if state.ctrl {
match d {
ScrollDelta::Lines { x: _, y } => {
let before = bounds.width * state.zoom;
state.zoom += y / 10.;
state.offset = state.offset * (bounds.width * state.zoom) / before;
}
ScrollDelta::Pixels { x: _, y } => {
let before = bounds.width * state.zoom;
state.zoom += y / 10.;
state.offset = state.offset * (bounds.width * state.zoom) / before;
}
}
} else {
match d {
ScrollDelta::Lines { x: _, y } => {
state.offset -= y * 32. * state.zoom;
}
ScrollDelta::Pixels { x: _, y } => {
state.offset -= y * 32. * state.zoom;
}
}
}
}
_ => {}
}
}
state.zoom = state.zoom.clamp(1.0, 10.);
if state.offset + bounds.width >= bounds.width * state.zoom {
state.offset = bounds.width * state.zoom - bounds.width
}
if state.offset <= 0. {
state.offset = 0.
}
(Status::Ignored, None)
}
}