Skip to content

Commit

Permalink
Medium-level API: Add AudioAccessor with corresponding functions.
Browse files Browse the repository at this point in the history
`AudioAccessor` in ptr_wrappers.rs
`create_track_audio_accessor`
`create_take_audio_accessor`
`destroy_audio_accessor`
`audio_accessor_state_changed`
`audio_accessor_update`
`audio_accessor_validate_state`
`get_audio_accessor_end_time`
`get_audio_accessor_start_time`
`get_audio_accessor_samples`
`GetAudioAccessorHash` is not wrapped, as it is deprecated.
Low-level API: Fixed AudioAccessor to be ReaperPointer


applied cargo fmt


restricted to MainThreadOnly
  • Loading branch information
Levitanus committed Dec 14, 2022
1 parent cee86bb commit f982832
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 22 deletions.
28 changes: 14 additions & 14 deletions main/low/src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ use std::os::raw::{c_int, c_void};
/// Structs, types and constants defined by REAPER.
pub use super::bindings::root::{
accelerator_register_t, audio_hook_register_t, gaccel_register_t, midi_Input, midi_Output,
midi_realtime_write_struct_t, preview_register_t, reaper_plugin_info_t, IReaperControlSurface,
IReaperPitchShift, KbdCmd, KbdSectionInfo, MIDI_event_t, MIDI_eventlist, MediaItem,
MediaItem_Take, MediaTrack, PCM_sink, PCM_source, PCM_source_peaktransfer_t,
PCM_source_transfer_t, ProjectStateContext, REAPER_Resample_Interface, ReaProject, ReaSample,
TrackEnvelope, WDL_HeapBuf, CSURF_EXT_RESET, CSURF_EXT_SETBPMANDPLAYRATE,
CSURF_EXT_SETFOCUSEDFX, CSURF_EXT_SETFXCHANGE, CSURF_EXT_SETFXENABLED, CSURF_EXT_SETFXOPEN,
CSURF_EXT_SETFXPARAM, CSURF_EXT_SETFXPARAM_RECFX, CSURF_EXT_SETINPUTMONITOR,
CSURF_EXT_SETLASTTOUCHEDFX, CSURF_EXT_SETPAN_EX, CSURF_EXT_SETPROJECTMARKERCHANGE,
CSURF_EXT_SETRECVPAN, CSURF_EXT_SETRECVVOLUME, CSURF_EXT_SETSENDPAN, CSURF_EXT_SETSENDVOLUME,
CSURF_EXT_SUPPORTS_EXTENDED_TOUCH, CSURF_EXT_TRACKFX_PRESET_CHANGED,
PCM_SOURCE_EXT_EXPORTTOFILE, PCM_SOURCE_EXT_GETPOOLEDMIDIID, PCM_SOURCE_EXT_OPENEDITOR,
PCM_SOURCE_EXT_SETPREVIEWTEMPO, REAPER_PITCHSHIFT_API_VER, REAPER_PLUGIN_VERSION,
RESAMPLE_EXT_SETRSMODE, UNDO_STATE_ALL, UNDO_STATE_FREEZE, UNDO_STATE_FX, UNDO_STATE_ITEMS,
UNDO_STATE_MISCCFG, UNDO_STATE_TRACKCFG,
midi_realtime_write_struct_t, preview_register_t, reaper_functions::AudioAccessor,
reaper_plugin_info_t, IReaperControlSurface, IReaperPitchShift, KbdCmd, KbdSectionInfo,
MIDI_event_t, MIDI_eventlist, MediaItem, MediaItem_Take, MediaTrack, PCM_sink, PCM_source,
PCM_source_peaktransfer_t, PCM_source_transfer_t, ProjectStateContext,
REAPER_Resample_Interface, ReaProject, ReaSample, TrackEnvelope, WDL_HeapBuf, CSURF_EXT_RESET,
CSURF_EXT_SETBPMANDPLAYRATE, CSURF_EXT_SETFOCUSEDFX, CSURF_EXT_SETFXCHANGE,
CSURF_EXT_SETFXENABLED, CSURF_EXT_SETFXOPEN, CSURF_EXT_SETFXPARAM, CSURF_EXT_SETFXPARAM_RECFX,
CSURF_EXT_SETINPUTMONITOR, CSURF_EXT_SETLASTTOUCHEDFX, CSURF_EXT_SETPAN_EX,
CSURF_EXT_SETPROJECTMARKERCHANGE, CSURF_EXT_SETRECVPAN, CSURF_EXT_SETRECVVOLUME,
CSURF_EXT_SETSENDPAN, CSURF_EXT_SETSENDVOLUME, CSURF_EXT_SUPPORTS_EXTENDED_TOUCH,
CSURF_EXT_TRACKFX_PRESET_CHANGED, PCM_SOURCE_EXT_EXPORTTOFILE, PCM_SOURCE_EXT_GETPOOLEDMIDIID,
PCM_SOURCE_EXT_OPENEDITOR, PCM_SOURCE_EXT_SETPREVIEWTEMPO, REAPER_PITCHSHIFT_API_VER,
REAPER_PLUGIN_VERSION, RESAMPLE_EXT_SETRSMODE, UNDO_STATE_ALL, UNDO_STATE_FREEZE,
UNDO_STATE_FX, UNDO_STATE_ITEMS, UNDO_STATE_MISCCFG, UNDO_STATE_TRACKCFG,
};

