mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-07 03:50:11 +02:00
Change audio SHM buffer offsets to be in bytes
CLAP allows mixed precision ports. For instance, the main IO ports can be 32-bit only, while some CV ports allow 64-bit audio. The plugin only knows the sample format it receives when the process call happens, so we'll always need to allocate enough space for that to work.
This commit is contained in:
+18
-13
@@ -75,17 +75,22 @@ class AudioShmBuffer {
|
||||
uint32_t size;
|
||||
|
||||
/**
|
||||
* Offsets **in samples** within the shared memory object for an input
|
||||
* Offsets **in bytes** within the shared memory object for an input
|
||||
* audio channel, indexed by `[bus][channel]`. For VST2 plugins the bus
|
||||
* will always be 0. This can be used later to retrieve a pointer to the
|
||||
* audio channel.
|
||||
*
|
||||
* The offsets are in bytes rather than in samples to accommodate mixed
|
||||
* 32-bit and 64-bit IO. This is allowed in CLAP. If a port can do
|
||||
* either 32-bit or 64-bit audio, we'll reserve enough space for 64-bit
|
||||
* samples and then just not use the latter half if the host ends up
|
||||
* using 32-bit samples.
|
||||
*/
|
||||
std::vector<std::vector<uint32_t>> input_offsets;
|
||||
/**
|
||||
* Offsets **in samples** within the shared memory object for an output
|
||||
* audio channel, indexed by `[bus][channel]`. For VST2 plugins the bus
|
||||
* will always be 0. This can be used later to retrieve a pointer to the
|
||||
* audio channel.
|
||||
* Offsets **in bytes** within the shared memory object for an output
|
||||
* audio channel, indexed by `[bus][channel]`. See `input_offsets` for
|
||||
* more details.
|
||||
*/
|
||||
std::vector<std::vector<uint32_t>> output_offsets;
|
||||
|
||||
@@ -151,16 +156,16 @@ class AudioShmBuffer {
|
||||
template <typename T>
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
T* input_channel_ptr(const uint32_t bus, const uint32_t channel) noexcept {
|
||||
return reinterpret_cast<T*>(shm_bytes_) +
|
||||
config_.input_offsets[bus][channel];
|
||||
return reinterpret_cast<T*>(shm_bytes_ +
|
||||
config_.input_offsets[bus][channel]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
const T* input_channel_ptr(const uint32_t bus,
|
||||
const uint32_t channel) const noexcept {
|
||||
return reinterpret_cast<const T*>(shm_bytes_) +
|
||||
config_.input_offsets[bus][channel];
|
||||
return reinterpret_cast<const T*>(shm_bytes_ +
|
||||
config_.input_offsets[bus][channel]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,16 +176,16 @@ class AudioShmBuffer {
|
||||
template <typename T>
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
T* output_channel_ptr(const uint32_t bus, const uint32_t channel) noexcept {
|
||||
return reinterpret_cast<T*>(shm_bytes_) +
|
||||
config_.output_offsets[bus][channel];
|
||||
return reinterpret_cast<T*>(shm_bytes_ +
|
||||
config_.output_offsets[bus][channel]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
const T* output_channel_ptr(const uint32_t bus,
|
||||
const uint32_t channel) const noexcept {
|
||||
return reinterpret_cast<const T*>(shm_bytes_) +
|
||||
config_.output_offsets[bus][channel];
|
||||
return reinterpret_cast<const T*>(shm_bytes_ +
|
||||
config_.output_offsets[bus][channel]);
|
||||
}
|
||||
|
||||
Config config_;
|
||||
|
||||
@@ -795,30 +795,34 @@ intptr_t Vst2Bridge::dispatch_wrapper(AEffect* plugin,
|
||||
}
|
||||
|
||||
AudioShmBuffer::Config Vst2Bridge::setup_shared_audio_buffers() {
|
||||
assert(max_samples_per_block_);
|
||||
|
||||
// We'll first compute the size and channel offsets for our buffer based on
|
||||
// the information already passed to us by the host. The offsets for each
|
||||
// audio channel are in samples (since they'll be used with pointer
|
||||
// arithmetic in `AudioShmBuffer`), and we'll only use the first bus (since
|
||||
// VST2 plugins don't have multiple audio busses).
|
||||
assert(max_samples_per_block_);
|
||||
// audio channel are in bytes because CLAP allows some ports to be 32-bit
|
||||
// only while other others are mixed 32-bit and 64-bit if the plugin opts in
|
||||
// to it, and the plugin only knows what format it receives during the
|
||||
// process call.
|
||||
const size_t sample_size =
|
||||
(double_precision_ ? sizeof(double) : sizeof(float));
|
||||
|
||||
uint32_t current_offset = 0;
|
||||
|
||||
std::vector<uint32_t> input_channel_offsets(plugin_->numInputs);
|
||||
for (int channel = 0; channel < plugin_->numInputs; channel++) {
|
||||
input_channel_offsets[channel] = current_offset;
|
||||
current_offset += *max_samples_per_block_;
|
||||
current_offset += *max_samples_per_block_ * sample_size;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> output_channel_offsets(plugin_->numOutputs);
|
||||
for (int channel = 0; channel < plugin_->numOutputs; channel++) {
|
||||
output_channel_offsets[channel] = current_offset;
|
||||
current_offset += *max_samples_per_block_;
|
||||
current_offset += *max_samples_per_block_ * sample_size;
|
||||
}
|
||||
|
||||
// The size of the buffer is in bytes, and it will depend on whether the
|
||||
// host is going to pass 32-bit or 64-bit audio to the plugin
|
||||
const uint32_t buffer_size =
|
||||
current_offset * (double_precision_ ? sizeof(double) : sizeof(float));
|
||||
const uint32_t buffer_size = current_offset;
|
||||
|
||||
// We'll set up these shared memory buffers on the Wine side first, and then
|
||||
// when this request returns we'll do the same thing on the native plugin
|
||||
|
||||
@@ -1376,8 +1376,15 @@ std::optional<AudioShmBuffer::Config> Vst3Bridge::setup_shared_audio_buffers(
|
||||
|
||||
// We'll query the plugin for its audio bus layouts, and then create
|
||||
// calculate the offsets in a large memory buffer for the different audio
|
||||
// channels. The offsets for each audio channel are in samples (since
|
||||
// they'll be used with pointer arithmetic in `AudioShmBuffer`).
|
||||
// channels. The offsets for each audio channel are in bytes because CLAP
|
||||
// allows some ports to be 32-bit only while other others are mixed 32-bit
|
||||
// and 64-bit if the plugin opts in to it, and the plugin only knows what
|
||||
// format it receives during the process call.
|
||||
const bool double_precision =
|
||||
instance.process_setup->symbolicSampleSize == Steinberg::Vst::kSample64;
|
||||
const size_t sample_size =
|
||||
(double_precision ? sizeof(double) : sizeof(float));
|
||||
|
||||
uint32_t current_offset = 0;
|
||||
|
||||
auto create_bus_offsets = [&, &setup = instance.process_setup](
|
||||
@@ -1404,7 +1411,7 @@ std::optional<AudioShmBuffer::Config> Vst3Bridge::setup_shared_audio_buffers(
|
||||
|
||||
for (size_t channel = 0; channel < num_channels; channel++) {
|
||||
bus_offsets[bus][channel] = current_offset;
|
||||
current_offset += setup->maxSamplesPerBlock;
|
||||
current_offset += setup->maxSamplesPerBlock * sample_size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1419,10 +1426,7 @@ std::optional<AudioShmBuffer::Config> Vst3Bridge::setup_shared_audio_buffers(
|
||||
|
||||
// The size of the buffer is in bytes, and it will depend on whether the
|
||||
// host is going to pass 32-bit or 64-bit audio to the plugin
|
||||
const bool double_precision =
|
||||
instance.process_setup->symbolicSampleSize == Steinberg::Vst::kSample64;
|
||||
const uint32_t buffer_size =
|
||||
current_offset * (double_precision ? sizeof(double) : sizeof(float));
|
||||
const uint32_t buffer_size = current_offset;
|
||||
|
||||
// If this function has been called previously and the size did not change,
|
||||
// then we should not do any work
|
||||
|
||||
Reference in New Issue
Block a user