@@ -3,24 +3,62 @@ use iced::{
33 mouse:: { self , Button } ,
44 theme:: Palette ,
55 widget:: canvas:: { path:: Builder , Event , Frame , Geometry , Path , Program , Stroke } ,
6- Color , Point , Rectangle , Renderer , Theme , Vector ,
6+ Color , Point , Rectangle , Renderer , Theme ,
77} ;
8+ use ordered_float:: OrderedFloat ;
89
910use crate :: {
10- audio:: { get_volume_at, interpolate , interpolation_factor , AudioTime , CutInfo , WavFileReader } ,
11+ audio:: { get_volume_at, AudioTime , CutInfo , WavFileReader } ,
1112 song:: Song ,
1213} ;
1314
14- const WIDTH : f32 = 800.0 ;
15- const HEIGHT : f32 = 50.0 ;
1615const NUM_PLOT_POINTS : usize = 100 ;
1716const PLOT_STROKE_WIDTH : f32 = 1.5 ;
18- const PLOT_COLOR : Color = Palette :: GRUVBOX_DARK . text ;
17+ const PLOT_COLOR : Color = Palette :: GRUVBOX_DARK . primary ;
1918const MARKER_STROKE_WIDTH : f32 = 2.5 ;
20- const MARKER_COLOR : Color = Palette :: GRUVBOX_DARK . primary ;
19+ const MARKER_COLOR : Color = Palette :: GRUVBOX_DARK . danger ;
20+
21+ type Volume = f32 ;
22+
23+ struct Data {
24+ time : AudioTime ,
25+ /// The volume of this data point normalized
26+ /// by the maximum volume of all points in this
27+ /// plot.
28+ volume : Volume ,
29+ }
30+
31+ struct Bounds {
32+ min_time : AudioTime ,
33+ max_time : AudioTime ,
34+ height : f32 ,
35+ width : f32 ,
36+ }
37+
38+ pub fn interpolate ( start : AudioTime , end : AudioTime , factor : f32 ) -> AudioTime {
39+ start + ( end - start) * factor as f64
40+ }
41+
42+ pub fn interpolation_factor ( start : AudioTime , end : AudioTime , x : AudioTime ) -> f64 {
43+ ( x. time - start. time ) / ( end. time - start. time )
44+ }
45+
46+ impl Bounds {
47+ fn x_pos_to_time ( & self , pos : Point ) -> AudioTime {
48+ let f = pos. x / self . width ;
49+ interpolate ( self . min_time , self . max_time , f)
50+ }
51+
52+ fn data_to_point ( & self , data : & Data ) -> Point {
53+ let f = interpolation_factor ( self . min_time , self . max_time , data. time ) ;
54+ Point :: new ( f as f32 * self . width , data. volume * self . height )
55+ }
56+ }
57+
58+ impl Data { }
2159
2260pub struct Plot {
23- data : Vec < Point > ,
61+ volume_data : Vec < Data > ,
2462 song_before : Option < Song > ,
2563 song_after : Option < Song > ,
2664 start : AudioTime ,
@@ -40,16 +78,29 @@ impl Plot {
4078 let delta = AudioTime :: from_time_same_spec ( 3.0 , cut_time) ;
4179 let start = cut_time - delta;
4280 let end = cut_time + delta;
43- let data = ( 0 ..NUM_PLOT_POINTS )
81+ let volume_data : Vec < _ > = ( 0 ..NUM_PLOT_POINTS )
4482 . map ( |i| {
4583 let f = i as f32 / NUM_PLOT_POINTS as f32 ;
46- let time = interpolate ( start, end, f as f64 ) ;
47- let vol = get_volume_at ( reader, time) . unwrap_or ( 0.0 ) as f32 ;
48- Point :: new ( f * WIDTH , HEIGHT / 2.0 + vol * HEIGHT )
84+ let time = interpolate ( start, end, f) ;
85+ let volume = get_volume_at ( reader, time) . unwrap_or ( 0.0 ) as f32 ;
86+ Data { time, volume }
87+ } )
88+ . collect ( ) ;
89+ // Normalize
90+ let max_volume = volume_data
91+ . iter ( )
92+ . map ( |data| OrderedFloat ( data. volume ) )
93+ . max ( )
94+ . unwrap ( ) ;
95+ let volume_data = volume_data
96+ . into_iter ( )
97+ . map ( |data| Data {
98+ time : data. time ,
99+ volume : data. volume / * max_volume,
49100 } )
50101 . collect ( ) ;
51102 Self {
52- data ,
103+ volume_data ,
53104 song_before,
54105 song_after,
55106 start,
@@ -60,47 +111,44 @@ impl Plot {
60111 }
61112 }
62113
63- fn pos_to_time ( & self , pos : Point ) -> AudioTime {
64- interpolate ( self . start , self . end , ( pos. x / WIDTH ) as f64 )
65- }
66-
67- fn time_to_pos ( & self , time : AudioTime ) -> f32 {
68- WIDTH * interpolation_factor ( self . start , self . end , time) as f32
69- }
70-
71- pub fn get_plot_path ( & self , data : & [ Point ] ) -> Path {
114+ pub fn get_plot_path ( & self , data : & [ Data ] , bounds : & Bounds ) -> Path {
72115 let mut path = Builder :: new ( ) ;
73116
74117 if data. len ( ) > 0 {
75- path. move_to ( data[ 0 ] ) ;
76- for point in data. iter ( ) {
77- path. line_to ( * point ) ;
118+ path. move_to ( bounds . data_to_point ( & data[ 0 ] ) ) ;
119+ for data in data. iter ( ) {
120+ path. line_to ( bounds . data_to_point ( data ) ) ;
78121 }
79122 }
80123 path. build ( )
81124 }
82125
83126 /// Return the path left of the marker and the path right
84127 /// of the marker, so they can be colored individually.
85- pub fn get_plot_paths ( & self ) -> ( Path , Path ) {
128+ pub fn get_plot_paths ( & self , bounds : & Bounds ) -> ( Path , Path ) {
86129 let cutoff = self
87- . data
130+ . volume_data
88131 . iter ( )
89132 . enumerate ( )
90- . find ( |( _, p ) | self . pos_to_time ( * * p ) > self . cut_time )
133+ . find ( |( _, data ) | data . time > self . cut_time )
91134 . map ( |( i, _) | i)
92- . unwrap_or ( self . data . len ( ) - 1 ) ;
135+ . unwrap_or ( self . volume_data . len ( ) - 1 ) ;
93136 (
94- self . get_plot_path ( & self . data [ ..=cutoff] ) ,
95- self . get_plot_path ( & self . data [ cutoff..] ) ,
137+ self . get_plot_path ( & self . volume_data [ ..=cutoff] , bounds ) ,
138+ self . get_plot_path ( & self . volume_data [ cutoff..] , bounds ) ,
96139 )
97140 }
98141
99- pub fn get_marker_path ( & self ) -> Path {
142+ pub fn get_marker_path ( & self , bounds : & Bounds ) -> Path {
100143 let mut path = Builder :: new ( ) ;
101- let x = self . time_to_pos ( self . cut_time ) ;
102- path. move_to ( Point :: new ( x, 0.0 ) ) ;
103- path. line_to ( Point :: new ( x, HEIGHT ) ) ;
144+ path. move_to ( bounds. data_to_point ( & Data {
145+ time : self . cut_time ,
146+ volume : -1.0 ,
147+ } ) ) ;
148+ path. line_to ( bounds. data_to_point ( & Data {
149+ time : self . cut_time ,
150+ volume : 1.0 ,
151+ } ) ) ;
104152 path. build ( )
105153 }
106154
@@ -126,6 +174,15 @@ impl Plot {
126174 pub fn song_before ( & self ) -> Option < & Song > {
127175 self . song_before . as_ref ( )
128176 }
177+
178+ fn get_bounds ( & self , bounds : Rectangle ) -> Bounds {
179+ Bounds {
180+ width : bounds. width ,
181+ height : bounds. height ,
182+ min_time : self . volume_data . first ( ) . unwrap ( ) . time ,
183+ max_time : self . volume_data . last ( ) . unwrap ( ) . time ,
184+ }
185+ }
129186}
130187
131188pub struct PlotMarkerMoved {
@@ -139,16 +196,17 @@ impl Program<PlotMarkerMoved> for Plot {
139196 & self ,
140197 _state : & mut Self :: State ,
141198 event : Event ,
142- bounds : Rectangle ,
199+ rect : Rectangle ,
143200 cursor : mouse:: Cursor ,
144201 ) -> ( Status , Option < PlotMarkerMoved > ) {
202+ let bounds = self . get_bounds ( rect) ;
145203 if let Event :: Mouse ( mouse:: Event :: ButtonPressed ( ev) ) = event {
146204 if ev == Button :: Left {
147- if let Some ( pos) = cursor. position_in ( bounds ) {
205+ if let Some ( pos) = cursor. position_in ( rect ) {
148206 return (
149207 Status :: Ignored ,
150208 Some ( PlotMarkerMoved {
151- time : self . pos_to_time ( pos) ,
209+ time : bounds . x_pos_to_time ( pos) ,
152210 } ) ,
153211 ) ;
154212 }
@@ -162,12 +220,13 @@ impl Program<PlotMarkerMoved> for Plot {
162220 _state : & ( ) ,
163221 renderer : & Renderer ,
164222 _theme : & Theme ,
165- bounds : Rectangle ,
223+ rect : Rectangle ,
166224 _cursor : mouse:: Cursor ,
167225 ) -> Vec < Geometry > {
168- let mut frame = Frame :: new ( renderer, bounds . size ( ) ) ;
226+ let mut frame = Frame :: new ( renderer, rect . size ( ) ) ;
169227
170- let ( plot_before, plot_after) = self . get_plot_paths ( ) ;
228+ let bounds = self . get_bounds ( rect) ;
229+ let ( plot_before, plot_after) = self . get_plot_paths ( & bounds) ;
171230 let color = |finished_cutting| {
172231 if finished_cutting {
173232 Color :: from_rgb ( 0.0 , 0.8 , 0.0 )
@@ -187,7 +246,7 @@ impl Program<PlotMarkerMoved> for Plot {
187246 . with_width ( PLOT_STROKE_WIDTH )
188247 . with_color ( color ( self . finished_cut_after ) ) ,
189248 ) ;
190- let marker = self . get_marker_path ( ) ;
249+ let marker = self . get_marker_path ( & bounds ) ;
191250 frame. stroke (
192251 & marker,
193252 Stroke :: default ( )
0 commit comments