/// Structs, types and constants defined by `swell.h` (on Linux and Mac OS X) and
Expand Down
2 changes: 2 additions & 0 deletions main/medium/src/ptr_wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ pub type MediaItem = NonNull<raw::MediaItem>;
pub type MediaItemTake = NonNull<raw::MediaItem_Take>;
/// Pointer to an envelope on a track.
pub type TrackEnvelope = NonNull<raw::TrackEnvelope>;
/// Pointer to an audio accessor on track or take.
pub type AudioAccessor = NonNull<raw::AudioAccessor>;
/// Pointer to a window (window handle).
pub type Hwnd = NonNull<raw::HWND__>;
/// Pointer to a module/instance (module/instance handle).
Expand Down
166 changes: 159 additions & 7 deletions main/medium/src/reaper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ use reaper_low::{raw, register_plugin_destroy_hook};

use crate::ProjectContext::CurrentProject;
use crate::{
require_non_null_panic, Accel, ActionValueChange, AddFxBehavior, AudioDeviceAttributeKey,
AutoSeekBehavior, AutomationMode, BookmarkId, BookmarkRef, Bpm, ChunkCacheHint, CommandId, Db,
DurationInSeconds, EditMode, EnvChunkName, FxAddByNameBehavior, FxChainVisibility, FxPresetRef,
FxShowInstruction, GangBehavior, GlobalAutomationModeOverride, HelpMode, Hidden, Hwnd,
InitialAction, InputMonitoringMode, InsertMediaFlag, InsertMediaMode, KbdSectionInfo,
MasterTrackBehavior, MeasureMode, MediaItem, MediaItemTake, MediaTrack, MessageBoxResult,
MessageBoxType, MidiImportBehavior, MidiInput, MidiInputDeviceId, MidiOutput,
require_non_null_panic, Accel, ActionValueChange, AddFxBehavior, AudioAccessor,
AudioDeviceAttributeKey, AutoSeekBehavior, AutomationMode, BookmarkId, BookmarkRef, Bpm,
ChunkCacheHint, CommandId, Db, DurationInSeconds, EditMode, EnvChunkName, FxAddByNameBehavior,
FxChainVisibility, FxPresetRef, FxShowInstruction, GangBehavior, GlobalAutomationModeOverride,
HelpMode, Hidden, Hwnd, InitialAction, InputMonitoringMode, InsertMediaFlag, InsertMediaMode,
KbdSectionInfo, MasterTrackBehavior, MeasureMode, MediaItem, MediaItemTake, MediaTrack,
MessageBoxResult, MessageBoxType, MidiImportBehavior, MidiInput, MidiInputDeviceId, MidiOutput,
MidiOutputDeviceId, NativeColor, NormalizedPlayRate, NotificationBehavior, OwnedPcmSource,
OwnedReaperPitchShift, OwnedReaperResample, PanMode, ParamId, PcmSource, PitchShiftMode,
PitchShiftSubMode, PlaybackSpeedFactor, PluginContext, PositionInBeats, PositionInQuarterNotes,
Expand Down Expand Up @@ -2405,6 +2405,158 @@ impl<UsageScope> Reaper<UsageScope> {
self.low.ClearConsole();
}

/// # Safety
///
/// REAPER can crash if you pass an invalid track.
/// AudioAccessor has to be destroyed.
pub unsafe fn create_track_audio_accessor(&self, track: MediaTrack) -> AudioAccessor
where
UsageScope: MainThreadOnly,
{
self.require_main_thread();
AudioAccessor::new_unchecked(self.low().CreateTrackAudioAccessor(track.as_ptr()))
}

/// # Safety
///
/// REAPER can crash if you pass an invalid take.
/// AudioAccessor has to be destroyed.
pub unsafe fn create_take_audio_accessor(&self, take: MediaItemTake) -> AudioAccessor
where
UsageScope: MainThreadOnly,
{
self.require_main_thread();
AudioAccessor::new_unchecked(self.low().CreateTakeAudioAccessor(take.as_ptr()))
}

/// Should be called after using of AudioAccessor.
///
/// # Safety
///
/// REAPER can crash if you pass an invalid audio accessor.
pub unsafe fn destroy_audio_accessor(&self, mut accessor: AudioAccessor)
where
UsageScope: MainThreadOnly,
{
self.require_main_thread();
self.low().DestroyAudioAccessor(accessor.as_mut())
}

/// Returns true if the underlying samples (track or media item take)
/// have changed
///
/// # Note
///
/// Does not update the audio accessor, so the user can selectively
/// call AudioAccessorValidateState only when needed.
///
/// # Safety
///
/// REAPER can crash if you pass an invalid audio accessor.
pub unsafe fn audio_accessor_state_changed(&self, accessor: AudioAccessor) -> bool
where
UsageScope: MainThreadOnly,
{
self.require_main_thread();
self.low().AudioAccessorStateChanged(accessor.as_ptr())
}

/// Force the accessor to reload its state from the underlying
/// track or media item take.
///
/// # Safety
///
/// REAPER can crash if you pass an invalid audio accessor.
pub unsafe fn audio_accessor_update(&self, mut accessor: AudioAccessor)
where
UsageScope: MainThreadOnly,
{
self.require_main_thread();
self.low().AudioAccessorUpdate(accessor.as_mut())
}

/// Validates the current state of the audio accessor.
///
/// Returns true if the state changed.
///
/// # Safety
///
/// REAPER can crash if you pass an invalid audio accessor.
pub unsafe fn audio_accessor_validate_state(&self, mut accessor: AudioAccessor) -> bool
where
UsageScope: MainThreadOnly,
{
self.require_main_thread();
self.low().AudioAccessorValidateState(accessor.as_mut())
}

/// Get the end time of the audio that can be returned from this accessor.
///
/// # Safety
///
/// REAPER can crash if you pass an invalid audio accessor.
pub unsafe fn get_audio_accessor_end_time(&self, accessor: AudioAccessor) -> PositionInSeconds
where
UsageScope: MainThreadOnly,
{
self.require_main_thread();
PositionInSeconds::new(self.low().GetAudioAccessorEndTime(accessor.as_ptr()))
}

/// Get the start time of the audio that can be returned from this accessor.
///
/// # Safety
///
/// REAPER can crash if you pass an invalid audio accessor.
pub unsafe fn get_audio_accessor_start_time(&self, accessor: AudioAccessor) -> PositionInSeconds
where
UsageScope: MainThreadOnly,
{
self.require_main_thread();
PositionInSeconds::new(self.low().GetAudioAccessorStartTime(accessor.as_ptr()))
}

/// Get a block of samples from the audio accessor.
///
/// Samples are extracted immediately pre-FX,
/// and returned interleaved (first sample of first channel,
/// first sample of second channel...).
///
/// Returns false if no audio, true if audio
///
/// # Safety
///
/// REAPER can crash if you pass an invalid audio accessor.
pub unsafe fn get_audio_accessor_samples(
&self,
accessor: AudioAccessor,
samplerate: u32,
channels_amount: u32,
start_time: PositionInSeconds,
samples_per_channel: u32,
mut sample_buffer: Vec<f64>,
) -> ReaperFunctionResult<bool>
where
UsageScope: MainThreadOnly,
{
self.require_main_thread();
let result = self.low().GetAudioAccessorSamples(
accessor.as_ptr(),
samplerate as i32,
channels_amount as i32,
start_time.get(),
samples_per_channel as i32,
sample_buffer.as_mut_ptr(),
);
match result {
0 => Ok(false),
1 => Ok(true),
_ => Err(ReaperFunctionError::new(
"Can not get samples from accessor.",
)),
}
}

/// Returns the number of tracks in the given project.
///
/// # Panics
Expand Down
6 changes: 5 additions & 1 deletion main/medium/src/reaper_pointer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{MediaItem, MediaItemTake, MediaTrack, ReaProject, TrackEnvelope};
use crate::{concat_reaper_strs, PcmSource, ReaperStr, ReaperStringArg};
use crate::{concat_reaper_strs, AudioAccessor, PcmSource, ReaperStr, ReaperStringArg};

use std::borrow::Cow;
use std::os::raw::c_void;
Expand All @@ -13,6 +13,7 @@ pub enum ReaperPointer<'a> {
MediaItemTake(MediaItemTake),
TrackEnvelope(TrackEnvelope),
PcmSource(PcmSource),
AudioAccessor(AudioAccessor),
/// If a variant is missing in this enum, you can use this custom one as a resort.
///
/// Use [`custom()`] to create this variant.
Expand Down Expand Up @@ -49,6 +50,7 @@ impl<'a> ReaperPointer<'a> {
MediaItemTake(_) => reaper_str!("MediaItem_Take*").into(),
TrackEnvelope(_) => reaper_str!("TrackEnvelope*").into(),
PcmSource(_) => reaper_str!("PCM_source*").into(),
AudioAccessor(_) => reaper_str!("AudioAccessor*").into(),
Custom {
pointer: _,
type_name,
Expand All @@ -65,6 +67,7 @@ impl<'a> ReaperPointer<'a> {
MediaItemTake(p) => p.as_ptr() as *mut _,
TrackEnvelope(p) => p.as_ptr() as *mut _,
PcmSource(p) => p.as_ptr() as *mut _,
AudioAccessor(p) => p.as_ptr() as *mut _,
Custom { pointer, .. } => *pointer,
}
}
Expand All @@ -87,3 +90,4 @@ impl_from_ptr_to_variant!(MediaItem, MediaItem);
impl_from_ptr_to_variant!(MediaItemTake, MediaItemTake);
impl_from_ptr_to_variant!(TrackEnvelope, TrackEnvelope);
impl_from_ptr_to_variant!(PcmSource, PcmSource);
impl_from_ptr_to_variant!(AudioAccessor, AudioAccessor);

0 comments on commit f982832

Please sign in to comment.