Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ out/*
# Ides/Agents
__pycache__/
.juggler/
.reasonix/
.vscode/
.idea/
.vs/
Expand All @@ -51,4 +52,3 @@ __pycache__/
.pytest_cache/
.cache/
docs/superpowers/
reasonix.toml
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- SDL3 windowing: mouse move/drag was broken on touch platforms (iOS, Android). Motion was synthesized only by polling `SDL_GetGlobalMouseState`, which has no backend implementation there and falls back to window-relative coordinates, so subtracting the window position shifted every move. Touch platforms now consume the touch-synthesized `SDL_EVENT_MOUSE_MOTION` events directly; desktop keeps the global-cursor poll (needed for embedded plugin editors).
- SDL3 windowing: mouse drag events were lost inside embedded plugin editors (notably on macOS, where the host owns the native application so SDL never receives Cocoa mouse focus and suppresses drag motion). Dragging is now synthesized by polling the global cursor while a button is held, on the message thread, for all platforms.
- UBSAN and ASAN fixes throughout the codebase
- AUv3 plugin host bypass is now connected to the processor: the wrapper-owned bypass parameter is created and drives `processBlockBypassed`, and host bypass state is persisted/restored inside the `YUPProcessorState` blob (legacy raw processor state still loads)
- Added bypass parameter handling tests for the AU, CLAP, and VST3 plugin client wrappers (routing to `processBlockBypassed`, bypass state round-trip, and text/value conversion)

---

Expand Down Expand Up @@ -229,6 +231,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- Standalone plugin support with improved audio parameters ([#46](https://github.com/kunitoki/yup/pull/46))
- CLAP/VST3/AU validators and code signing (`YUP_ENABLE_VST3_VALIDATOR`, etc.) ([#106](https://github.com/kunitoki/yup/pull/106))
- pluginval integration for automated VST3 validation ([#67](https://github.com/kunitoki/yup/pull/67))
- Sidechain and multi-bus audio input support across VST3, CLAP, AUv3, AUv2, AAX, and LV2: `AudioBus` gains a `Role` (`Main`/`Auxiliary`) and `isDefaultActive`, `AudioProcessContext` exposes per-bus `inputs`/`outputs` views (`AudioBusBufferView`) with `getMainInput()`/`getAuxiliaryInput()`/`getMainOutput()` accessors, and secondary input buses are forwarded to the processor instead of being discarded

#### Audio Formats (`yup_audio_formats`)
- New `yup_audio_formats` module: `AudioFormat`, `AudioFormatManager`, `AudioFormatReader`, `AudioFormatWriter`, WAV codec ([#51](https://github.com/kunitoki/yup/pull/51))
Expand Down
2 changes: 1 addition & 1 deletion cmake/platforms/mac/AudioUnitV3ContainerInfo.plist.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>@auv3_container_bundle_identifier@</string>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
Expand Down
1 change: 1 addition & 0 deletions cmake/plugins/yup_plugin_auv3.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ function (yup_plugin_auv3)
MACOSX_BUNDLE_INFO_PLIST "${auv3_container_plist_output}"
MACOSX_BUNDLE_BUNDLE_NAME "${YUP_ARG_PLUGIN_NAME}"
MACOSX_BUNDLE_GUI_IDENTIFIER "${auv3_container_bundle_identifier}"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${auv3_container_bundle_identifier}"
FOLDER "${target_ide_group}"
XCODE_GENERATE_SCHEME ON)

Expand Down
Binary file removed examples/plugin/data/RobotoFlex-VariableFont.ttf
Binary file not shown.
2 changes: 1 addition & 1 deletion modules/yup_audio_devices/yup_audio_devices.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@
Enable logging of audio device events on macOS, such as device changes and errors.
*/
#ifndef YUP_ENABLE_CORE_AUDIO_LOGGING
#define YUP_ENABLE_CORE_AUDIO_LOGGING 1
#define YUP_ENABLE_CORE_AUDIO_LOGGING 0
#endif

//==============================================================================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ YupPlugin_AAX_PlugInID_Native and YupPlugin_AAX_PlugInID_AudioSuite to be define
#endif
#endif

extern "C" yup::AudioProcessor* createPluginProcessor();
extern "C" yup::AudioProcessor* YUP_AUDIO_PLUGIN_CREATE_FUNCTION();

