Browse Source

AU processing details, still WIP

Signed-off-by: falkTX <falktx@falktx.com>
pull/1898/head
falkTX 6 months ago
parent
commit
a580473fbc
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
2 changed files with 333 additions and 35 deletions
  1. +284
    -26
      source/backend/plugin/CarlaPluginAU.cpp
  2. +49
    -9
      source/discovery/carla-discovery.cpp

+ 284
- 26
source/backend/plugin/CarlaPluginAU.cpp View File

@@ -41,7 +41,8 @@ class CarlaPluginAU : public CarlaPlugin,
public:
CarlaPluginAU(CarlaEngine* const engine, const uint id)
: CarlaPlugin(engine, id),
fInterface(nullptr)
fInterface(nullptr),
fAudioBufferData(nullptr)
{
carla_stdout("CarlaPluginAU::CarlaPluginAU(%p, %i)", engine, id);
}
@@ -71,6 +72,12 @@ public:
fInterface = nullptr;
}

if (fAudioBufferData != nullptr)
{
std::free(fAudioBufferData);
fAudioBufferData = nullptr;
}

// if (fLastChunk != nullptr)
// {
// std::free(fLastChunk);
@@ -211,12 +218,12 @@ public:
const float fixedValue = pData->param.getFixedValue(parameterId, value);

// TODO use scheduled events
fFunctions.setParameter(fInterface, paramId, kAudioUnitScope_Global, 0, value, 0);
fFunctions.setParameter(fInterface, paramId, kAudioUnitScope_Global, 0, value, frameOffset);

CarlaPlugin::setParameterValueRT(parameterId, fixedValue, frameOffset, sendCallbackLater);
}

// -------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// Plugin state

void reload() override
@@ -242,31 +249,63 @@ public:
needsCtrlIn = needsCtrlOut = hasMidiIn = hasMidiOut = false;

CarlaString portName;
const uint portNameSize(pData->engine->getMaxPortNameSize());
const uint portNameSize = pData->engine->getMaxPortNameSize();

UInt32 outDataSize;
Boolean outWritable = false;

// audio ports
outDataSize = 0;
if (fFunctions.getPropertyInfo(fInterface, kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, 0, &outDataSize, &outWritable) == noErr && outDataSize != 0 && outDataSize % sizeof(AUChannelInfo) == 0)
if (fFunctions.getPropertyInfo(fInterface,
kAudioUnitProperty_SupportedNumChannels,
kAudioUnitScope_Global,
0, &outDataSize, &outWritable) == noErr
/*
&& outDataSize != 0
&& outDataSize % sizeof(AUChannelInfo) == 0
*/
)
{
const uint32_t numChannels = outDataSize / sizeof(AUChannelInfo);
AUChannelInfo* const channelInfo = new AUChannelInfo[numChannels];

if (fFunctions.getProperty(fInterface, kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, 0, channelInfo, &outDataSize) == noErr && outDataSize == numChannels * sizeof(AUChannelInfo))
carla_stdout("kAudioUnitProperty_SupportedNumChannels returns %u configs", numChannels);

if (fFunctions.getProperty(fInterface,
kAudioUnitProperty_SupportedNumChannels,
kAudioUnitScope_Global,
0, channelInfo, &outDataSize) == noErr
&& outDataSize == numChannels * sizeof(AUChannelInfo))
{
AUChannelInfo* highestInfo = &channelInfo[0];

carla_stdout("getProperty returns {%u,%u}... config",
channelInfo[0].inChannels,
channelInfo[0].outChannels);

for (uint32_t i=1; i<numChannels; ++i)
{
if (channelInfo[i].inChannels > highestInfo->inChannels && channelInfo[i].outChannels > highestInfo->outChannels)
if (channelInfo[i].inChannels > highestInfo->inChannels
&& channelInfo[i].outChannels > highestInfo->outChannels)
{
highestInfo = &channelInfo[i];
}
}

audioIns = highestInfo->inChannels;
audioOuts = highestInfo->outChannels;
}
else
{
carla_stdout("getProperty failed");
}

delete[] channelInfo;
}
else
{
carla_stdout("kAudioUnitProperty_SupportedNumChannels returns no configs, assume stereo");
audioIns = audioOuts = 2;
}

if (audioIns > 0)
@@ -280,6 +319,22 @@ public:
needsCtrlIn = true;
}

std::free(fAudioBufferData);

if (const uint32_t numBuffers = std::max(audioIns, audioOuts))
{
fAudioBufferData = static_cast<AudioBufferList*>(std::malloc(sizeof(uint32_t) + sizeof(AudioBuffer) * numBuffers));
fAudioBufferData->mNumberBuffers = numBuffers;

for (uint32_t i = 0; i < numBuffers; ++i)
fAudioBufferData->mBuffers[i].mNumberChannels = 1;
}
else
{
fAudioBufferData = static_cast<AudioBufferList*>(std::malloc(sizeof(uint32_t)));
fAudioBufferData->mNumberBuffers = 0;
}

// Audio Ins
for (uint32_t i=0; i < audioIns; ++i)
{
@@ -294,14 +349,14 @@ public:
if (audioIns > 1)
{
portName += "input_";
portName += CarlaString(i+1);
portName += CarlaString(i + 1);
}
else
portName += "input";

portName.truncate(portNameSize);

pData->audioIn.ports[i].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, i);
pData->audioIn.ports[i].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, i);
pData->audioIn.ports[i].rindex = i;
}

@@ -319,7 +374,7 @@ public:
if (audioOuts > 1)
{
portName += "output_";
portName += CarlaString(i+1);
portName += CarlaString(i + 1);
}
else
portName += "output";
@@ -332,7 +387,12 @@ public:

// parameters
outDataSize = 0;
if (fFunctions.getPropertyInfo(fInterface, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0, &outDataSize, &outWritable) == noErr && outDataSize != 0 && outDataSize % sizeof(AudioUnitParameterID) == 0)
if (fFunctions.getPropertyInfo(fInterface,
kAudioUnitProperty_ParameterList,
kAudioUnitScope_Global,
0, &outDataSize, &outWritable) == noErr
&& outDataSize != 0
&& outDataSize % sizeof(AudioUnitParameterID) == 0)
{
const uint32_t numParams = outDataSize / sizeof(AudioUnitParameterID);
AudioUnitParameterID* const paramIds = new AudioUnitParameterID[numParams];
@@ -504,31 +564,160 @@ public:
{
CARLA_SAFE_ASSERT_RETURN(fInterface != nullptr,);

// TODO
AudioStreamBasicDescription streamFormat = {
.mFormatID = kAudioFormatLinearPCM,
.mBitsPerChannel = 32,
.mBytesPerFrame = sizeof(float),
.mBytesPerPacket = sizeof(float),
.mFramesPerPacket = 1,
.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved,
.mChannelsPerFrame = 0,
.mSampleRate = pData->engine->getSampleRate(),
};

if (pData->audioIn.count != 0)
{
streamFormat.mChannelsPerFrame = pData->audioIn.count;
CARLA_SAFE_ASSERT_RETURN(fFunctions.setProperty(fInterface,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0, &streamFormat, sizeof(streamFormat)) == noErr,);
}

if (pData->audioOut.count != 0)
{
streamFormat.mChannelsPerFrame = pData->audioOut.count;
CARLA_SAFE_ASSERT_RETURN(fFunctions.setProperty(fInterface,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
0, &streamFormat, sizeof(streamFormat)) == noErr,);
}

fFunctions.initialize(fInterface);
}

void deactivate() noexcept override
{
CARLA_SAFE_ASSERT_RETURN(fInterface != nullptr,);

// TODO
fFunctions.uninitialize(fInterface);
}

void process(const float* const* const audioIn,
float** const audioOut,
const float* const* const cvIn,
const float* const* const,
float** const,
const uint32_t frames) override
{
// ------------------------------------------------------------------------------------------------------------
// Check if active

if (! pData->active)
{
// disable any output sound
for (uint32_t i=0; i < pData->audioOut.count; ++i)
carla_zeroFloats(audioOut[i], frames);
return;
}

// ------------------------------------------------------------------------------------------------------------
// Check buffers

CARLA_SAFE_ASSERT_RETURN(frames > 0,);

if (pData->audioIn.count > 0)
{
CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr,);
}
if (pData->audioOut.count > 0)
{
CARLA_SAFE_ASSERT_RETURN(audioOut != nullptr,);
}

// ------------------------------------------------------------------------------------------------------------
// Try lock, silence otherwise

if (pData->engine->isOffline())
{
pData->singleMutex.lock();
}
else if (! pData->singleMutex.tryLock())
{
for (uint32_t i=0; i < pData->audioOut.count; ++i)
carla_zeroFloats(audioOut[i], frames);
return;
}

// ------------------------------------------------------------------------------------------------------------
// Check if needs reset

if (pData->needsReset)
{
// TODO
}

// ------------------------------------------------------------------------------------------------------------
// Event Input (main port)

if (pData->event.portIn != nullptr)
{
// TODO
}

// ------------------------------------------------------------------------------------------------------------
// Plugin processing

const EngineTimeInfo timeInfo(pData->engine->getTimeInfo());

AudioUnitRenderActionFlags actionFlags = kAudioUnitRenderAction_DoNotCheckRenderArgs;
AudioTimeStamp timeStamp = {};
timeStamp.mFlags = kAudioTimeStampSampleTimeValid;
timeStamp.mSampleTime = timeInfo.frame;
const UInt32 inBusNumber = 0;

{
uint32_t i = 0;
for (; i < pData->audioOut.count; ++i)
{
fAudioBufferData->mBuffers[i].mData = audioOut[i];
fAudioBufferData->mBuffers[i].mDataByteSize = sizeof(float) * frames;

if (audioOut[i] != audioIn[i])
std::memcpy(audioOut[i], audioIn[i], sizeof(float) * frames);
}

for (; i < pData->audioIn.count; ++i)
{
fAudioBufferData->mBuffers[i].mData = audioOut[i];
fAudioBufferData->mBuffers[i].mDataByteSize = sizeof(float) * frames;
}
}

fFunctions.render(fInterface, &actionFlags, &timeStamp, inBusNumber, frames, fAudioBufferData);

// ------------------------------------------------------------------------------------------------------------

pData->singleMutex.unlock();

#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
// ------------------------------------------------------------------------------------------------------------
// Control Output

// TODO
#endif

// ------------------------------------------------------------------------------------------------------------
// Events/MIDI Output

// TODO
}

// -------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------

protected:
void handlePluginUIClosed() override
{
carla_stdout("CarlaPluginCLAP::handlePluginUIClosed()");
carla_stdout("CarlaPluginAU::handlePluginUIClosed()");

// TODO
}
@@ -564,12 +753,6 @@ public:
return false;
}

if (label == nullptr)
{
pData->engine->setLastError("null label");
return false;
}

// ---------------------------------------------------------------
// load bundle information

@@ -643,7 +826,7 @@ public:

clabel[4] = clabel[9] = ',';

if (label[0] == '\0' || std::strcmp(label, clabel) == 0)
if (label == nullptr || label[0] == '\0' || std::strcmp(label, clabel) == 0)
break;
}

@@ -717,7 +900,81 @@ public:
return false;
}

// ---------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------
// init component

{
const UInt32 bufferSize = pData->engine->getBufferSize();

if (fFunctions.setProperty(fInterface,
kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Global,
0, &bufferSize, sizeof(bufferSize)) != noErr)
{
pData->engine->setLastError("Failed to set Component maximum frames per slice");
return false;
}
}

{
const Float64 sampleRate = pData->engine->getSampleRate();

// input scope
UInt32 outDataSize = 0;
Boolean outWritable = false;
if (fFunctions.getPropertyInfo(fInterface,
kAudioUnitProperty_ElementCount,
kAudioUnitScope_Input,
0, &outDataSize, &outWritable) == noErr
&& outDataSize == sizeof(UInt32))
{
UInt32 outData = 0;
if (fFunctions.getProperty(fInterface,
kAudioUnitProperty_ElementCount,
kAudioUnitScope_Input,
0, &outData, &outDataSize) == noErr
&& outData != 0)
{
if (fFunctions.setProperty(fInterface,
kAudioUnitProperty_SampleRate,
kAudioUnitScope_Input,
0, &sampleRate, sizeof(sampleRate)) != noErr)
{
pData->engine->setLastError("Failed to set Component input sample rate");
return false;
}
}
}

// output scope
outDataSize = 0;
outWritable = false;
if (fFunctions.getPropertyInfo(fInterface,
kAudioUnitProperty_ElementCount,
kAudioUnitScope_Output,
0, &outDataSize, &outWritable) == noErr
&& outDataSize == sizeof(UInt32))
{
UInt32 outData = 0;
if (fFunctions.getProperty(fInterface,
kAudioUnitProperty_ElementCount,
kAudioUnitScope_Output,
0, &outData, &outDataSize) == noErr
&& outData != 0)
{
if (fFunctions.setProperty(fInterface,
kAudioUnitProperty_SampleRate,
kAudioUnitScope_Output,
0, &sampleRate, sizeof(sampleRate)) != noErr)
{
pData->engine->setLastError("Failed to set Component output sample rate");
return false;
}
}
}
}

// ------------------------------------------------------------------------------------------------------------
// set default options

pData->options = PLUGIN_OPTION_FIXED_BUFFERS;
@@ -728,6 +985,7 @@ public:
private:
BundleLoader fBundleLoader;
AudioComponentPlugInInterface* fInterface;
AudioBufferList* fAudioBufferData;
CarlaString fName;
CarlaString fLabel;
CarlaString fMaker;
@@ -786,7 +1044,7 @@ private:
};
#endif

// -------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------

CarlaPluginPtr CarlaPlugin::newAU(const Initializer& init)
{
@@ -806,6 +1064,6 @@ CarlaPluginPtr CarlaPlugin::newAU(const Initializer& init)
#endif
}

// -------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------

CARLA_BACKEND_END_NAMESPACE

+ 49
- 9
source/discovery/carla-discovery.cpp View File

@@ -2164,34 +2164,57 @@ static bool do_au_check(const char* const filename, const bool doInit)

// audio port count
outDataSize = 0;
if (auGetPropertyInfo(interface, kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, 0, &outDataSize, &outWritable) == noErr && outDataSize != 0 && outDataSize % sizeof(AUChannelInfo) == 0)
if (auGetPropertyInfo(interface,
kAudioUnitProperty_SupportedNumChannels,
kAudioUnitScope_Global,
0, &outDataSize, &outWritable) == noErr
&& outDataSize != 0
&& outDataSize % sizeof(AUChannelInfo) == 0)
{
const uint32_t numChannels = outDataSize / sizeof(AUChannelInfo);
AUChannelInfo* const channelInfo = new AUChannelInfo[numChannels];

if (auGetProperty(interface, kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Global, 0, channelInfo, &outDataSize) == noErr && outDataSize == numChannels * sizeof(AUChannelInfo))
if (auGetProperty(interface,
kAudioUnitProperty_SupportedNumChannels,
kAudioUnitScope_Global,
0, channelInfo, &outDataSize) == noErr
&& outDataSize == numChannels * sizeof(AUChannelInfo))
{
AUChannelInfo* highestInfo = &channelInfo[0];

for (uint32_t i=1; i<numChannels; ++i)
{
if (channelInfo[i].inChannels > highestInfo->inChannels && channelInfo[i].outChannels > highestInfo->outChannels)
if (channelInfo[i].inChannels > highestInfo->inChannels
&& channelInfo[i].outChannels > highestInfo->outChannels)
{
highestInfo = &channelInfo[i];
}
}

audioIns = highestInfo->inChannels;
audioOuts = highestInfo->outChannels;
}

delete[] channelInfo;
}

// parameter count
outDataSize = 0;
if (auGetPropertyInfo(interface, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0, &outDataSize, &outWritable) == noErr && outDataSize != 0 && outDataSize % sizeof(AudioUnitParameterID) == 0)
if (auGetPropertyInfo(interface,
kAudioUnitProperty_ParameterList,
kAudioUnitScope_Global,
0, &outDataSize, &outWritable) == noErr
&& outDataSize != 0
&& outDataSize % sizeof(AudioUnitParameterID) == 0)
{
const uint32_t numParams = outDataSize / sizeof(AudioUnitParameterID);
AudioUnitParameterID* const paramIds = new AudioUnitParameterID[numParams];

if (auGetProperty(interface, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0, paramIds, &outDataSize) == noErr && outDataSize == numParams * sizeof(AudioUnitParameterID))
if (auGetProperty(interface,
kAudioUnitProperty_ParameterList,
kAudioUnitScope_Global,
0, paramIds, &outDataSize) == noErr
&& outDataSize == numParams * sizeof(AudioUnitParameterID))
{
AudioUnitParameterInfo info;

@@ -2200,11 +2223,17 @@ static bool do_au_check(const char* const filename, const bool doInit)
carla_zeroStruct(info);

outDataSize = 0;
if (auGetPropertyInfo(interface, kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, paramIds[i], &outDataSize, &outWritable) != noErr)
if (auGetPropertyInfo(interface,
kAudioUnitProperty_ParameterInfo,
kAudioUnitScope_Global,
paramIds[i], &outDataSize, &outWritable) != noErr)
break;
if (outDataSize != sizeof(AudioUnitParameterInfo))
break;
if (auGetProperty(interface, kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, paramIds[i], &info, &outDataSize) != noErr)
if (auGetProperty(interface,
kAudioUnitProperty_ParameterInfo,
kAudioUnitScope_Global,
paramIds[i], &info, &outDataSize) != noErr)
break;

if ((info.flags & kAudioUnitParameterFlag_IsReadable) == 0)
@@ -2232,15 +2261,26 @@ static bool do_au_check(const char* const filename, const bool doInit)
// MIDI output
outDataSize = 0;
outWritable = false;
if (auGetPropertyInfo(interface, kAudioUnitProperty_MIDIOutputCallback, kAudioUnitScope_Global, 0, &outDataSize, &outWritable) == noErr && outDataSize == sizeof(AUMIDIOutputCallbackStruct) && outWritable)
if (auGetPropertyInfo(interface,
kAudioUnitProperty_MIDIOutputCallback,
kAudioUnitScope_Global,
0, &outDataSize, &outWritable) == noErr
&& outDataSize == sizeof(AUMIDIOutputCallbackStruct)
&& outWritable)
{
midiOuts = 1;
}

// hints
if (category == PLUGIN_CATEGORY_SYNTH)
hints |= PLUGIN_IS_SYNTH;

outDataSize = 0;
if (auGetPropertyInfo(interface, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, &outDataSize, &outWritable) == noErr && outDataSize == sizeof(AudioUnitCocoaViewInfo))
if (auGetPropertyInfo(interface,
kAudioUnitProperty_CocoaUI,
kAudioUnitScope_Global,
0, &outDataSize, &outWritable) == noErr
&& outDataSize == sizeof(AudioUnitCocoaViewInfo))
{
hints |= PLUGIN_HAS_CUSTOM_UI;
#ifndef BUILD_BRIDGE


Loading…
Cancel
Save