Skip to content

Commit

Permalink
loop working
Browse files Browse the repository at this point in the history
  • Loading branch information
xasopheno committed Nov 24, 2024
1 parent de8b16e commit d3bb66c
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 147 deletions.
17 changes: 13 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ colored = "2.0.0"
num-traits = "0.2.14"
num-integer = "0.1.44"
polynomials = "0.2.4"
meval = "0.2.0"
meval = { git = "https://github.com/xasopheno/meval-rs"}
csv = "1.1.6"
hamcrest2 = "0.3.0"
peekread = "0.1.1"
Expand Down
252 changes: 180 additions & 72 deletions core/src/manager/render_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ pub struct RenderManager {
kill_channel: KillChannel,
once: bool,
paused: bool,
total_samples_per_loop: usize,
samples_processed: usize,
}

pub fn render_op_to_normalized_op4d(render_op: &RenderOp, normalizer: &Normalizer) -> Option<Op4D> {
Expand Down Expand Up @@ -97,6 +99,8 @@ impl RenderManager {
kill_channel,
once,
paused: false,
total_samples_per_loop: 0,
samples_processed: 0,
}
}

Expand All @@ -121,6 +125,8 @@ impl RenderManager {
kill_channel: None,
once: false,
paused: false,
total_samples_per_loop: 0,
samples_processed: 0,
}
}

Expand Down Expand Up @@ -167,94 +173,192 @@ impl RenderManager {
) -> Option<(StereoWaveform, Vec<f32>)> {
if self.paused {
return None;
};
}

let mut remaining_buffer_size = buffer_size;
let mut total_rendered_per_batch: Vec<Vec<StereoWaveform>> = Vec::new();
let mut total_ops: Vec<RenderOp> = Vec::new();

let next = self.exists_next_render();
let vtx = self.visualization.channel.clone();
let normalizer = self.visualization.normalizer;
let current = self.current_render();

