torque_tracker_engine/
live_audio.rs1use std::ops::{AddAssign, IndexMut};
2
3use crate::audio_processing::playback::{PlaybackState, PlaybackStatus};
4use crate::audio_processing::sample::Interpolation;
5use crate::audio_processing::sample::SamplePlayer;
6use crate::audio_processing::Frame;
7use crate::manager::{OutputConfig, ToWorkerMsg};
8use crate::project::song::Song;
9use crate::sample::Sample;
10use dasp::sample::ToSample;
11use simple_left_right::Reader;
12
13pub(crate) struct LiveAudio {
14 song: Reader<Song>,
15 playback_state: Option<PlaybackState>,
16 live_note: Option<SamplePlayer>,
17 manager: rtrb::Consumer<ToWorkerMsg>,
18 state_sender: triple_buffer::Input<Option<PlaybackStatus>>,
19 config: OutputConfig,
20
21 buffer: Box<[Frame]>,
22}
23
24const INTERPOLATION: u8 = Interpolation::Linear as u8;
26
27impl LiveAudio {
28 pub fn new(
30 song: Reader<Song>,
31 manager: rtrb::Consumer<ToWorkerMsg>,
32 state_sender: triple_buffer::Input<Option<PlaybackStatus>>,
33 config: OutputConfig,
34 ) -> Self {
35 Self {
36 song,
37 playback_state: None,
38 live_note: None,
39 manager,
40 state_sender,
41 config,
42 buffer: vec![Frame::default(); usize::try_from(config.buffer_size).unwrap() * 2].into(),
43 }
44 }
45
46 #[rtsan_standalone::nonblocking]
47 fn send_state(&mut self) {
48 self.state_sender
49 .write(self.playback_state.as_ref().map(|s| s.get_status()));
50 }
51
52 #[rtsan_standalone::nonblocking]
53 fn fill_internal_buffer(&mut self, len: usize) -> bool {
55 let buffer = &mut self.buffer[..len];
57
58 let song = self.song.lock();
59
60 while let Ok(event) = self.manager.pop() {
62 match event {
63 ToWorkerMsg::StopPlayback => self.playback_state = None,
64 ToWorkerMsg::Playback(settings) => {
65 self.playback_state =
66 PlaybackState::new(&song, self.config.sample_rate, settings);
67 }
68 ToWorkerMsg::PlayEvent(note) => {
69 if let Some(sample) = &song.samples[usize::from(note.sample_instr)] {
70 let sample_player = SamplePlayer::new(
71 Sample::clone(&sample.1),
72 sample.0,
73 self.config.sample_rate,
75 note.note,
76 );
77 self.live_note = Some(sample_player);
78 }
79 }
80 ToWorkerMsg::StopLiveNote => self.live_note = None,
81 }
82 }
83 if self.live_note.is_none() && self.playback_state.is_none() {
84 return false;
86 }
87
88 buffer.fill(Frame::default());
91
92 if let Some(live_note) = &mut self.live_note {
94 let note_iter = live_note.iter::<{ INTERPOLATION }>();
95 buffer
96 .iter_mut()
97 .zip(note_iter)
98 .for_each(|(buf, note)| buf.add_assign(note));
99
100 if live_note.check_position().is_break() {
101 self.live_note = None;
102 }
103 }
104
105 if let Some(playback) = &mut self.playback_state {
107 let playback_iter = playback.iter::<{ INTERPOLATION }>(&song);
108 buffer
109 .iter_mut()
110 .zip(playback_iter)
111 .for_each(|(buf, frame)| buf.add_assign(frame));
112
113 if playback.is_done() {
114 self.playback_state = None;
115 }
116 }
117
118 true
119 }
120
121 #[rtsan_standalone::nonblocking]
124 #[inline]
125 fn fill_from_internal<Sample: dasp::sample::Sample + dasp::sample::FromSample<f32>>(
126 &mut self,
127 data: &mut [Sample],
128 ) {
129 if self.config.channel_count.get() == 1 {
131 data.iter_mut()
132 .zip(self.buffer.iter())
133 .for_each(|(out, buf)| *out = buf.sum_to_mono().to_sample_());
134 } else {
135 data.chunks_exact_mut(usize::from(self.config.channel_count.get()))
136 .map(|frame| frame.split_first_chunk_mut::<2>().unwrap().0)
137 .zip(self.buffer.iter())
138 .for_each(|(out, buf)| *out = buf.to_sample());
139 }
140 }
141
142 pub fn get_typed_callback<Sample: dasp::sample::Sample + dasp::sample::FromSample<f32>>(
145 mut self,
146 ) -> impl FnMut(&mut [Sample]) {
147 move |data| {
148 let channel_count = usize::from(self.config.channel_count.get());
149 assert!(data.len().is_multiple_of(channel_count));
150 let out_frames = data.len() / channel_count;
151 assert!(self.buffer.len() > out_frames);
152 if self.fill_internal_buffer(out_frames) {
159 self.fill_from_internal(data);
160 }
161 self.send_state();
162 }
163 }
172
173 }
183
184#[allow(dead_code)]
187fn sine(output: &mut [[f32; 2]], sample_rate: f32) {
188 let mut sample_clock = 0f32;
189 for frame in output {
190 sample_clock = (sample_clock + 1.) % sample_rate;
191 let value = (sample_clock * 440. * 2. * std::f32::consts::PI / sample_rate).sin();
192 *frame.index_mut(0) = value;
193 *frame.index_mut(1) = value;
194 }
195}