summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/ardour/ardour/audio_unit.h25
-rw-r--r--libs/ardour/audio_unit.cc131
2 files changed, 131 insertions, 25 deletions
diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h
index db38b0f234..14665da301 100644
--- a/libs/ardour/ardour/audio_unit.h
+++ b/libs/ardour/ardour/audio_unit.h
@@ -143,6 +143,17 @@ class AUPlugin : public ARDOUR::Plugin
static std::string maybe_fix_broken_au_id (const std::string&);
+ /* this MUST be called from thread in which you want to receive notifications
+ about parameter changes.
+ */
+ int create_parameter_listener (AUEventListenerProc callback, void *arg, float interval_secs);
+ /* these can be called from any thread but SHOULD be called from the same thread
+ that will receive parameter change notifications.
+ */
+ int listen_to_parameter (uint32_t param_id);
+ int end_listen_to_parameter (uint32_t param_id);
+
+
protected:
std::string do_save_preset (std::string name);
void do_remove_preset (std::string);
@@ -187,20 +198,26 @@ class AUPlugin : public ARDOUR::Plugin
void discover_parameters ();
void add_state (XMLNode *) const;
- std::vector<std::pair<uint32_t, uint32_t> > parameter_map;
- uint32_t current_maxbuf;
- framecnt_t current_offset;
+ typedef std::map<uint32_t, uint32_t> ParameterMap;
+ ParameterMap parameter_map;
+ uint32_t input_maxbuf;
+ framecnt_t input_offset;
framecnt_t cb_offset;
- BufferSet* current_buffers;
+ BufferSet* input_buffers;
framecnt_t frames_processed;
std::vector<AUParameterDescriptor> descriptors;
+ AUEventListenerRef _parameter_listener;
+ void * _parameter_listener_arg;
void init ();
void discover_factory_presets ();
bool last_transport_rolling;
float last_transport_speed;
+
+ static void _parameter_change_listener (void* /*arg*/, void* /*src*/, const AudioUnitEvent* event, UInt64 host_time, Float32 new_value);
+ void parameter_change_listener (void* /*arg*/, void* /*src*/, const AudioUnitEvent* event, UInt64 host_time, Float32 new_value);
};
typedef boost::shared_ptr<AUPlugin> AUPluginPtr;
diff --git a/libs/ardour/audio_unit.cc b/libs/ardour/audio_unit.cc
index 76a9f1d45e..b53d62614f 100644
--- a/libs/ardour/audio_unit.cc
+++ b/libs/ardour/audio_unit.cc
@@ -345,10 +345,12 @@ AUPlugin::AUPlugin (AudioEngine& engine, Session& session, boost::shared_ptr<CAC
, _current_block_size (0)
, _requires_fixed_size_buffers (false)
, buffers (0)
- , current_maxbuf (0)
- , current_offset (0)
- , current_buffers (0)
+ , input_maxbuf (0)
+ , input_offset (0)
+ , input_buffers (0)
, frames_processed (0)
+ , _parameter_listener (0)
+ , _parameter_listener_arg (0)
, last_transport_rolling (false)
, last_transport_speed (0.0)
{
@@ -373,10 +375,12 @@ AUPlugin::AUPlugin (const AUPlugin& other)
, _last_nframes (0)
, _requires_fixed_size_buffers (false)
, buffers (0)
- , current_maxbuf (0)
- , current_offset (0)
- , current_buffers (0)
+ , input_maxbuf (0)
+ , input_offset (0)
+ , input_buffers (0)
, frames_processed (0)
+ , _parameter_listener (0)
+ , _parameter_listener_arg (0)
{
init ();
@@ -384,6 +388,11 @@ AUPlugin::AUPlugin (const AUPlugin& other)
AUPlugin::~AUPlugin ()
{
+ if (_parameter_listener) {
+ AUListenerDispose (_parameter_listener);
+ _parameter_listener = 0;
+ }
+
if (unit) {
DEBUG_TRACE (DEBUG::AudioUnits, "about to call uninitialize in plugin destructor\n");
unit->Uninitialize ();
@@ -501,6 +510,7 @@ AUPlugin::init ()
throw failed_constructor();
}
+ create_parameter_listener (AUPlugin::_parameter_change_listener, this, 0.05);
discover_parameters ();
discover_factory_presets ();
@@ -616,6 +626,10 @@ AUPlugin::discover_parameters ()
d.max_unbound = 0; // upper is bound
descriptors.push_back (d);
+
+ uint32_t last_param = descriptors.size() - 1;
+ parameter_map.insert (pair<uint32_t,uint32_t> (d.id, last_param));
+ listen_to_parameter (last_param);
}
}
}
@@ -1248,11 +1262,11 @@ AUPlugin::render_callback(AudioUnitRenderActionFlags*,
DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("%1: render callback, frames %2 bufs %3\n",
name(), inNumberFrames, ioData->mNumberBuffers));
- if (current_maxbuf == 0) {
+ if (input_maxbuf == 0) {
error << _("AUPlugin: render callback called illegally!") << endmsg;
return kAudioUnitErr_CannotDoInCurrentContext;
}
- uint32_t limit = min ((uint32_t) ioData->mNumberBuffers, current_maxbuf);
+ uint32_t limit = min ((uint32_t) ioData->mNumberBuffers, input_maxbuf);
for (uint32_t i = 0; i < limit; ++i) {
ioData->mBuffers[i].mNumberChannels = 1;
@@ -1263,7 +1277,7 @@ AUPlugin::render_callback(AudioUnitRenderActionFlags*,
passed to PluginInsert::connect_and_run()
*/
- ioData->mBuffers[i].mData = current_buffers->get_audio (i).data (cb_offset + current_offset);
+ ioData->mBuffers[i].mData = input_buffers->get_audio (i).data (cb_offset + input_offset);
}
cb_offset += inNumberFrames;
@@ -1290,9 +1304,9 @@ AUPlugin::connect_and_run (BufferSet& bufs, ChanMapping in_map, ChanMapping out_
*/
assert (bufs.available() >= ChanCount (DataType::AUDIO, output_channels));
- current_buffers = &bufs;
- current_maxbuf = bufs.count().n_audio(); // number of input audio buffers
- current_offset = offset;
+ input_buffers = &bufs;
+ input_maxbuf = bufs.count().n_audio(); // number of input audio buffers
+ input_offset = offset;
cb_offset = 0;
DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("%1 in %2 out %3 MIDI %4 bufs %5 (available %6)\n",
@@ -1347,7 +1361,7 @@ AUPlugin::connect_and_run (BufferSet& bufs, ChanMapping in_map, ChanMapping out_
if ((err = unit->Render (&flags, &ts, 0, nframes, buffers)) == noErr) {
- current_maxbuf = 0;
+ input_maxbuf = 0;
frames_processed += nframes;
DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("%1 rendered %2 buffers of %3\n",
@@ -1398,8 +1412,8 @@ AUPlugin::get_beat_and_tempo_callback (Float64* outCurrentBeat,
}
Timecode::BBT_Time bbt;
- TempoMetric metric = tmap.metric_at (_session.transport_frame() + current_offset);
- tmap.bbt_time_with_metric (_session.transport_frame() + current_offset, bbt, metric);
+ TempoMetric metric = tmap.metric_at (_session.transport_frame() + input_offset);
+ tmap.bbt_time_with_metric (_session.transport_frame() + input_offset, bbt, metric);
if (outCurrentBeat) {
float beat;
@@ -1437,8 +1451,8 @@ AUPlugin::get_musical_time_location_callback (UInt32* outDeltaSampleOffsetToNe
}
Timecode::BBT_Time bbt;
- TempoMetric metric = tmap.metric_at (_session.transport_frame() + current_offset);
- tmap.bbt_time_with_metric (_session.transport_frame() + current_offset, bbt, metric);
+ TempoMetric metric = tmap.metric_at (_session.transport_frame() + input_offset);
+ tmap.bbt_time_with_metric (_session.transport_frame() + input_offset, bbt, metric);
if (outDeltaSampleOffsetToNextBeat) {
if (bbt.ticks == 0) {
@@ -1505,9 +1519,9 @@ AUPlugin::get_transport_state_callback (Boolean* outIsPlaying,
if (outCurrentSampleInTimeLine) {
/* this assumes that the AU can only call this host callback from render context,
- where current_offset is valid.
+ where input_offset is valid.
*/
- *outCurrentSampleInTimeLine = _session.transport_frame() + current_offset;
+ *outCurrentSampleInTimeLine = _session.transport_frame() + input_offset;
}
if (outIsCycling) {
@@ -1532,7 +1546,7 @@ AUPlugin::get_transport_state_callback (Boolean* outIsPlaying,
Timecode::BBT_Time bbt;
if (outCycleStartBeat) {
- TempoMetric metric = tmap.metric_at (loc->start() + current_offset);
+ TempoMetric metric = tmap.metric_at (loc->start() + input_offset);
_session.tempo_map().bbt_time_with_metric (loc->start(), bbt, metric);
float beat;
@@ -1544,7 +1558,7 @@ AUPlugin::get_transport_state_callback (Boolean* outIsPlaying,
}
if (outCycleEndBeat) {
- TempoMetric metric = tmap.metric_at (loc->end() + current_offset);
+ TempoMetric metric = tmap.metric_at (loc->end() + input_offset);
_session.tempo_map().bbt_time_with_metric (loc->end(), bbt, metric);
float beat;
@@ -2662,3 +2676,78 @@ AUPlugin::set_info (PluginInfoPtr info)
_has_midi_input = pinfo->needs_midi_input ();
_has_midi_output = false;
}
+
+int
+AUPlugin::create_parameter_listener (AUEventListenerProc cb, void* arg, float interval_secs)
+{
+ CFRunLoopRef run_loop = (CFRunLoopRef) GetCFRunLoopFromEventLoop(GetCurrentEventLoop());
+ CFStringRef loop_mode = kCFRunLoopDefaultMode;
+
+ if (AUEventListenerCreate (cb, arg, run_loop, loop_mode, interval_secs, interval_secs, &_parameter_listener) != noErr) {
+ return -1;
+ }
+
+ _parameter_listener_arg = arg;
+
+ return 0;
+}
+
+int
+AUPlugin::listen_to_parameter (uint32_t param_id)
+{
+ AudioUnitEvent event;
+
+ if (!_parameter_listener || param_id >= descriptors.size()) {
+ return -2;
+ }
+
+ event.mEventType = kAudioUnitEvent_ParameterValueChange;
+ event.mArgument.mParameter.mAudioUnit = unit->AU();
+ event.mArgument.mParameter.mParameterID = descriptors[param_id].id;
+ event.mArgument.mParameter.mScope = descriptors[param_id].scope;
+ event.mArgument.mParameter.mElement = descriptors[param_id].element;
+
+ if (AUEventListenerAddEventType (_parameter_listener, _parameter_listener_arg, &event) != noErr) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+AUPlugin::end_listen_to_parameter (uint32_t param_id)
+{
+ AudioUnitEvent event;
+
+ if (!_parameter_listener || param_id >= descriptors.size()) {
+ return -2;
+ }
+
+ event.mEventType = kAudioUnitEvent_ParameterValueChange;
+ event.mArgument.mParameter.mAudioUnit = unit->AU();
+ event.mArgument.mParameter.mParameterID = descriptors[param_id].id;
+ event.mArgument.mParameter.mScope = descriptors[param_id].scope;
+ event.mArgument.mParameter.mElement = descriptors[param_id].element;
+
+ if (AUEventListenerRemoveEventType (_parameter_listener, _parameter_listener_arg, &event) != noErr) {
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+AUPlugin::_parameter_change_listener (void* arg, void* src, const AudioUnitEvent* event, UInt64 host_time, Float32 new_value)
+{
+ ((AUPlugin*) arg)->parameter_change_listener (arg, src, event, host_time, new_value);
+}
+
+void
+AUPlugin::parameter_change_listener (void* /*arg*/, void* /*src*/, const AudioUnitEvent* event, UInt64 host_time, Float32 new_value)
+{
+ ParameterMap::iterator i = parameter_map.find (event->mArgument.mParameter.mParameterID);
+
+ if (i != parameter_map.end()) {
+ ParameterChanged (i->second, new_value);
+ }
+}