rustysynth_ext/
midifile_sequencer.rs1use std::cmp;
2use std::sync::Arc;
3
4use crate::midifile::Message;
5use crate::midifile::MidiFile;
6use crate::synthesizer::Synthesizer;
7
8#[derive(Debug)]
10#[non_exhaustive]
11pub struct MidiFileSequencer {
12 synthesizer: Synthesizer,
13
14 speed: f64,
15
16 midi_file: Option<Arc<MidiFile>>,
17 play_loop: bool,
18
19 block_wrote: usize,
20
21 current_time: f64,
22 msg_index: usize,
23 loop_index: usize,
24}
25
26impl MidiFileSequencer {
27 pub fn new(synthesizer: Synthesizer) -> Self {
33 Self {
34 synthesizer,
35 speed: 1.0,
36 midi_file: None,
37 play_loop: false,
38 block_wrote: 0,
39 current_time: 0.0,
40 msg_index: 0,
41 loop_index: 0,
42 }
43 }
44
45 pub fn play(&mut self, midi_file: &Arc<MidiFile>, play_loop: bool) {
52 self.midi_file = Some(Arc::clone(midi_file));
53 self.play_loop = play_loop;
54
55 self.block_wrote = self.synthesizer.block_size;
56
57 self.current_time = 0.0;
58 self.msg_index = 0;
59 self.loop_index = 0;
60
61 self.synthesizer.reset()
62 }
63
64 pub fn stop(&mut self) {
66 self.midi_file = None;
67 self.synthesizer.reset();
68 }
69
70 pub fn render(&mut self, left: &mut [f32], right: &mut [f32]) {
81 if left.len() != right.len() {
82 panic!("The output buffers for the left and right must be the same length.");
83 }
84
85 let left_length = left.len();
86 let mut wrote: usize = 0;
87 while wrote < left_length {
88 if self.block_wrote == self.synthesizer.block_size {
89 self.process_events();
90 self.block_wrote = 0;
91 self.current_time += self.speed * self.synthesizer.block_size as f64
92 / self.synthesizer.sample_rate as f64;
93 }
94
95 let src_rem = self.synthesizer.block_size - self.block_wrote;
96 let dst_rem = left_length - wrote;
97 let rem = cmp::min(src_rem, dst_rem);
98
99 self.synthesizer.render(
100 &mut left[wrote..wrote + rem],
101 &mut right[wrote..wrote + rem],
102 );
103
104 self.block_wrote += rem;
105 wrote += rem;
106 }
107 }
108
109 fn process_events(&mut self) {
110 let midi_file = match self.midi_file.as_ref() {
111 Some(value) => value,
112 None => return,
113 };
114
115 while self.msg_index < midi_file.messages.len() {
116 let time = midi_file.times[self.msg_index];
117 let msg = midi_file.messages[self.msg_index];
118
119 if time <= self.current_time {
120 match msg {
121 Message::Normal {
122 status,
123 data1,
124 data2,
125 } => {
126 let channel = status & 0x0F;
127 let command = status & 0xF0;
128 self.synthesizer.process_midi_message(
129 channel as i32,
130 command as i32,
131 data1 as i32,
132 data2 as i32,
133 );
134 }
135 Message::LoopStart if self.play_loop => self.loop_index = self.msg_index,
136 Message::LoopEnd if self.play_loop => {
137 self.current_time = midi_file.times[self.loop_index];
138 self.msg_index = self.loop_index;
139 self.synthesizer.note_off_all(false);
140 }
141 _ => (),
142 }
143 self.msg_index += 1;
144 } else {
145 break;
146 }
147 }
148
149 if self.msg_index == midi_file.messages.len() && self.play_loop {
150 self.current_time = midi_file.times[self.loop_index];
151 self.msg_index = self.loop_index;
152 self.synthesizer.note_off_all(false);
153 }
154 }
155
156 pub fn get_synthesizer(&self) -> &Synthesizer {
158 &self.synthesizer
159 }
160
161 pub fn get_midi_file(&self) -> Option<&MidiFile> {
163 match &self.midi_file {
164 None => None,
165 Some(value) => Some(value),
166 }
167 }
168
169 pub fn get_position(&self) -> f64 {
171 self.current_time
172 }
173
174 pub fn end_of_sequence(&self) -> bool {
181 match &self.midi_file {
182 None => true,
183 Some(value) => self.msg_index == value.messages.len(),
184 }
185 }
186
187 pub fn get_speed(&self) -> f64 {
194 self.speed
195 }
196
197 pub fn set_speed(&mut self, value: f64) {
203 if value < 0.0 {
204 panic!("The playback speed must be a non-negative value.");
205 }
206
207 self.speed = value;
208 }
209}