Implement state handling for CLAP
This commit is contained in:
parent
ec452bd41d
commit
7e9eadfc64
2 changed files with 87 additions and 5 deletions
|
@ -48,8 +48,8 @@ use crate::buffer::Buffer;
|
||||||
use crate::event_loop::{EventLoop, MainThreadExecutor, TASK_QUEUE_CAPACITY};
|
use crate::event_loop::{EventLoop, MainThreadExecutor, TASK_QUEUE_CAPACITY};
|
||||||
use crate::param::internals::ParamPtr;
|
use crate::param::internals::ParamPtr;
|
||||||
use crate::plugin::{BufferConfig, BusConfig, ClapPlugin, NoteEvent, ProcessStatus};
|
use crate::plugin::{BufferConfig, BusConfig, ClapPlugin, NoteEvent, ProcessStatus};
|
||||||
|
use crate::wrapper::state;
|
||||||
use crate::wrapper::util::{hash_param_id, process_wrapper, strlcpy};
|
use crate::wrapper::util::{hash_param_id, process_wrapper, strlcpy};
|
||||||
use crate::Plugin;
|
|
||||||
|
|
||||||
/// Right now the wrapper adds its own bypass parameter.
|
/// Right now the wrapper adds its own bypass parameter.
|
||||||
///
|
///
|
||||||
|
@ -849,7 +849,7 @@ impl<P: ClapPlugin> Wrapper<P> {
|
||||||
let name = match channel_count {
|
let name = match channel_count {
|
||||||
1 => format!("Mono {port_type_name}"),
|
1 => format!("Mono {port_type_name}"),
|
||||||
2 => format!("Stereo {port_type_name}"),
|
2 => format!("Stereo {port_type_name}"),
|
||||||
n => format!("{channel_count} channel {port_type_name}"),
|
n => format!("{n} channel {port_type_name}"),
|
||||||
};
|
};
|
||||||
let port_type = match channel_count {
|
let port_type = match channel_count {
|
||||||
1 => CLAP_PORT_MONO,
|
1 => CLAP_PORT_MONO,
|
||||||
|
@ -1072,14 +1072,96 @@ impl<P: ClapPlugin> Wrapper<P> {
|
||||||
check_null_ptr!(false, plugin, stream);
|
check_null_ptr!(false, plugin, stream);
|
||||||
let wrapper = &*(plugin as *const Self);
|
let wrapper = &*(plugin as *const Self);
|
||||||
|
|
||||||
todo!()
|
let serialized = state::serialize(
|
||||||
|
wrapper.plugin.read().params(),
|
||||||
|
&wrapper.param_by_hash,
|
||||||
|
&wrapper.param_id_to_hash,
|
||||||
|
BYPASS_PARAM_ID,
|
||||||
|
&wrapper.bypass_state,
|
||||||
|
);
|
||||||
|
match serialized {
|
||||||
|
Ok(serialized) => {
|
||||||
|
let num_bytes_written = ((*stream).write)(
|
||||||
|
stream,
|
||||||
|
serialized.as_ptr() as *const c_void,
|
||||||
|
serialized.len() as u64,
|
||||||
|
);
|
||||||
|
|
||||||
|
nih_debug_assert_eq!(num_bytes_written as usize, serialized.len());
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
nih_debug_assert_failure!("Could not save state: {}", err);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn ext_state_load(
|
unsafe extern "C" fn ext_state_load(
|
||||||
plugin: *const clap_plugin,
|
plugin: *const clap_plugin,
|
||||||
stream: *mut clap_istream,
|
stream: *mut clap_istream,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
todo!()
|
check_null_ptr!(false, plugin, stream);
|
||||||
|
let wrapper = &*(plugin as *const Self);
|
||||||
|
|
||||||
|
// CLAP does not have a way to tell you about the size of a stream, so the workaround would
|
||||||
|
// be to keep reading 1 MiB chunks until we reach the end of file, reallocating the buffer
|
||||||
|
// each time as we go.
|
||||||
|
const CHUNK_SIZE: usize = 1 << 20;
|
||||||
|
let mut actual_read_buffer_size = 0usize;
|
||||||
|
let mut read_buffer: Vec<u8> = Vec::with_capacity(CHUNK_SIZE);
|
||||||
|
loop {
|
||||||
|
let num_bytes_read = ((*stream).read)(
|
||||||
|
stream,
|
||||||
|
// Make sure to start reading from where we left off if we're going through this
|
||||||
|
// loop multiple times
|
||||||
|
read_buffer.as_mut_ptr().add(actual_read_buffer_size) as *mut c_void,
|
||||||
|
CHUNK_SIZE as u64,
|
||||||
|
);
|
||||||
|
if num_bytes_read < 0 {
|
||||||
|
nih_debug_assert_failure!("Error while reading plugin state");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
actual_read_buffer_size += num_bytes_read as usize;
|
||||||
|
if num_bytes_read != CHUNK_SIZE as i64 {
|
||||||
|
// If we read anything below `CHUNK_SIZE` bytes, then we've reached the end of file
|
||||||
|
// on this read
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, reallocate the buffer with enough room for another chunk and try again
|
||||||
|
nih_debug_assert_eq!(num_bytes_read, CHUNK_SIZE as i64);
|
||||||
|
read_buffer.reserve(CHUNK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// After reading, trim the additional capacity near the end of the buffer
|
||||||
|
read_buffer.set_len(actual_read_buffer_size as usize);
|
||||||
|
|
||||||
|
let success = state::deserialize(
|
||||||
|
&read_buffer,
|
||||||
|
wrapper.plugin.read().params(),
|
||||||
|
&wrapper.param_by_hash,
|
||||||
|
&wrapper.param_id_to_hash,
|
||||||
|
wrapper.current_buffer_config.load().as_ref(),
|
||||||
|
BYPASS_PARAM_ID,
|
||||||
|
&wrapper.bypass_state,
|
||||||
|
);
|
||||||
|
if !success {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reinitialize the plugin after loading state so it can respond to the new parameter values
|
||||||
|
let bus_config = wrapper.current_bus_config.load();
|
||||||
|
if let Some(buffer_config) = wrapper.current_buffer_config.load() {
|
||||||
|
wrapper.plugin.write().initialize(
|
||||||
|
&bus_config,
|
||||||
|
&buffer_config,
|
||||||
|
&mut wrapper.make_process_context(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -209,7 +209,7 @@ impl<P: Vst3Plugin> IComponent for Wrapper<P> {
|
||||||
);
|
);
|
||||||
read_buffer.set_len(num_bytes_read as usize);
|
read_buffer.set_len(num_bytes_read as usize);
|
||||||
|
|
||||||
// If the size is zero, some hsots will always return `kResultFalse` even if the read was
|
// If the size is zero, some hosts will always return `kResultFalse` even if the read was
|
||||||
// 'successful', so we can't check the return value but we can check the number of bytes
|
// 'successful', so we can't check the return value but we can check the number of bytes
|
||||||
// read.
|
// read.
|
||||||
if read_buffer.len() != stream_byte_size as usize {
|
if read_buffer.len() != stream_byte_size as usize {
|
||||||
|
|
Loading…
Add table
Reference in a new issue