1
0
Fork 0

Implement state handling for CLAP

This commit is contained in:
Robbert van der Helm 2022-03-02 16:25:30 +01:00
parent ec452bd41d
commit 7e9eadfc64
2 changed files with 87 additions and 5 deletions

View file

@ -48,8 +48,8 @@ use crate::buffer::Buffer;
use crate::event_loop::{EventLoop, MainThreadExecutor, TASK_QUEUE_CAPACITY};
use crate::param::internals::ParamPtr;
use crate::plugin::{BufferConfig, BusConfig, ClapPlugin, NoteEvent, ProcessStatus};
use crate::wrapper::state;
use crate::wrapper::util::{hash_param_id, process_wrapper, strlcpy};
use crate::Plugin;
/// Right now the wrapper adds its own bypass parameter.
///
@ -849,7 +849,7 @@ impl<P: ClapPlugin> Wrapper<P> {
let name = match channel_count {
1 => format!("Mono {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 {
1 => CLAP_PORT_MONO,
@ -1072,14 +1072,96 @@ impl<P: ClapPlugin> Wrapper<P> {
check_null_ptr!(false, plugin, stream);
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(
plugin: *const clap_plugin,
stream: *mut clap_istream,
) -> 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
}
}

View file

@ -209,7 +209,7 @@ impl<P: Vst3Plugin> IComponent for Wrapper<P> {
);
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
// read.
if read_buffer.len() != stream_byte_size as usize {