match current {
Some(render_voices) => {
let (ops, rendered): (Vec<_>, Vec<_>) = render_voices
.iter_mut()
.filter_map(|voice| {
voice
.get_batch(Settings::global().buffer_size, None)
.map(|mut batch| {
(
if vtx.is_some() {
batch.iter().filter(|op| op.index == 0).cloned().collect()
} else {
vec![]
},
batch.render(&mut voice.oscillator, Some(&offset)),
)
})
})
.unzip();

if let Some(tx) = vtx {
let mut opmap: OpMap<Op4D> = OpMap::with_capacity(ops.len());

ops.iter().flatten().for_each(|v| {
let name = v.names.last().map_or("nameless", |n| n);

let op = render_op_to_normalized_op4d(v, &normalizer);
if let Some(mut o) = op {
o.y = o.y * offset.freq;
o.z = o.z * offset.gain;
opmap.insert(name, o);
};
});
if tx.send(VisEvent::Ops(opmap)).is_err() {
info!("WereSoCool server closed");
std::process::exit(0);
}
}

if !rendered.is_empty() {
let mut sw: StereoWaveform = sum_all_waveforms(rendered);

if next {
sw.fade_out();

*current = None;
self.inc_render();
while remaining_buffer_size > 0 {
// Compute next_exists before mutable borrow
let next_exists = self.exists_next_render();

// Start mutable borrow scope
let (samples_processed, render_finished) = {
let current_render_option = self.current_render();

match current_render_option {
Some(render_voices) => {
let mut any_data_rendered = false;
let mut ops_per_voice: Vec<Vec<RenderOp>> = Vec::new();
let mut rendered_per_voice: Vec<StereoWaveform> = Vec::new();

let mut min_samples_processed = remaining_buffer_size;

for voice in render_voices.iter_mut() {
match voice.get_batch(
remaining_buffer_size,
None,
!next_exists && Settings::global().loop_play,
) {
Some(mut batch) => {
any_data_rendered = true;
let samples = batch.iter().map(|op| op.samples).sum::<usize>();
min_samples_processed = min_samples_processed.min(samples);

if let Some(_vtx) = &vtx {
let voice_ops: Vec<_> = batch
.iter()
.filter(|op| op.index == 0)
.cloned()
.collect();
ops_per_voice.push(voice_ops);
}
let voice_rendered =
batch.render(&mut voice.oscillator, Some(&offset));
// Collect the rendered waveform per voice
rendered_per_voice.push(voice_rendered);
}
None => {
// Voice has finished
// Do not set min_samples_processed to zero here
}
}
}

if any_data_rendered && min_samples_processed > 0 {
// Store the per-voice rendered waveforms for this batch
total_rendered_per_batch.push(rendered_per_voice);
total_ops.extend(ops_per_voice.into_iter().flatten());

(min_samples_processed, false)
} else if any_data_rendered {
// Some data rendered, but min_samples_processed is zero
(0, false)
} else {
// All voices have finished
(0, true)
}
}
None => {
// No current render
(0, true)
}
}
}; // End of mutable borrow

sw.pad(buffer_size);
if samples_processed > 0 {
remaining_buffer_size = remaining_buffer_size.saturating_sub(samples_processed);
}

let ramp = self.ramp_to_current_volume(buffer_size);
Some((sw, ramp))
if render_finished {
if self.exists_next_render() {
self.inc_render();
continue; // Continue processing with next render
} else {
*self.current_render() = None;

if self.once {
self.kill().expect("Not able to kill");
None
} else {
None
self.kill().expect("Unable to kill");
}
break; // No more renders, exit loop
}
}
None => {
if next {
self.inc_render();
self.read(buffer_size, offset)
} else {
None

if samples_processed == 0 {
// No samples processed, break to avoid infinite loop
break;
}
}

// Now, we have total_rendered_per_batch: Vec<Vec<StereoWaveform>>
// Each inner Vec<StereoWaveform> corresponds to per-voice waveforms for a batch
// Now, we need to sum the per-voice waveforms for each batch and append them to build the final combined waveform

if !total_rendered_per_batch.is_empty() {
let mut combined_sw = StereoWaveform::new_empty();

for rendered_per_voice in total_rendered_per_batch {
let batch_sw = sum_all_waveforms(rendered_per_voice);
combined_sw.append(batch_sw);
}

combined_sw.pad(buffer_size);

// Visualization
if let Some(tx) = vtx {
let mut opmap: OpMap<Op4D> = OpMap::with_capacity(total_ops.len());

total_ops.iter().for_each(|v| {
let name = v.names.last().map_or("nameless", |n| n);

let op = render_op_to_normalized_op4d(v, &normalizer);
if let Some(mut o) = op {
o.y = o.y * offset.freq;
o.z = o.z * offset.gain;
opmap.insert(name, o);
};
});

if tx.send(VisEvent::Ops(opmap)).is_err() {
info!("Visualization channel closed");
std::process::exit(0);
}
}

let ramp = self.ramp_to_current_volume(buffer_size);
Some((combined_sw, ramp))
} else {
None
}
}

pub fn inc_render(&mut self) {
self.render_idx = (self.render_idx + 1) % 2;
info!("Incrementing render");
// Update the render index

// Since self.renders has length 2, we can split it at index 1
let (first, second) = self.renders.split_at_mut(1);

let (current_render_option, next_render_option) = if self.render_idx == 0 {
(&first[0], &mut second[0])
} else {
(&second[0], &mut first[0])
};

if let (Some(current_voices), Some(next_voices)) =
(current_render_option.as_ref(), next_render_option.as_mut())
{
// Ensure that both renders have the same number of voices
let min_length = std::cmp::min(current_voices.len(), next_voices.len());
for i in 0..min_length {
let current_oscillator = &current_voices[i].oscillator;
let next_oscillator = &mut next_voices[i].oscillator;

// Copy the oscillator state
next_oscillator.copy_state_from(current_oscillator);
}
}

// Reset samples processed for the new render
self.samples_processed = 0;

// Update total_samples_per_loop for the new render
if let Some(next_render) = next_render_option.as_ref() {
if !next_render.is_empty() {
self.total_samples_per_loop = next_render[0].ops.iter().map(|op| op.samples).sum();
}
}

// Send visualization reset event if necessary
if let Some(vtx) = self.visualization.channel.clone() {
vtx.send(VisEvent::Reset)
.expect("couldn't send VisEvent::Reset");
};
.expect("Couldn't send VisEvent::Reset");
}

*self.current_render() = None;
self.render_idx = (self.render_idx + 1) % 2;
}

pub fn current_render(&mut self) -> &mut Option<Vec<RenderVoice>> {
Expand All @@ -265,12 +369,16 @@ impl RenderManager {
&mut self.renders[(self.render_idx + 1) % 2]
}

pub fn exists_current_render(&mut self) -> bool {
self.current_render().is_some()
pub fn current_render_ref(&self) -> &Option<Vec<RenderVoice>> {
&self.renders[self.render_idx]
}

pub fn exists_current_render(&self) -> bool {
self.renders[(self.render_idx) % 2].is_some()
}

pub fn exists_next_render(&mut self) -> bool {
self.next_render().is_some()
pub fn exists_next_render(&self) -> bool {
self.renders[(self.render_idx + 1) % 2].is_some()
}

pub fn push_render(&mut self, render: Vec<RenderVoice>, once: bool) {
Expand Down
4 changes: 2 additions & 2 deletions core/src/portaudio/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
pub mod duplex;
pub mod real_time;
// pub mod real_time;
pub mod real_time_buffer_manager;
pub mod real_time_render_manager;
pub mod real_time_render_manager_mic;

pub use self::duplex::duplex_setup;
pub use self::real_time::real_time;
// pub use self::real_time::real_time;
pub use self::real_time_buffer_manager::real_time_buffer_manager;
pub use self::real_time_render_manager::real_time_render_manager;
pub use self::real_time_render_manager_mic::real_time_render_manager_mic;
Loading

0 comments on commit d3bb66c

Please sign in to comment.