diff --git a/src/common/audio-shm.h b/src/common/audio-shm.h index e952e628..520b7c73 100644 --- a/src/common/audio-shm.h +++ b/src/common/audio-shm.h @@ -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> 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> output_offsets; @@ -151,16 +156,16 @@ class AudioShmBuffer { template // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) T* input_channel_ptr(const uint32_t bus, const uint32_t channel) noexcept { - return reinterpret_cast(shm_bytes_) + - config_.input_offsets[bus][channel]; + return reinterpret_cast(shm_bytes_ + + config_.input_offsets[bus][channel]); } template // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) const T* input_channel_ptr(const uint32_t bus, const uint32_t channel) const noexcept { - return reinterpret_cast(shm_bytes_) + - config_.input_offsets[bus][channel]; + return reinterpret_cast(shm_bytes_ + + config_.input_offsets[bus][channel]); } /** @@ -171,16 +176,16 @@ class AudioShmBuffer { template // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) T* output_channel_ptr(const uint32_t bus, const uint32_t channel) noexcept { - return reinterpret_cast(shm_bytes_) + - config_.output_offsets[bus][channel]; + return reinterpret_cast(shm_bytes_ + + config_.output_offsets[bus][channel]); } template // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) const T* output_channel_ptr(const uint32_t bus, const uint32_t channel) const noexcept { - return reinterpret_cast(shm_bytes_) + - config_.output_offsets[bus][channel]; + return reinterpret_cast(shm_bytes_ + + config_.output_offsets[bus][channel]); } Config config_; diff --git a/src/wine-host/bridges/vst2.cpp b/src/wine-host/bridges/vst2.cpp index eb36ab22..cc7a7d44 100644 --- a/src/wine-host/bridges/vst2.cpp +++ b/src/wine-host/bridges/vst2.cpp @@ -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 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 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 diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index eac17cdd..a7378322 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -1376,8 +1376,15 @@ std::optional 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 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 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