, input_maxbuf (0)
, input_offset (0)
, input_buffers (0)
+ , input_map (0)
, frames_processed (0)
, audio_input_cnt (0)
, _parameter_listener (0)
, input_maxbuf (0)
, input_offset (0)
, input_buffers (0)
+ , input_map (0)
, frames_processed (0)
, _parameter_listener (0)
, _parameter_listener_arg (0)
bool
AUPlugin::can_support_io_configuration (const ChanCount& in, ChanCount& out, ChanCount* imprecise)
{
- // Note: We never attempt to multiply-instantiate plugins to meet io configurations.
-
+ _output_configs.clear ();
const int32_t audio_in = in.n_audio();
int32_t audio_out;
AUPluginInfoPtr pinfo = boost::dynamic_pointer_cast<AUPluginInfo>(get_info());
DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("%1 has %2 IO configurations, looking for %3 in, %4 out\n",
name(), io_configs.size(), in, out));
- //Ardour expects the plugin to tell it the output
- //configuration but AU plugins can have multiple I/O
- //configurations in most cases. so first lets see
- //if there's a configuration that keeps out==in
-
- if (in.n_midi() > 0 && audio_in == 0) {
- audio_out = 2; // prefer stereo version if available.
- } else {
- audio_out = audio_in;
- }
+ // preferred setting (provided by plugin_insert)
+ const int preferred_out = out.n_audio ();
+ audio_out = out.n_audio ();
+ bool found = false;
+ bool exact_match = false;
/* kAudioUnitProperty_SupportedNumChannels
* https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html#//apple_ref/doc/uid/TP40003278-CH12-SW20
int32_t possible_in = i->first;
int32_t possible_out = i->second;
- if ((possible_in == audio_in) && (possible_out == audio_out)) {
+ if ((possible_in == audio_in) && (possible_out == preferred_out)) {
DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tCHOSEN: %1 in %2 out to match in %3 out %4\n",
- possible_in, possible_out,
- in, out));
-
- out.set (DataType::MIDI, 0);
- out.set (DataType::AUDIO, audio_out);
+ possible_in, possible_out,
+ in, out));
- return true;
+ // exact match
+ _output_configs.insert (preferred_out);
+ exact_match = true;
+ found = true;
+ break;
}
}
/* now allow potentially "imprecise" matches */
- audio_out = -1;
- bool found = false;
+ int32_t audio_out = -1;
+ float penalty = 9999;
+ int used_possible_in = 0;
+
+#define FOUNDCFG(nch) { \
+ float p = fabsf ((float)(nch) - preferred_out); \
+ _output_configs.insert (nch); \
+ if ((nch) > preferred_out) { p *= 1.1; } \
+ if (p < penalty) { \
+ used_possible_in = possible_in; \
+ audio_out = (nch); \
+ penalty = p; \
+ found = true; \
+ } \
+}
+
+#define ANYTHINGGOES \
+ _output_configs.insert (0);
+
+#define UPTO(nch) { \
+ for (int n = 1; n < nch; ++n) { \
+ _output_configs.insert (n); \
+ } \
+}
for (vector<pair<int,int> >::iterator i = io_configs.begin(); i != io_configs.end(); ++i) {
/* no inputs, generators & instruments */
if (possible_out == -1) {
/* any configuration possible, provide stereo output */
- audio_out = 2;
- found = true;
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out == -2) {
/* invalid, should be (0, -1) */
- audio_out = 2;
- found = true;
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out < -2) {
- /* explicitly variable number of outputs. */
- audio_out = 2;
- found = true;
+ /* variable number of outputs up to -N, */
+ FOUNDCFG (min (-possible_out, preferred_out));
+ UPTO (-possible_out);
} else {
/* exact number of outputs */
- audio_out = possible_out;
- found = true;
+ FOUNDCFG (possible_out);
}
}
/* wildcard for input */
if (possible_out == -1) {
/* out must match in */
- audio_out = audio_in;
- found = true;
+ FOUNDCFG (audio_in);
} else if (possible_out == -2) {
/* any configuration possible, pick matching */
- audio_out = audio_in;
- found = true;
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out < -2) {
/* explicitly variable number of outputs, pick maximum */
- audio_out = -possible_out;
- found = true;
+ FOUNDCFG (max (-possible_out, preferred_out));
+ /* and try min, too, in case the penalty is lower */
+ FOUNDCFG (min (-possible_out, preferred_out));
+ UPTO (-possible_out)
} else {
/* exact number of outputs */
- audio_out = possible_out;
- found = true;
+ FOUNDCFG (possible_out);
}
}
if (possible_in == -2) {
if (possible_out == -1) {
/* any configuration possible, pick matching */
- audio_out = audio_in;
- found = true;
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out == -2) {
/* invalid. interpret as (-1, -1) */
- audio_out = audio_in;
- found = true;
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out < -2) {
- /* explicitly variable number of outputs, pick maximum */
- audio_out = -possible_out;
- found = true;
+ /* invalid, interpret as (<-2, <-2)
+ * variable number of outputs up to -N, */
+ FOUNDCFG (min (-possible_out, preferred_out));
+ UPTO (-possible_out)
} else {
/* exact number of outputs */
- audio_out = possible_out;
- found = true;
+ FOUNDCFG (possible_out);
}
}
if (audio_in > -possible_in && imprecise == NULL) {
/* request is too large */
} else if (possible_out == -1) {
- /* any output configuration possible, provide stereo out */
- audio_out = 2;
- found = true;
+ /* any output configuration possible */
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out == -2) {
/* invalid. interpret as (<-2, -1) */
- audio_out = 2;
- found = true;
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out < -2) {
- /* explicitly variable number of outputs, pick stereo */
- audio_out = 2;
- found = true;
+ /* variable number of outputs up to -N, */
+ FOUNDCFG (min (-possible_out, preferred_out));
+ UPTO (-possible_out)
} else {
/* exact number of outputs */
- audio_out = possible_out;
- found = true;
+ FOUNDCFG (possible_out);
}
}
if (possible_in && (possible_in == audio_in)) {
/* exact number of inputs ... must match obviously */
if (possible_out == -1) {
- /* any output configuration possible, provide stereo output */
- audio_out = 2;
- found = true;
+ /* any output configuration possible */
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out == -2) {
- /* plugins shouldn't really use (>0,-2) but might.
- interpret as (>0,-1):
- any output configuration possible, provide stereo output
- */
- audio_out = 2;
- found = true;
+ /* plugins shouldn't really use (>0,-2), interpret as (>0,-1) */
+ FOUNDCFG (preferred_out);
+ ANYTHINGGOES;
} else if (possible_out < -2) {
- /* explicitly variable number of outputs, pick maximum */
- audio_out = -possible_out;
- found = true;
+ /* > 0, < -2 is not specified
+ * interpret as up to -N */
+ FOUNDCFG (min (-possible_out, preferred_out));
+ UPTO (-possible_out)
} else {
/* exact number of outputs */
- audio_out = possible_out;
- found = true;
+ FOUNDCFG (possible_out);
}
}
-
- if (found) {
- if (possible_in < -2 && audio_in == 0) {
- // input-port count cannot be zero, use as many ports
- // as outputs, but at most abs(possible_in)
- audio_input_cnt = max (1, min (audio_out, -possible_in));
- }
- break;
- }
-
}
+
if (!found && imprecise) {
/* try harder */
for (vector<pair<int,int> >::iterator i = io_configs.begin(); i != io_configs.end(); ++i) {
- int possible_in = io["audio_in"];
- int possible_out = io["audio_out"];
+ int32_t possible_in = i->first;
+ int32_t possible_out = i->second;
assert (possible_in > 0); // all other cases will have been matched above
assert (possible_out !=0 || possible_in !=0); // already handled above
imprecise->set (DataType::AUDIO, possible_in);
if (possible_out == -1 || possible_out == -2) {
- audio_out = 2;
- found = true;
+ FOUNDCFG (2);
} else if (possible_out < -2) {
/* explicitly variable number of outputs, pick maximum */
- audio_out = -possible_out;
- found = true;
+ FOUNDCFG (min (-possible_out, preferred_out));
} else {
/* exact number of outputs */
- audio_out = possible_out;
- found = true;
- }
-
- if (found) {
- // ideally we'll keep iterating and take the "best match"
- // whatever "best" means:
- // least unconnected inputs, least silenced inputs,
- // closest match of inputs == outputs
- break;
+ FOUNDCFG (possible_out);
}
+ // ideally we'll also find the closest, best matching
+ // input configuration with minimal output penalty...
}
}
- if (found) {
- out.set (DataType::MIDI, 0); /// XXX
- out.set (DataType::AUDIO, audio_out);
- DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tCHOSEN: in %1 out %2\n", in, out));
- } else {
+ if (!found) {
DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tFAIL: no io configs match %1\n", in));
return false;
}
+ if (exact_match) {
+ out.set (DataType::MIDI, 0); // currently always zero
+ out.set (DataType::AUDIO, preferred_out);
+ } else {
+ if (used_possible_in < -2 && audio_in == 0) {
+ // input-port count cannot be zero, use as many ports
+ // as outputs, but at most abs(possible_in)
+ audio_input_cnt = max (1, min (audio_out, -used_possible_in));
+ }
+ out.set (DataType::MIDI, 0); /// XXX
+ out.set (DataType::AUDIO, audio_out);
+ }
+ DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("\tCHOSEN: in %1 out %2\n", in, out));
+
return true;
}
// name(), inNumberFrames, ioData->mNumberBuffers));
if (input_maxbuf == 0) {
+ DEBUG_TRACE (DEBUG::AudioUnits, "AUPlugin: render callback called illegally!");
error << _("AUPlugin: render callback called illegally!") << endmsg;
return kAudioUnitErr_CannotDoInCurrentContext;
}
uint32_t limit = min ((uint32_t) ioData->mNumberBuffers, input_maxbuf);
+ ChanCount bufs_count (DataType::AUDIO, 1);
+ BufferSet& silent_bufs = _session.get_silent_buffers(bufs_count);
+
for (uint32_t i = 0; i < limit; ++i) {
ioData->mBuffers[i].mNumberChannels = 1;
ioData->mBuffers[i].mDataByteSize = sizeof (Sample) * inNumberFrames;
- /* we don't use the channel mapping because audiounits are
- * never replicated. one plugin instance uses all channels/buffers
- * passed to PluginInsert::connect_and_run()
- */
-
- ioData->mBuffers[i].mData = input_buffers->get_audio (i).data (cb_offset + input_offset);
+ bool valid = false;
+ uint32_t idx = input_map->get (DataType::AUDIO, i, &valid);
+ if (valid) {
+ ioData->mBuffers[i].mData = input_buffers->get_audio (idx).data (cb_offset + input_offset);
+ } else {
+ ioData->mBuffers[i].mData = silent_bufs.get_audio(0).data (cb_offset + input_offset);
+ }
}
cb_offset += inNumberFrames;
_last_nframes = nframes;
}
- DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("%1 in %2 out %3 MIDI %4 bufs %5 (available %6)\n",
+ /* test if we can run in-place; only compare audio buffers */
+ bool inplace = true;
+ ChanMapping::Mappings inmap (in_map.mappings ());
+ ChanMapping::Mappings outmap (out_map.mappings ());
+ assert (outmap[DataType::AUDIO].size () > 0);
+ if (inmap[DataType::AUDIO].size() > 0 && inmap != outmap) {
+ inplace = false;
+ }
+
+ DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("%1 in %2 out %3 MIDI %4 bufs %5 (available %6) Inplace: %7\n",
name(), input_channels, output_channels, _has_midi_input,
- bufs.count(), bufs.available()));
+ bufs.count(), bufs.available(), inplace));
/* the apparent number of buffers matches our input configuration, but we know that the bufferset
- has the capacity to handle our outputs.
- */
+ * has the capacity to handle our outputs.
+ */
assert (bufs.available() >= ChanCount (DataType::AUDIO, output_channels));
input_buffers = &bufs;
+ input_map = &in_map;
input_maxbuf = bufs.count().n_audio(); // number of input audio buffers
input_offset = offset;
cb_offset = 0;
buffers->mNumberBuffers = output_channels;
+ ChanCount bufs_count (DataType::AUDIO, 1);
+ BufferSet& scratch_bufs = _session.get_scratch_buffers(bufs_count);
+
for (int32_t i = 0; i < output_channels; ++i) {
buffers->mBuffers[i].mNumberChannels = 1;
buffers->mBuffers[i].mDataByteSize = nframes * sizeof (Sample);
* a non-null values tells the plugin to render into the buffer pointed
* at by the value.
*/
- buffers->mBuffers[i].mData = 0;
+ if (inplace) {
+ buffers->mBuffers[i].mData = 0;
+ } else {
+ bool valid = false;
+ uint32_t idx = out_map.get (DataType::AUDIO, i, &valid);
+ if (valid) {
+ buffers->mBuffers[i].mData = bufs.get_audio (idx).data (offset);
+ } else {
+ buffers->mBuffers[i].mData = scratch_bufs.get_audio(0).data(offset);
+ }
+ }
}
if (_has_midi_input) {
}
}
- /* does this really mean anything ?
- */
+ /* does this really mean anything ? */
ts.mSampleTime = frames_processed;
ts.mFlags = kAudioTimeStampSampleTimeValid;
int32_t i;
for (i = 0; i < limit; ++i) {
- Sample* expected_buffer_address= bufs.get_audio (i).data (offset);
+ bool valid = false;
+ uint32_t idx = out_map.get (DataType::AUDIO, i, &valid);
+ if (!valid) continue;
+ Sample* expected_buffer_address = bufs.get_audio (idx).data (offset);
if (expected_buffer_address != buffers->mBuffers[i].mData) {
/* plugin provided its own buffer for output so copy it back to where we want it
*/
*/
for (;i < output_channels; ++i) {
- memset (bufs.get_audio (i).data (offset), 0, nframes * sizeof (Sample));
+ bool valid = false;
+ uint32_t idx = out_map.get (DataType::AUDIO, i, &valid);
+ if (!valid) continue;
+ memset (bufs.get_audio (idx).data (offset), 0, nframes * sizeof (Sample));
}
return 0;
continue;
}
+ bool has_midi_in = false;
+
AUPluginInfoPtr info (new AUPluginInfo
(boost::shared_ptr<CAComponentDescription> (new CAComponentDescription(temp))));
break;
case kAudioUnitType_MusicDevice:
info->category = _("AudioUnit Instruments");
+ has_midi_in = true;
break;
case kAudioUnitType_MusicEffect:
info->category = _("AudioUnit MusicEffects");
+ has_midi_in = true;
break;
case kAudioUnitType_Effect:
info->category = _("AudioUnit Effects");
info->n_inputs.set (DataType::AUDIO, 1);
}
+ info->n_inputs.set (DataType::MIDI, has_midi_in ? 1 : 0);
+
if (possible_out > 0) {
info->n_outputs.set (DataType::AUDIO, possible_out);
} else {
}
bool
-AUPluginInfo::needs_midi_input ()
+AUPluginInfo::needs_midi_input () const
{
return is_effect_with_midi_input () || is_instrument ();
}