Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide helpers to get I/O buffers in OnAudioBuffer handlers #56

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions main/medium/src/audio_hook_register.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::{decode_user_data, encode_user_data, Hz};
use reaper_low::raw::audio_hook_register_t;
use reaper_low::raw::{audio_hook_register_t, ReaSample};
use reaper_low::{firewall, raw};

use std::fmt;
use std::fmt::Debug;
use std::os::raw::c_int;
use std::ptr::{null_mut, NonNull};
use std::slice::{from_raw_parts_mut};

/// Consumers need to implement this trait in order to be called back in the real-time audio thread.
///
Expand Down Expand Up @@ -58,7 +59,35 @@ impl AudioHookRegister {

/// Returns the current number of output channels.
pub fn output_nch(&self) -> u32 {
unsafe { self.0.as_ref() }.input_nch as u32
unsafe { self.0.as_ref() }.output_nch as u32
}

/// Get access to the underlying samples of an output channel
pub fn output_channel_samples(&self, ch: usize, args: &OnAudioBufferArgs) -> Option<&mut [ReaSample]> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One goal of the medium-level API is to not change the naming too much. It would be more in line with the other code to have only one method get_buffer() and introduce a BufferKind enum to distinguish between input and output buffer (built analogously to e.g. enum RecordArmMode in misc_enums.rs).

Another goal is to use consistent data types. Therefore I would prefer u32 as channel type instead of usize (input_nch() and output_nch() both return u32 values).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, will change accordingly.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of passing the OnAudioBufferArgs parameter, I think it would make sense to make get_buffer() a method of the OnAudioBufferArgs struct itself - because it contains a reference to the AudioHookRegister and therefore has all information necessary to implement the method.

The final signature in OnAudioBufferArgs would look like this:

pub fn get_buffer(&self, kind: BufferKind, ch: u32) -> Option<&mut [ReaSample]>

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try it this way and update the PR.

unsafe {
if let Some(get_buffer) = self.0.as_ref().GetBuffer {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know, GetBuffer is supposed to always return Some in the context in which we access it (as parameter of OnAudioBuffer). Therefore it would be consequent to panic here with expect() instead of returning None. This makes sure that if REAPER really returns a null pointer one day, we become aware of that change in the contract and can handle that accordingly (e.g. by adjusting the signature). That's at least the approach I have pursued so far in reaper-rs.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I'll change it.

let ptr = get_buffer(true, ch as i32);
if ptr != null_mut() {
return Some(from_raw_parts_mut(ptr, args.len as usize));
}
}
}

None
}

/// Get access to the underlying samples of an input channel
pub fn input_channel_samples(&self, ch: usize, args: &OnAudioBufferArgs) -> Option<&mut [ReaSample]> {
unsafe {
if let Some(get_buffer) = self.0.as_ref().GetBuffer {
let ptr = get_buffer(false, ch as i32);
if ptr != null_mut() {
return Some(from_raw_parts_mut(ptr, args.len as usize));
}
}
}

None
}
}

Expand Down