Add automatable click-free bypass/enable feature to a-eq
[ardour.git] / libs / ardour / lv2_plugin.cc
index b0c67bf0343fa317c808a9caed66a99eac360f28..e45270ebcb6326e6baabb87883c494b35b151893 100644 (file)
@@ -558,6 +558,13 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
 
 #ifdef HAVE_LILV_0_16_0
        // Load default state
+       if (_worker) {
+               /* immediately schedule any work,
+                * so that state restore later will not find a busy
+                * worker.  latency_compute_run() flushes any replies
+                */
+               _worker->set_synchronous(true);
+       }
        LilvState* state = lilv_state_new_from_world(
                _world.world, _uri_map.urid_map(), lilv_plugin_get_uri(_impl->plugin));
        if (state && _has_state_interface) {
@@ -1088,8 +1095,8 @@ LV2Plugin::get_layout (uint32_t which, UILayoutHint& h) const
                case 15: h.x0 = 13; h.x1 = 14; h.y0 = 0; h.y1 = 1; break; // Gain H
                case 22: h.x0 = 13; h.x1 = 14; h.y0 = 5; h.y1 = 6; break; // enable H
 
-
-               case 16: h.x0 = 14; h.x1 = 15; h.y0 = 4; h.y1 = 6; break; // Master Gain
+               case 16: h.x0 = 14; h.x1 = 15; h.y0 = 1; h.y1 = 3; break; // Master Gain
+               case 23: h.x0 = 14; h.x1 = 15; h.y0 = 5; h.y1 = 6; break; // Master Enable
                default:
                        return false;
        }
@@ -1340,7 +1347,7 @@ LV2Plugin::load_preset(PresetRecord r)
        LV2_Worker_Schedule schedule            = { _state_worker, work_schedule };
        const LV2_Feature   state_sched_feature = { LV2_WORKER__schedule, &schedule };
        if (_state_worker) {
-               state_features[1] = &state_sched_feature;
+               state_features[0] = &state_sched_feature;
        }
 
        if (state) {
@@ -2276,6 +2283,7 @@ write_position(LV2_Atom_Forge*     forge,
                const TempoMetric&  t,
                Timecode::BBT_Time& bbt,
                double              speed,
+               double              bpm,
                framepos_t          position,
                framecnt_t          offset)
 {
@@ -2300,7 +2308,7 @@ write_position(LV2_Atom_Forge*     forge,
        lv2_atom_forge_key(forge, urids.time_beatsPerBar);
        lv2_atom_forge_float(forge, t.meter().divisions_per_bar());
        lv2_atom_forge_key(forge, urids.time_beatsPerMinute);
-       lv2_atom_forge_float(forge, t.tempo().beats_per_minute());
+       lv2_atom_forge_float(forge, bpm);
 #else
        lv2_atom_forge_blank(forge, &frame, 1, urids.time_Position);
        lv2_atom_forge_property_head(forge, urids.time_frame, 0);
@@ -2317,7 +2325,7 @@ write_position(LV2_Atom_Forge*     forge,
        lv2_atom_forge_property_head(forge, urids.time_beatsPerBar, 0);
        lv2_atom_forge_float(forge, t.meter().divisions_per_bar());
        lv2_atom_forge_property_head(forge, urids.time_beatsPerMinute, 0);
-       lv2_atom_forge_float(forge, t.tempo().beats_per_minute());
+       lv2_atom_forge_float(forge, bpm);
 #endif
 
        LV2_Evbuf_Iterator    end  = lv2_evbuf_end(buf);
@@ -2346,7 +2354,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
        }
 
        if (_bpm_control_port) {
-               *_bpm_control_port = tmetric.tempo().beats_per_minute();
+               *_bpm_control_port = tmap.tempo_at_frame (start).beats_per_minute();
        }
 
 #ifdef LV2_EXTENDED
@@ -2416,14 +2424,20 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                        }
 
                        if (valid && (flags & PORT_INPUT)) {
-                               Timecode::BBT_Time bbt;
                                if ((flags & PORT_POSITION)) {
+                                       Timecode::BBT_Time bbt (tmap.bbt_at_frame (start));
+                                       double bpm = tmap.tempo_at_frame (start).beats_per_minute();
+                                       double beatpos = (bbt.bars - 1) * tmetric.meter().divisions_per_bar()
+                                                      + (bbt.beats - 1)
+                                                      + (bbt.ticks / Timecode::BBT_Time::ticks_per_beat);
+                                       beatpos *= tmetric.meter().note_divisor() / 4.0;
                                        if (start != _next_cycle_start ||
-                                           speed != _next_cycle_speed) {
-                                               // Transport has changed, write position at cycle start
-                                               bbt = tmap.bbt_at_frame (start);
+                                                       speed != _next_cycle_speed ||
+                                                       rint (1000 * beatpos) != rint(1000 * _next_cycle_beat) ||
+                                                       bpm != _current_bpm) {
+                                               // Transport or Tempo has changed, write position at cycle start
                                                write_position(&_impl->forge, _ev_buffers[port_index],
-                                                              tmetric, bbt, speed, start, 0);
+                                                               tmetric, bbt, speed, bpm, start, 0);
                                        }
                                }
 
@@ -2452,9 +2466,11 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
                                                ++m;
                                        } else {
                                                tmetric.set_metric(metric);
+                                               Timecode::BBT_Time bbt;
                                                bbt = tmap.bbt_at_pulse (metric->pulse());
+                                               double bpm = tmap.tempo_at_frame (start/*XXX*/).beats_per_minute();
                                                write_position(&_impl->forge, _ev_buffers[port_index],
-                                                              tmetric, bbt, speed,
+                                                              tmetric, bbt, speed, bpm,
                                                               metric->frame(),
                                                               metric->frame() - start);
                                                ++metric_i;
@@ -2708,6 +2724,21 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
        _next_cycle_speed = speed;
        _next_cycle_start = end;
 
+       {
+               /* keep track of lv2:timePosition like plugins can do.
+                * Note: for no-midi plugins, we only ever send information at cycle-start,
+                * so it needs to be realative to that.
+                */
+               TempoMetric t = tmap.metric_at(start);
+               _current_bpm = tmap.tempo_at_frame (start).beats_per_minute();
+               Timecode::BBT_Time bbt (tmap.bbt_at_frame (start));
+               double beatpos = (bbt.bars - 1) * t.meter().divisions_per_bar()
+                              + (bbt.beats - 1)
+                              + (bbt.ticks / Timecode::BBT_Time::ticks_per_beat);
+               beatpos *= tmetric.meter().note_divisor() / 4.0;
+               _next_cycle_beat = beatpos + nframes * speed * _current_bpm / (60.f * _session.frame_rate());
+       }
+
        if (_latency_control_port) {
                framecnt_t new_latency = signal_latency ();
                _current_latency = new_latency;
@@ -2806,7 +2837,7 @@ LV2Plugin::get_scale_points(uint32_t port_index) const
 }
 
 void
-LV2Plugin::run(pframes_t nframes)
+LV2Plugin::run(pframes_t nframes, bool sync_work)
 {
        uint32_t const N = parameter_count();
        for (uint32_t i = 0; i < N; ++i) {
@@ -2817,7 +2848,7 @@ LV2Plugin::run(pframes_t nframes)
 
        if (_worker) {
                // Execute work synchronously if we're freewheeling (export)
-               _worker->set_synchronous(session().engine().freewheeling());
+               _worker->set_synchronous(sync_work || session().engine().freewheeling());
        }
 
        // Run the plugin for this cycle
@@ -2878,7 +2909,7 @@ LV2Plugin::latency_compute_run()
                port_index++;
        }
 
-       run(bufsize);
+       run(bufsize, true);
        deactivate();
        if (was_activated) {
                activate();