+void
+LV2Plugin::allocate_atom_event_buffers()
+{
+ /* reserve local scratch buffers for ATOM event-queues */
+ const LilvPlugin* p = _impl->plugin;
+
+ /* count non-MIDI atom event-ports
+ * TODO: nicely ask drobilla to make a lilv_ call for that
+ */
+ int count_atom_out = 0;
+ int count_atom_in = 0;
+ for (uint32_t i = 0; i < lilv_plugin_get_num_ports(p); ++i) {
+ const LilvPort* port = lilv_plugin_get_port_by_index(p, i);
+ if (lilv_port_is_a(p, port, _world.atom_AtomPort)) {
+ LilvNodes* buffer_types = lilv_port_get_value(
+ p, port, _world.atom_bufferType);
+ LilvNodes* atom_supports = lilv_port_get_value(
+ p, port, _world.atom_supports);
+
+ if (!lilv_nodes_contains(buffer_types, _world.atom_Sequence)
+ || !lilv_nodes_contains(atom_supports, _world.midi_MidiEvent)) {
+ if (lilv_port_is_a(p, port, _world.lv2_InputPort)) {
+ count_atom_in++;
+ }
+ if (lilv_port_is_a(p, port, _world.lv2_OutputPort)) {
+ count_atom_out++;
+ }
+ }
+ lilv_nodes_free(buffer_types);
+ lilv_nodes_free(atom_supports);
+ }
+ }
+
+ DEBUG_TRACE(DEBUG::LV2, string_compose("%1 need buffers for %2 atom-in and %3 atom-out event-ports\n",
+ name(), count_atom_in, count_atom_out));
+
+ const int total_atom_buffers = (count_atom_in + count_atom_out);
+ if (_atom_ev_buffers || total_atom_buffers == 0) {
+ return;
+ }
+
+ DEBUG_TRACE(DEBUG::LV2, string_compose("allocate %1 atom_ev_buffers\n", total_atom_buffers));
+ _atom_ev_buffers = (LV2_Evbuf**) malloc((total_atom_buffers + 1) * sizeof(LV2_Evbuf*));
+ for (int i = 0; i < total_atom_buffers; ++i ) {
+ _atom_ev_buffers[i] = lv2_evbuf_new(32768, LV2_EVBUF_ATOM,
+ LV2Plugin::urids.atom_Chunk, LV2Plugin::urids.atom_Sequence);
+ }
+ _atom_ev_buffers[total_atom_buffers] = 0;
+ return;
+}
+
+/** Write an ardour position/time/tempo/meter as an LV2 event.
+ * @return true on success.
+ */
+static bool
+write_position(LV2_Atom_Forge* forge,
+ LV2_Evbuf* buf,
+ const TempoMetric& t,
+ Timecode::BBT_Time& bbt,
+ double speed,
+ framepos_t position,
+ framecnt_t offset)
+{
+ uint8_t pos_buf[256];
+ lv2_atom_forge_set_buffer(forge, pos_buf, sizeof(pos_buf));
+ LV2_Atom_Forge_Frame frame;
+ lv2_atom_forge_blank(forge, &frame, 1, LV2Plugin::urids.time_Position);
+ lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_frame, 0);
+ lv2_atom_forge_long(forge, position);
+ lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_speed, 0);
+ lv2_atom_forge_float(forge, speed);
+ lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_barBeat, 0);
+ lv2_atom_forge_float(forge, bbt.beats - 1 +
+ (bbt.ticks / Timecode::BBT_Time::ticks_per_beat));
+ lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_bar, 0);
+ lv2_atom_forge_long(forge, bbt.bars - 1);
+ lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_beatUnit, 0);
+ lv2_atom_forge_int(forge, t.meter().note_divisor());
+ lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_beatsPerBar, 0);
+ lv2_atom_forge_float(forge, t.meter().divisions_per_bar());
+ lv2_atom_forge_property_head(forge, LV2Plugin::urids.time_beatsPerMinute, 0);
+ lv2_atom_forge_float(forge, t.tempo().beats_per_minute());
+
+ LV2_Evbuf_Iterator end = lv2_evbuf_end(buf);
+ const LV2_Atom* const atom = (const LV2_Atom*)pos_buf;
+ return lv2_evbuf_write(&end, offset, 0, atom->type, atom->size,
+ (const uint8_t*)(atom + 1));
+}
+