Add a way to fetch the current processing mode
This commit is contained in:
parent
9601c9c0c1
commit
665108721a
8 changed files with 93 additions and 7 deletions
|
@ -24,6 +24,9 @@ pub trait ProcessContext {
|
|||
/// Get information about the current transport position and status.
|
||||
fn transport(&self) -> &Transport;
|
||||
|
||||
/// The current processing mode. The host will reinitialize the plugin any time this changes.
|
||||
fn process_mode(&self) -> ProcessMode;
|
||||
|
||||
/// Returns the next note event, if there is one. Use [`NoteEvent::timing()`] to get the event's
|
||||
/// timing within the buffer. Only available when
|
||||
/// [`Plugin::MIDI_INPUT`][crate::prelude::Plugin::MIDI_INPUT] is set.
|
||||
|
@ -204,6 +207,22 @@ pub enum PluginApi {
|
|||
Vst3,
|
||||
}
|
||||
|
||||
/// The plugin's current processing mode. Can be queried through [`ProcessContext::process_mode()`].
|
||||
/// The host will reinitialize the plugin whenever this changes.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ProcessMode {
|
||||
/// The plugin is processing audio in real time at a fixed rate.
|
||||
Realtime,
|
||||
/// The plugin is processing audio at a real time-like pace, but at irregular intervals. The
|
||||
/// host may do this to process audio ahead of time to loosen realtime constraints and to reduce
|
||||
/// the chance of xruns happening. This is only used by VST3.
|
||||
Buffered,
|
||||
/// The plugin is rendering audio offline, potentially faster than realtime ('freewheeling').
|
||||
/// The host will continuously call the process function back to back until all audio has been
|
||||
/// processed.
|
||||
Offline,
|
||||
}
|
||||
|
||||
impl Display for PluginApi {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
|
|
|
@ -11,7 +11,7 @@ pub use crate::formatters;
|
|||
pub use crate::util;
|
||||
|
||||
pub use crate::buffer::Buffer;
|
||||
pub use crate::context::{GuiContext, ParamSetter, PluginApi, ProcessContext};
|
||||
pub use crate::context::{GuiContext, ParamSetter, PluginApi, ProcessContext, ProcessMode};
|
||||
// This also includes the derive macro
|
||||
pub use crate::midi::{control_change, MidiConfig, NoteEvent};
|
||||
pub use crate::param::enums::{Enum, EnumParam};
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::sync::atomic::Ordering;
|
|||
use std::sync::Arc;
|
||||
|
||||
use super::wrapper::{OutputParamEvent, Task, Wrapper};
|
||||
use crate::context::{GuiContext, PluginApi, ProcessContext, Transport};
|
||||
use crate::context::{GuiContext, PluginApi, ProcessContext, ProcessMode, Transport};
|
||||
use crate::event_loop::EventLoop;
|
||||
use crate::midi::NoteEvent;
|
||||
use crate::param::internals::ParamPtr;
|
||||
|
@ -104,6 +104,10 @@ impl<P: ClapPlugin> ProcessContext for WrapperProcessContext<'_, P> {
|
|||
&self.transport
|
||||
}
|
||||
|
||||
fn process_mode(&self) -> ProcessMode {
|
||||
self.wrapper.current_process_mode.load()
|
||||
}
|
||||
|
||||
fn next_event(&mut self) -> Option<NoteEvent> {
|
||||
self.input_events_guard.pop_front()
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ use clap_sys::ext::params::{
|
|||
CLAP_PARAM_IS_MODULATABLE, CLAP_PARAM_IS_READONLY, CLAP_PARAM_IS_STEPPED,
|
||||
CLAP_PARAM_RESCAN_VALUES,
|
||||
};
|
||||
use clap_sys::ext::render::{
|
||||
clap_plugin_render, clap_plugin_render_mode, CLAP_RENDER_OFFLINE, CLAP_RENDER_REALTIME,
|
||||
};
|
||||
use clap_sys::ext::state::{clap_plugin_state, CLAP_EXT_STATE};
|
||||
use clap_sys::ext::tail::{clap_plugin_tail, CLAP_EXT_TAIL};
|
||||
use clap_sys::ext::thread_check::{clap_host_thread_check, CLAP_EXT_THREAD_CHECK};
|
||||
|
@ -75,7 +78,7 @@ use super::context::{WrapperGuiContext, WrapperProcessContext};
|
|||
use super::descriptor::PluginDescriptor;
|
||||
use super::util::ClapPtr;
|
||||
use crate::buffer::Buffer;
|
||||
use crate::context::Transport;
|
||||
use crate::context::{ProcessMode, Transport};
|
||||
use crate::event_loop::{EventLoop, MainThreadExecutor, TASK_QUEUE_CAPACITY};
|
||||
use crate::midi::{MidiConfig, NoteEvent};
|
||||
use crate::param::internals::{ParamPtr, Params};
|
||||
|
@ -125,6 +128,8 @@ pub struct Wrapper<P: ClapPlugin> {
|
|||
/// The current buffer configuration, containing the sample rate and the maximum block size.
|
||||
/// Will be set in `clap_plugin::activate()`.
|
||||
current_buffer_config: AtomicCell<Option<BufferConfig>>,
|
||||
/// The current audio processing mode. Set through the render extension. Defaults to realtime.
|
||||
pub current_process_mode: AtomicCell<ProcessMode>,
|
||||
/// The incoming events for the plugin, if `P::MIDI_INPUT` is set to `MidiConfig::Basic` or
|
||||
/// higher.
|
||||
///
|
||||
|
@ -217,6 +222,8 @@ pub struct Wrapper<P: ClapPlugin> {
|
|||
|
||||
host_thread_check: AtomicRefCell<Option<ClapPtr<clap_host_thread_check>>>,
|
||||
|
||||
clap_plugin_render: clap_plugin_render,
|
||||
|
||||
clap_plugin_state: clap_plugin_state,
|
||||
|
||||
clap_plugin_tail: clap_plugin_tail,
|
||||
|
@ -481,6 +488,7 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
num_output_channels: P::DEFAULT_NUM_OUTPUTS,
|
||||
}),
|
||||
current_buffer_config: AtomicCell::new(None),
|
||||
current_process_mode: AtomicCell::new(ProcessMode::Realtime),
|
||||
input_events: AtomicRefCell::new(VecDeque::with_capacity(512)),
|
||||
output_events: AtomicRefCell::new(VecDeque::with_capacity(512)),
|
||||
last_process_status: AtomicCell::new(ProcessStatus::Normal),
|
||||
|
@ -556,6 +564,11 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
|
||||
host_thread_check: AtomicRefCell::new(None),
|
||||
|
||||
clap_plugin_render: clap_plugin_render {
|
||||
has_hard_realtime_requirement: Self::ext_render_has_hard_realtime_requirement,
|
||||
set: Self::ext_render_set,
|
||||
},
|
||||
|
||||
clap_plugin_state: clap_plugin_state {
|
||||
save: Self::ext_state_save,
|
||||
load: Self::ext_state_load,
|
||||
|
@ -2620,6 +2633,33 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn ext_render_has_hard_realtime_requirement(
|
||||
_plugin: *const clap_plugin,
|
||||
) -> bool {
|
||||
// TODO: Add a constant on the CLapPlugin trait
|
||||
false
|
||||
}
|
||||
|
||||
unsafe extern "C" fn ext_render_set(
|
||||
plugin: *const clap_plugin,
|
||||
mode: clap_plugin_render_mode,
|
||||
) -> bool {
|
||||
check_null_ptr!(false, plugin);
|
||||
let wrapper = &*(plugin as *const Self);
|
||||
|
||||
let mode = match mode {
|
||||
CLAP_RENDER_REALTIME => ProcessMode::Realtime,
|
||||
CLAP_RENDER_OFFLINE => ProcessMode::Offline,
|
||||
n => {
|
||||
nih_debug_assert_failure!("Unknown rendering mode '{}', defaulting to realtime", n);
|
||||
ProcessMode::Realtime
|
||||
}
|
||||
};
|
||||
wrapper.current_process_mode.store(mode);
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
unsafe extern "C" fn ext_state_save(
|
||||
plugin: *const clap_plugin,
|
||||
stream: *const clap_ostream,
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
|||
|
||||
use super::backend::Backend;
|
||||
use super::wrapper::{GuiTask, Wrapper};
|
||||
use crate::context::{GuiContext, PluginApi, ProcessContext, Transport};
|
||||
use crate::context::{GuiContext, PluginApi, ProcessContext, ProcessMode, Transport};
|
||||
use crate::midi::NoteEvent;
|
||||
use crate::param::internals::ParamPtr;
|
||||
use crate::plugin::Plugin;
|
||||
|
@ -81,6 +81,11 @@ impl<P: Plugin, B: Backend> ProcessContext for WrapperProcessContext<'_, P, B> {
|
|||
&self.transport
|
||||
}
|
||||
|
||||
fn process_mode(&self) -> ProcessMode {
|
||||
// TODO: Detect JACK freewheeling and report it here
|
||||
ProcessMode::Realtime
|
||||
}
|
||||
|
||||
fn next_event(&mut self) -> Option<NoteEvent> {
|
||||
nih_debug_assert_failure!("TODO: WrapperProcessContext::next_event()");
|
||||
|
||||
|
|
|
@ -117,6 +117,10 @@ impl<P: Vst3Plugin> ProcessContext for WrapperProcessContext<'_, P> {
|
|||
&self.transport
|
||||
}
|
||||
|
||||
fn process_mode(&self) -> crate::context::ProcessMode {
|
||||
self.inner.current_process_mode.load()
|
||||
}
|
||||
|
||||
fn next_event(&mut self) -> Option<NoteEvent> {
|
||||
self.input_events_guard.pop_front()
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ use super::param_units::ParamUnits;
|
|||
use super::util::{ObjectPtr, VstPtr, VST3_MIDI_PARAMS_END, VST3_MIDI_PARAMS_START};
|
||||
use super::view::WrapperView;
|
||||
use crate::buffer::Buffer;
|
||||
use crate::context::Transport;
|
||||
use crate::context::{ProcessMode, Transport};
|
||||
use crate::event_loop::{EventLoop, MainThreadExecutor, OsEventLoop};
|
||||
use crate::midi::{MidiConfig, NoteEvent};
|
||||
use crate::param::internals::{ParamPtr, Params};
|
||||
|
@ -67,6 +67,8 @@ pub(crate) struct WrapperInner<P: Vst3Plugin> {
|
|||
/// The current buffer configuration, containing the sample rate and the maximum block size.
|
||||
/// Will be set in `IAudioProcessor::setupProcessing()`.
|
||||
pub current_buffer_config: AtomicCell<Option<BufferConfig>>,
|
||||
/// The current audio processing mode. Set in `IAudioProcessor::setup_processing()`.
|
||||
pub current_process_mode: AtomicCell<ProcessMode>,
|
||||
/// The last process status returned by the plugin. This is used for tail handling.
|
||||
pub last_process_status: AtomicCell<ProcessStatus>,
|
||||
/// The current latency in samples, as set by the plugin through the [`ProcessContext`].
|
||||
|
@ -277,6 +279,7 @@ impl<P: Vst3Plugin> WrapperInner<P> {
|
|||
num_output_channels: P::DEFAULT_NUM_OUTPUTS,
|
||||
}),
|
||||
current_buffer_config: AtomicCell::new(None),
|
||||
current_process_mode: AtomicCell::new(ProcessMode::Realtime),
|
||||
last_process_status: AtomicCell::new(ProcessStatus::Normal),
|
||||
current_latency: AtomicU32::new(0),
|
||||
output_buffer: AtomicRefCell::new(Buffer::default()),
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::mem::{self, MaybeUninit};
|
|||
use std::ptr;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use vst3_com::vst::IProcessContextRequirementsFlags;
|
||||
use vst3_com::vst::{IProcessContextRequirementsFlags, ProcessModes};
|
||||
use vst3_sys::base::{kInvalidArgument, kNoInterface, kResultFalse, kResultOk, tresult, TBool};
|
||||
use vst3_sys::base::{IBStream, IPluginBase};
|
||||
use vst3_sys::utils::SharedVstPtr;
|
||||
|
@ -23,7 +23,7 @@ use super::util::{
|
|||
u16strlcpy, VstPtr, VST3_MIDI_CCS, VST3_MIDI_NUM_PARAMS, VST3_MIDI_PARAMS_START,
|
||||
};
|
||||
use super::view::WrapperView;
|
||||
use crate::context::Transport;
|
||||
use crate::context::{ProcessMode, Transport};
|
||||
use crate::midi::{MidiConfig, NoteEvent};
|
||||
use crate::param::ParamFlags;
|
||||
use crate::plugin::{BufferConfig, BusConfig, ProcessStatus, Vst3Plugin};
|
||||
|
@ -690,6 +690,17 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
|
|||
max_buffer_size: setup.max_samples_per_block as u32,
|
||||
}));
|
||||
|
||||
let mode = match setup.process_mode {
|
||||
n if n == ProcessModes::kRealtime as i32 => ProcessMode::Realtime,
|
||||
n if n == ProcessModes::kPrefetch as i32 => ProcessMode::Buffered,
|
||||
n if n == ProcessModes::kOffline as i32 => ProcessMode::Offline,
|
||||
n => {
|
||||
nih_debug_assert_failure!("Unknown rendering mode '{}', defaulting to realtime", n);
|
||||
ProcessMode::Realtime
|
||||
}
|
||||
};
|
||||
self.inner.current_process_mode.store(mode);
|
||||
|
||||
// Initializing the plugin happens in `IAudioProcessor::set_active()` because the host may
|
||||
// still change the channel layouts at this point
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue