AU + Logic: Has anyone sorted this out?


#1

Hello fellow jucers!
I have a plugin that is working perfectly everywhere apart from Logic…
The weirdest thing is that I have managed to open it in logic various times during the process but lately and while approaching the final build I have not managed to open it no matter what settings I use on Projucer. Any ideas?


#2

What says auval?

In a terminal call
auval -v aufx CODE MANU
CODE: in projucer under “Plugin Code” and MANU under “Plugin Manufacturer Code”
aufx might be augn for generators or aumf for musical effects (depends on Plugin AU Main type, aufx if you left this blank)
auval -a shows all plugins, but the list might be long…


#3

Many thanks Daniel,
I found out what the problem was…
Xcode was placing the .component file at /Users/chriss/Library/Audio/Plug-Ins/Components
(and that used to work for the last 10 months…)
but now I have to place the .component file at
/Library/Audio/Plug-Ins/Components
and it works fine!!
Any ideas why this is happening?


#4

and another thing: when I put in the plugin channel configuration {1,1},{2,2} build fails and I get the error: Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang failed with exit code 1
but if I change it to {2,2} is working fine as a stereo in logic
and then if I change it to {1,1} and change the right channel buffer.getWritePointer(1) to buffer.getWritePointer(0) is working as a mono plugin in logic…


#5

maybe the problem lies somewhere here :slightly_smiling_face:
#ifndef JucePlugin_PreferredChannelConfigurations
bool BatSimAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
{
#if JucePlugin_IsMidiEffect
ignoreUnused (layouts);
return true;
#else
// This is the place where you check if the layout is supported.
// In this template code we only support mono or stereo.
if (layouts.getMainOutputChannelSet() != AudioChannelSet::mono()
&& layouts.getMainOutputChannelSet() != AudioChannelSet::stereo())
return false;

// This checks if the input layout matches the output layout

#if ! JucePlugin_IsSynth
if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
return false;
#endif

return true;

#endif
}
#endif

???


#6

Ok, so I take it that auval returns “PASS”, right?
Logic and auval use the same method to scan the plugins, so if it fails auval, logic will not show it.

AUs are searched in both locations, /Library/Audio/Plug-Ins/Components and ~/Library/Audio/Plug-Ins/Components (the ~ is synonym for /Users/chriss in your case). AFAIK the system library takes precedence. Also please note, that the plugins are not identified by their filename (could be anything), but the triplet of “TYPE CODE MANU”. If there are two components with the same triplet, I don’t know what happens, probably takes the one that was scanned first, i.e. random.

If the compilation fails, the error code 1 doesn’t really help, you would have to paste at least the first error you find in the output. So this can be anything, from missing semicolon to something hard to spot.

The plugin channel configuration is a define, so as soon as you put something into that field, the method you posted becomes ignored, because of the #ifndef JucePlugin_PreferredChannelConfigurations. Instead a generic version is used, that takes the configuration into account.

I just double checked, and I can enter “{1, 1}, {2, 2}” into plugin channel configuration in a new plugin and get no compiler error, so would you mind sharing the output of the compiler, then I can have a look, what’s going on.

BTW, for the forum, if you put three backticks ``` before a block with code and after it, it will be formatted correctly…

Good luck!


#7

many thanks for all your very helpful info and tips!!! much appreciated!
meanwhile i noticed that the Gain plugin from Juce examples behaves excellently in mono/stereo for Cubase and Logic !!! so i am thinking to just use that configuration for my plugin as well…
the Plugin channel configurations field is empty and on the processor:

``` bool isBusesLayoutSupported (const BusesLayout& layouts) const override
{
    const AudioChannelSet& mainInLayout  = layouts.getChannelSet (true,  0);
    const AudioChannelSet& mainOutLayout = layouts.getChannelSet (false, 0);

    return (mainInLayout == mainOutLayout && (! mainInLayout.isDisabled()));
}

#8

and again i get a crash when trying to load the plugin to a mono channel…

here is part of my processor.cpp


//==============================================================================
BatSimAudioProcessor::BatSimAudioProcessor()
	: Parameters(*this, nullptr),
		AudioProcessor(BusesProperties().withInput("Input", AudioChannelSet::stereo())
										.withOutput("Output", AudioChannelSet::stereo()))
{

	//=============Parameters Template================================================


	Parameters.state = ValueTree(Identifier("StateIdentifier"));
......
......
.......
//==============================================================================
const String BatSimAudioProcessor::getName() const
{
    return JucePlugin_Name;
}


//=========================================================================================


const String BatSimAudioProcessor::getInputChannelName(int channelIndex) const
{
	return String(channelIndex + 1);
}
//================================================================
const String BatSimAudioProcessor::getOutputChannelName(int channelIndex) const
{
	return String(channelIndex + 1);
}

bool BatSimAudioProcessor::acceptsMidi() const
{
   #if JucePlugin_WantsMidiInput
    return true;
   #else
    return false;
   #endif
}

bool BatSimAudioProcessor::producesMidi() const
{
   #if JucePlugin_ProducesMidiOutput
    return true;
   #else
    return false;
   #endif
}



    
    
    
 
 
 double BatSimAudioProcessor::getTailLengthSeconds() const
{
    return 0.0;
}

int BatSimAudioProcessor::getNumPrograms()
{
    return 1;   // NB: some hosts don't cope very well if you tell them there are 0 programs,
                // so this should be at least 1, even if you're not really implementing programs.
}

int BatSimAudioProcessor::getCurrentProgram()
{
    return 0;
}

void BatSimAudioProcessor::setCurrentProgram (int index)
{
}

const String BatSimAudioProcessor::getProgramName (int index)
{
    return String();
    //return {};
}

void BatSimAudioProcessor::changeProgramName (int index, const String& newName)
{
}

//==============================================================================
void BatSimAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
 
    
     
    // Use this method as the place to do any pre-playback
    // initialisation that you need..
	
	fs = float(sampleRate);
...
...
...
...


void BatSimAudioProcessor::releaseResources()
{
    // When playback stops, you can use this as an opportunity to free up any
    // spare memory, etc.
}


bool BatSimAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
{
	const AudioChannelSet& mainInLayout = layouts.getChannelSet(true, 0);
	const AudioChannelSet& mainOutLayout = layouts.getChannelSet(false, 0);

	return (mainInLayout == mainOutLayout && (!mainInLayout.isDisabled()));
}



void BatSimAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) 
{
	
    const int totalNumInputChannels  = getTotalNumInputChannels();
    const int totalNumOutputChannels = getTotalNumOutputChannels();

    // In case we have more outputs than inputs, this code clears any output
    // channels that didn't contain input data, (because these aren't
    // guaranteed to be empty - they may contain garbage).
    // This is here to avoid people getting screaming feedback
    // when they first compile a plugin, but obviously you don't need to keep
    // this code if your algorithm always overwrites all the output channels.
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
 // This is the place where you'd normally do the guts of your plugin's

 //----------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
 
    for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
        buffer.clear (i, 0, buffer.getNumSamples());
   
            

...
...
...
...
...
...
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	float * leftChannel = buffer.getWritePointer(0);

	for (int i = 0; i < buffer.getNumSamples(); i++)
	{
		leftChannel[i] = .....filterL2->tick(leftChannel[i]))))))));
	    inputSample = buffer.getReadPointer(0)[i]; ////Drawing PEAK
	}

	for (int i = getTotalNumInputChannels(); i < getTotalNumOutputChannels(); ++i)
		buffer.clear(i, 0, buffer.getNumSamples());

	float * rightChannel = buffer.getWritePointer(1);

	for (int i = 0; i < buffer.getNumSamples(); i++)  // SECOND LOOP ADDED FOR PERFORMANCE ISSUES......
		rightChannel[i] =  ......filterR2->tick(rightChannel[i]))))))));
}

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




//==============================================================================
bool BatSimAudioProcessor::hasEditor() const
{
    return true; // (change this to false if you choose to not supply an editor)
}

AudioProcessorEditor* BatSimAudioProcessor::createEditor()
{
     return new BatSimAudioProcessorEditor (*this, Parameters);
}

//==============================================================================
void BatSimAudioProcessor::getStateInformation (MemoryBlock& destData)
{
    ScopedPointer<XmlElement> xml (Parameters.state.createXml());
    copyXmlToBinary (*xml, destData);
}

void BatSimAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
    ScopedPointer<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));
    if (xmlState != nullptr)
        if (xmlState->hasTagName (Parameters.state.getType()))
            Parameters.state = ValueTree::fromXml (*xmlState);
}



//==============================================================================
// This creates new instances of the plugin..
AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
    return new BatSimAudioProcessor();
}

#9

You can attach the debugger to your host application / Logic. When you load now the plugin and the crash happens, the debugger will exactly show you, what went wrong.
If you can’t make any sense of it, post the stack trace here (i.e. the last called methods).

But just spottet:

float * rightChannel = buffer.getWritePointer(1);

This will assert in debug mode and probably crash in release mode.

Good luck.


#10

ok! many thanks Daniel! Max Respect! it makes total sense…
any ideas haw can I avoid float * rightChannel = buffer.getWritePointer(1);
and still be able to have stereo operation??


#11

That might be related to some audio units cache, which was cleared for your plugin when you moved it.


#12

Ideally use the code in your isBusesLayoutSupported() to decide, what buffers you have at hand:

const AudioChannelSet& mainInLayout  = layouts.getChannelSet (true,  0);
const AudioChannelSet& mainOutLayout = layouts.getChannelSet (false, 0);

if (mainOutLayout.size() > 1) { // output channel set has more than one output channels
    // this avoids problems when you add additional buses later, for one bus you might assume 1:
    const auto index = getChannelIndexInProcessBlockBuffer (false, 0, 1); 
    float * rightChannel = buffer.getWritePointer (index);

    for (int i = 0; i < buffer.getNumSamples(); i++)  // SECOND LOOP ADDED FOR PERFORMANCE ISSUES......
        rightChannel[i] =  ......filterR2->tick(rightChannel[i]))))))));
// ...

HTH