namespace yup
{
Expand Down Expand Up @@ -278,7 +278,7 @@ class YupAAX_Processor

YupAAX_Processor()
{
processor.reset (createPluginProcessor());
processor.reset (::YUP_AUDIO_PLUGIN_CREATE_FUNCTION());
processor->addListener (this);

AAX_CEffectParameters::GetNumberOfChunks (&yupChunkIndex);
Expand Down Expand Up @@ -613,6 +613,63 @@ class YupAAX_Processor
// Audio processing
//==========================================================================

// Builds one AudioBusBufferView per audio input bus from the flat array of
// host-provided input channel buffers. Channels are consumed in bus
// declaration order; channels beyond the host-provided count (e.g. an
// unconnected sidechain) are exposed as null channel pointers so
// processors see deterministic silence.
void buildInputBusViews (float* const* inputChannelData, int numIn)
{
inputBusViews.clear();

int chOffset = 0;

for (const auto& bus : processor->getBusLayout().getInputBuses())
{
if (bus.getType() != AudioBus::Type::Audio)
continue;

const int numCh = bus.getNumChannels();
auto* chPtrs = inputChannelPtrStorage.data() + chOffset;

for (int ch = 0; ch < numCh; ++ch)
chPtrs[ch] = (inputChannelData != nullptr && chOffset + ch < numIn)
? inputChannelData[chOffset + ch]
: nullptr;

inputBusViews.emplace_back (chPtrs, numCh, bus.getRole());

chOffset += numCh;
}
}

// Builds one AudioBusBufferView per audio output bus from the flat array of
// host-provided output channel buffers.
void buildOutputBusViews (float* const* outputChannelData, int numOut)
{
outputBusViews.clear();

int chOffset = 0;

for (const auto& bus : processor->getBusLayout().getOutputBuses())
{
if (bus.getType() != AudioBus::Type::Audio)
continue;

const int numCh = bus.getNumChannels();
auto* chPtrs = outputChannelPtrStorage.data() + chOffset;

for (int ch = 0; ch < numCh; ++ch)
chPtrs[ch] = (outputChannelData != nullptr && chOffset + ch < numOut)
? outputChannelData[chOffset + ch]
: nullptr;

outputBusViews.emplace_back (chPtrs, numCh, bus.getRole());

chOffset += numCh;
}
}

void process (float* const* inputChannelData,
float* const* outputChannelData,
int bufferSize,
Expand All @@ -636,12 +693,21 @@ class YupAAX_Processor
const auto numIn = layout.getNumAudioInputChannels();
const auto numOut = layout.getNumAudioOutputChannels();

// Only Main-role input channels are copied into the outputs; auxiliary
// (sidechain) channels must never leak into the main signal path. This
// assumes the main input buses are declared before auxiliary buses, which
// is the YUP layout convention (mirrored by VST3's kMain-before-kAux rule).
int numMainIn = 0;
for (const auto& bus : layout.getInputBuses())
if (bus.getType() == AudioBus::Type::Audio && bus.getRole() == AudioBus::Role::Main)
numMainIn += bus.getNumChannels();

for (int ch = 0; ch < numOut; ++ch)
{
if (outputChannelData[ch] == nullptr)
continue;

if (ch < numIn && inputChannelData[ch] != nullptr)
if (inputChannelData != nullptr && ch < numMainIn && inputChannelData[ch] != nullptr)
{
if (outputChannelData[ch] != inputChannelData[ch])
std::memcpy (outputChannelData[ch], inputChannelData[ch], static_cast<size_t> (bufferSize) * sizeof (float));
Expand All @@ -654,10 +720,18 @@ class YupAAX_Processor

AudioBuffer<float> audioBuffer (outputChannelData, numOut, bufferSize);

buildInputBusViews (inputChannelData, numIn);
buildOutputBusViews (outputChannelData, numOut);

paramChangeBuffer.clear();

AudioProcessContext<float> context {
audioBuffer, midiBuffer, paramChangeBuffer, nullptr
audioBuffer,
midiBuffer,
paramChangeBuffer,
nullptr,
{ inputBusViews.data(), inputBusViews.size() },
{ outputBusViews.data(), outputBusViews.size() }
};

processAudioBlock (*processor, context, currentlyBypassed);
Expand Down Expand Up @@ -712,6 +786,12 @@ class YupAAX_Processor

paramChangeBuffer.reserve (getDefaultParameterChangeCapacity (*processor));

// Pre-allocate per-bus view storage so the algorithm callback never allocates
inputBusViews.reserve (static_cast<size_t> (processor->getNumAudioInputs()));
outputBusViews.reserve (static_cast<size_t> (processor->getNumAudioOutputs()));
inputChannelPtrStorage.resize (static_cast<size_t> (processor->getBusLayout().getNumAudioInputChannels()));
outputChannelPtrStorage.resize (static_cast<size_t> (processor->getBusLayout().getNumAudioOutputChannels()));

if (auto* ctrl = Controller())
ctrl->SetSignalLatency (processor->getLatencySamples());

Expand Down Expand Up @@ -971,6 +1051,13 @@ class YupAAX_Processor
MidiBuffer midiBuffer;
ParameterChangeBuffer paramChangeBuffer;

// Per-bus view state, pre-allocated in preparePlugin so the real-time
// algorithm callback only clears and refills the vectors without allocating
std::vector<AudioBusBufferView<const float>> inputBusViews;
std::vector<AudioBusBufferView<float>> outputBusViews;
std::vector<const float*> inputChannelPtrStorage;
std::vector<float*> outputChannelPtrStorage;

std::unordered_map<int32_t, AudioParameter*> paramMap;
std::vector<AudioParameter*> aaxMeters;

Expand Down Expand Up @@ -1153,7 +1240,7 @@ void AAX_CALLBACK yupAAXAlgorithmCallback (void* const instancesBegin[], const v

static void getPlugInDescription (AAX_IEffectDescriptor& descriptor)
{
std::unique_ptr<AudioProcessor> plugin (createPluginProcessor());
std::unique_ptr<AudioProcessor> plugin (::YUP_AUDIO_PLUGIN_CREATE_FUNCTION());

descriptor.AddName (YupPlugin_Name);
descriptor.AddName (YupPlugin_Description);
Expand Down
Loading
Loading