#define ArdourFindNext AudioComponentFindNext
#endif
-#include "i18n.h"
+#include "pbd/i18n.h"
using namespace std;
using namespace PBD;
, comp (_comp)
, unit (new CAAudioUnit)
, initialized (false)
- , _current_block_size (0)
+ , _last_nframes (0)
+ , _current_latency (UINT_MAX)
, _requires_fixed_size_buffers (false)
, buffers (0)
, variable_inputs (false)
, audio_input_cnt (0)
, _parameter_listener (0)
, _parameter_listener_arg (0)
- , last_transport_rolling (false)
+ , transport_frame (0)
+ , transport_speed (0)
, last_transport_speed (0.0)
{
if (!preset_search_path_initialized) {
, comp (other.get_comp())
, unit (new CAAudioUnit)
, initialized (false)
- , _current_block_size (0)
, _last_nframes (0)
+ , _current_latency (UINT_MAX)
, _requires_fixed_size_buffers (false)
, buffers (0)
, variable_inputs (false)
, bus_outputs (0)
, input_maxbuf (0)
, input_offset (0)
+ , cb_offsets (0)
, input_buffers (0)
, input_map (0)
, frames_processed (0)
, _parameter_listener (0)
, _parameter_listener_arg (0)
+ , transport_frame (0)
+ , transport_speed (0)
+ , last_transport_speed (0.0)
{
init ();
framecnt_t
AUPlugin::signal_latency () const
{
- return unit->Latency() * _session.frame_rate();
+ guint lat = g_atomic_int_get (&_current_latency);;
+ if (lat == UINT_MAX) {
+ lat = unit->Latency() * _session.frame_rate();
+ g_atomic_int_set (&_current_latency, lat);
+ }
+ return lat;
}
void
activate ();
}
- _current_block_size = nframes;
-
return 0;
}
return false;
}
- vector<pair<int,int> >& io_configs = pinfo->cache.io_configs;
+ vector<pair<int,int> > io_configs = pinfo->cache.io_configs;
+
+ if (input_elements > 1) {
+ const vector<pair<int,int> >& ioc (pinfo->cache.io_configs);
+ for (vector<pair<int,int> >::const_iterator i = ioc.begin(); i != ioc.end(); ++i) {
+ int32_t possible_in = i->first;
+ int32_t possible_out = i->second;
+ if (possible_in < 1 || possible_out < 1) {
+ continue;
+ }
+ for (uint32_t i = 1; i < input_elements; ++i) {
+ // can't use up-to bus_inputs[]
+ // waves' SC-C6(s) for example fails to configure with only 1 input
+ // on the 2nd bus.
+ io_configs.push_back (pair<int,int> (possible_in + bus_inputs[i], possible_out));
+ }
+ }
+ }
+
+ if (output_elements > 1) {
+ const vector<pair<int,int> >& ioc (pinfo->cache.io_configs);
+ for (vector<pair<int,int> >::const_iterator i = ioc.begin(); i != ioc.end(); ++i) {
+ int32_t possible_in = i->first;
+ int32_t possible_out = i->second;
+ if (possible_in < 1 || possible_out < 1) {
+ continue;
+ }
+ for (uint32_t i = 1; i < output_elements; ++i) {
+ int32_t c = bus_outputs[i];
+ for (uint32_t j = 1; j < i; ++j) {
+ c += bus_outputs [j];
+ }
+ io_configs.push_back (pair<int,int> (possible_in, possible_out + c));
+ }
+ }
+ }
DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("%1 has %2 IO configurations, looking for %3 in, %4 out\n",
name(), io_configs.size(), in, out));
}
int
-AUPlugin::connect_and_run (BufferSet& bufs, ChanMapping in_map, ChanMapping out_map, pframes_t nframes, framecnt_t offset)
+AUPlugin::connect_and_run (BufferSet& bufs,
+ framepos_t start, framepos_t end, double speed,
+ ChanMapping in_map, ChanMapping out_map,
+ pframes_t nframes, framecnt_t offset)
{
- Plugin::connect_and_run (bufs, in_map, out_map, nframes, offset);
+ Plugin::connect_and_run(bufs, start, end, speed, in_map, out_map, nframes, offset);
+
+ transport_frame = start;
+ transport_speed = speed;
AudioUnitRenderActionFlags flags = 0;
AudioTimeStamp ts;
bool inplace = true; // TODO check plugin-insert in-place ?
ChanMapping::Mappings inmap (in_map.mappings ());
ChanMapping::Mappings outmap (out_map.mappings ());
- assert (outmap[DataType::AUDIO].size () > 0);
+ if (outmap[DataType::AUDIO].size () == 0) {
+ inplace = false;
+ }
if (inmap[DataType::AUDIO].size() > 0 && inmap != outmap) {
inplace = false;
}
return kAudioUnitErr_CannotDoInCurrentContext;
}
- Timecode::BBT_Time bbt;
- TempoMetric metric = tmap.metric_at (_session.transport_frame() + input_offset);
- tmap.bbt_time (_session.transport_frame() + input_offset, bbt);
+ TempoMetric metric = tmap.metric_at (transport_frame + input_offset);
+ Timecode::BBT_Time bbt = _session.tempo_map().bbt_at_frame (transport_frame + input_offset);
if (outCurrentBeat) {
const double ppq_scaling = metric.meter().note_divisor() / 4.0;
return kAudioUnitErr_CannotDoInCurrentContext;
}
- Timecode::BBT_Time bbt;
- TempoMetric metric = tmap.metric_at (_session.transport_frame() + input_offset);
- tmap.bbt_time (_session.transport_frame() + input_offset, bbt);
+ TempoMetric metric = tmap.metric_at (transport_frame + input_offset);
+ Timecode::BBT_Time bbt = _session.tempo_map().bbt_at_frame (transport_frame + input_offset);
if (outDeltaSampleOffsetToNextBeat) {
if (bbt.ticks == 0) {
/* on the beat */
*outDeltaSampleOffsetToNextBeat = 0;
} else {
- *outDeltaSampleOffsetToNextBeat = (UInt32)
- floor (((Timecode::BBT_Time::ticks_per_beat - bbt.ticks)/Timecode::BBT_Time::ticks_per_beat) * // fraction of a beat to next beat
- metric.tempo().frames_per_beat (_session.frame_rate())); // frames per beat
+ double const beat_frac_to_next = (Timecode::BBT_Time::ticks_per_beat - bbt.ticks) / Timecode::BBT_Time::ticks_per_beat;
+ *outDeltaSampleOffsetToNextBeat = tmap.frame_at_beat (tmap.beat_at_frame (transport_frame + input_offset) + beat_frac_to_next);
}
}
Float64* outCycleStartBeat,
Float64* outCycleEndBeat)
{
- bool rolling;
- float speed;
+ const bool rolling = (transport_speed != 0);
+ const bool last_transport_rolling = (last_transport_speed != 0);
DEBUG_TRACE (DEBUG::AudioUnits, "AU calls ardour transport state callback\n");
- rolling = _session.transport_rolling();
- speed = _session.transport_speed ();
if (outIsPlaying) {
- *outIsPlaying = _session.transport_rolling();
+ *outIsPlaying = rolling;
}
if (outTransportStateChanged) {
if (rolling != last_transport_rolling) {
*outTransportStateChanged = true;
- } else if (speed != last_transport_speed) {
+ } else if (transport_speed != last_transport_speed) {
*outTransportStateChanged = true;
} else {
*outTransportStateChanged = false;
/* this assumes that the AU can only call this host callback from render context,
where input_offset is valid.
*/
- *outCurrentSampleInTimeLine = _session.transport_frame() + input_offset;
+ *outCurrentSampleInTimeLine = transport_frame + input_offset;
}
if (outIsCycling) {
+ // TODO check bounce-processing
Location* loc = _session.locations()->auto_loop_location();
- *outIsCycling = (loc && _session.transport_rolling() && _session.get_play_loop());
+ *outIsCycling = (loc && rolling && _session.get_play_loop());
if (*outIsCycling) {
if (outCycleStartBeat) {
TempoMetric metric = tmap.metric_at (loc->start() + input_offset);
- _session.tempo_map().bbt_time (loc->start(), bbt);
+ bbt = _session.tempo_map().bbt_at_frame (loc->start() + input_offset);
float beat;
beat = metric.meter().divisions_per_bar() * bbt.bars;
if (outCycleEndBeat) {
TempoMetric metric = tmap.metric_at (loc->end() + input_offset);
- _session.tempo_map().bbt_time (loc->end(), bbt);
+ bbt = _session.tempo_map().bbt_at_frame (loc->end() + input_offset);
float beat;
beat = metric.meter().divisions_per_bar() * bbt.bars;
}
}
- last_transport_rolling = rolling;
- last_transport_speed = speed;
+ last_transport_speed = transport_speed;
return noErr;
}
_parameter_listener_arg = arg;
+ // listen for latency changes
+ AudioUnitEvent event;
+ event.mEventType = kAudioUnitEvent_PropertyChange;
+ event.mArgument.mProperty.mAudioUnit = unit->AU();
+ event.mArgument.mProperty.mPropertyID = kAudioUnitProperty_Latency;
+ event.mArgument.mProperty.mScope = kAudioUnitScope_Global;
+ event.mArgument.mProperty.mElement = 0;
+
+ if (AUEventListenerAddEventType (_parameter_listener, _parameter_listener_arg, &event) != noErr) {
+ PBD::error << "Failed to create latency event listener\n";
+ // TODO don't cache _current_latency
+ }
+
return 0;
}
void
AUPlugin::parameter_change_listener (void* /*arg*/, void* src, const AudioUnitEvent* event, UInt64 /*host_time*/, Float32 new_value)
{
+ if (event->mEventType == kAudioUnitEvent_PropertyChange) {
+ if (event->mArgument.mProperty.mPropertyID == kAudioUnitProperty_Latency) {
+ DEBUG_TRACE (DEBUG::AudioUnits, string_compose("AU Latency Change Event %1 <> %2\n", new_value, unit->Latency()));
+ guint lat = unit->Latency() * _session.frame_rate();
+ g_atomic_int_set (&_current_latency, lat);
+ }
+ return;
+ }
+
ParameterMap::iterator i;
if ((i = parameter_map.find (event->mArgument.mParameter.mParameterID)) == parameter_map.end()) {