+ Filter: implement drawing optimization
[calf.git] / src / calf / lv2wrap.h
blobc8c3a52d32a3d88fa5ef6e4e5eb788a08f6d1198
1 /* Calf DSP Library
2 * LV2 wrapper templates
4 * Copyright (C) 2001-2008 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, USA.
21 #ifndef CALF_LV2WRAP_H
22 #define CALF_LV2WRAP_H
24 #if USE_LV2
26 #include <string>
27 #include <vector>
28 #include <lv2.h>
29 #include <calf/giface.h>
30 #include <calf/lv2-midiport.h>
31 #include <calf/lv2_contexts.h>
32 #include <calf/lv2_event.h>
33 #include <calf/lv2_progress.h>
34 #include <calf/lv2_string_port.h>
35 #include <calf/lv2_uri_map.h>
37 namespace calf_plugins {
39 template<class Module>
40 struct lv2_instance: public plugin_ctl_iface, public progress_report_iface, public Module
42 bool set_srate;
43 int srate_to_set;
44 LV2_MIDI *midi_data;
45 LV2_Event_Buffer *event_data;
46 LV2_URI_Map_Feature *uri_map;
47 LV2_Event_Feature *event_feature;
48 uint32_t midi_event_type;
49 std::vector<int> message_params;
50 LV2_Progress *progress_report_feature;
51 lv2_instance()
53 for (int i=0; i < Module::in_count; i++)
54 Module::ins[i] = NULL;
55 for (int i=0; i < Module::out_count; i++)
56 Module::outs[i] = NULL;
57 for (int i=0; i < Module::param_count; i++)
58 Module::params[i] = NULL;
59 uri_map = NULL;
60 midi_data = NULL;
61 event_data = NULL;
62 midi_event_type = 0xFFFFFFFF;
63 set_srate = true;
64 srate_to_set = 44100;
65 get_message_context_parameters(message_params);
66 progress_report_feature = NULL;
67 // printf("message params %d\n", (int)message_params.size());
69 /// This, and not Module::post_instantiate, is actually called by lv2_wrapper class
70 void post_instantiate()
72 if (progress_report_feature)
73 Module::progress_report = this;
74 Module::post_instantiate();
76 virtual parameter_properties *get_param_props(int param_no)
78 return &Module::param_props[param_no];
80 virtual float get_param_value(int param_no)
82 return *Module::params[param_no];
84 virtual void set_param_value(int param_no, float value)
86 *Module::params[param_no] = value;
88 virtual int get_param_count()
90 return Module::param_count;
92 virtual int get_param_port_offset()
94 return Module::in_count + Module::out_count;
96 virtual const char *get_gui_xml() {
97 return Module::get_gui_xml();
99 virtual line_graph_iface *get_line_graph_iface()
101 return dynamic_cast<line_graph_iface *>(this);
103 virtual bool activate_preset(int bank, int program) {
104 return false;
106 virtual const char *get_name()
108 return Module::get_name();
110 virtual const char *get_id()
112 return Module::get_id();
114 virtual const char *get_label()
116 return Module::get_label();
118 virtual int get_input_count() { return Module::in_count; }
119 virtual int get_output_count() { return Module::out_count; }
120 virtual bool get_midi() { return Module::support_midi; }
121 virtual float get_level(unsigned int port) { return 0.f; }
122 virtual void execute(int cmd_no) {
123 Module::execute(cmd_no);
125 virtual void report_progress(float percentage, const std::string &message) {
126 if (progress_report_feature)
127 (*progress_report_feature->progress)(progress_report_feature->context, percentage, !message.empty() ? message.c_str() : NULL);
129 void send_configures(send_configure_iface *sci) {
130 Module::send_configures(sci);
132 uint32_t impl_message_run(const void *valid_inputs, void *output_ports) {
133 for (unsigned int i = 0; i < message_params.size(); i++)
135 int pn = message_params[i];
136 parameter_properties &pp = *get_param_props(pn);
137 if ((pp.flags & PF_TYPEMASK) == PF_STRING
138 && (((LV2_String_Data *)Module::params[pn])->flags & LV2_STRING_DATA_CHANGED_FLAG)) {
139 printf("Calling configure on %s\n", pp.short_name);
140 configure(pp.short_name, ((LV2_String_Data *)Module::params[pn])->data);
143 return Module::message_run(valid_inputs, output_ports);
145 char *configure(const char *key, const char *value) {
146 // disambiguation - the plugin_ctl_iface version is just a stub, so don't use it
147 return Module::configure(key, value);
149 #if 0
150 // the default implementation should be fine
151 virtual void clear_preset() {
152 // This is never called in practice, at least for now
153 // However, it will change when presets are implemented
154 for (int i=0; i < Module::param_count; i++)
155 *Module::params[i] = Module::param_props[i].def_value;
157 const char **p = Module::get_default_configure_vars();
158 if (p)
160 for(; p[0]; p += 2)
161 configure(p[0], p[1]);
165 #endif
168 struct LV2_Calf_Descriptor {
169 plugin_ctl_iface *(*get_pci)(LV2_Handle Instance);
172 template<class Module>
173 struct lv2_wrapper
175 typedef lv2_instance<Module> instance;
176 static LV2_Descriptor descriptor;
177 static LV2_Calf_Descriptor calf_descriptor;
178 static LV2MessageContext message_context;
179 std::string uri;
181 lv2_wrapper()
183 ladspa_plugin_info &info = Module::plugin_info;
184 uri = "http://calf.sourceforge.net/plugins/" + std::string(info.label);
185 descriptor.URI = uri.c_str();
186 descriptor.instantiate = cb_instantiate;
187 descriptor.connect_port = cb_connect;
188 descriptor.activate = cb_activate;
189 descriptor.run = cb_run;
190 descriptor.deactivate = cb_deactivate;
191 descriptor.cleanup = cb_cleanup;
192 descriptor.extension_data = cb_ext_data;
193 calf_descriptor.get_pci = cb_get_pci;
194 message_context.message_connect_port = cb_connect;
195 message_context.message_run = cb_message_run;
198 static void cb_connect(LV2_Handle Instance, uint32_t port, void *DataLocation) {
199 unsigned long ins = Module::in_count;
200 unsigned long outs = Module::out_count;
201 unsigned long params = Module::param_count;
202 instance *const mod = (instance *)Instance;
203 if (port < ins)
204 mod->ins[port] = (float *)DataLocation;
205 else if (port < ins + outs)
206 mod->outs[port - ins] = (float *)DataLocation;
207 else if (port < ins + outs + params) {
208 int i = port - ins - outs;
209 mod->params[i] = (float *)DataLocation;
211 else if (Module::support_midi && port == ins + outs + params) {
212 mod->event_data = (LV2_Event_Buffer *)DataLocation;
216 static void cb_activate(LV2_Handle Instance) {
217 instance *const mod = (instance *)Instance;
218 mod->set_srate = true;
221 static void cb_deactivate(LV2_Handle Instance) {
222 instance *const mod = (instance *)Instance;
223 mod->deactivate();
226 static LV2_Handle cb_instantiate(const LV2_Descriptor * Descriptor, double sample_rate, const char *bundle_path, const LV2_Feature *const *features)
228 instance *mod = new instance();
229 // XXXKF some people use fractional sample rates; we respect them ;-)
230 mod->srate_to_set = (uint32_t)sample_rate;
231 mod->set_srate = true;
232 while(*features)
234 if (!strcmp((*features)->URI, LV2_URI_MAP_URI))
236 mod->uri_map = (LV2_URI_Map_Feature *)((*features)->data);
237 mod->midi_event_type = mod->uri_map->uri_to_id(
238 mod->uri_map->callback_data,
239 "http://lv2plug.in/ns/ext/event",
240 "http://lv2plug.in/ns/ext/midi#MidiEvent");
242 else if (!strcmp((*features)->URI, LV2_EVENT_URI))
244 mod->event_feature = (LV2_Event_Feature *)((*features)->data);
246 else if (!strcmp((*features)->URI, LV2_PROGRESS_URI))
248 mod->progress_report_feature = (LV2_Progress *)((*features)->data);
250 features++;
252 mod->post_instantiate();
253 return mod;
255 static inline void zero_by_mask(Module *module, uint32_t mask, uint32_t offset, uint32_t nsamples)
257 for (int i=0; i<Module::out_count; i++) {
258 if ((mask & (1 << i)) == 0) {
259 dsp::zero(module->outs[i] + offset, nsamples);
263 static plugin_ctl_iface *cb_get_pci(LV2_Handle Instance)
265 return static_cast<plugin_ctl_iface *>(Instance);
268 static inline void process_slice(Module *mod, uint32_t offset, uint32_t end)
270 while(offset < end)
272 uint32_t newend = std::min(offset + MAX_SAMPLE_RUN, end);
273 uint32_t out_mask = mod->process(offset, newend - offset, -1, -1);
274 zero_by_mask(mod, out_mask, offset, newend - offset);
275 offset = newend;
279 static uint32_t cb_message_run(LV2_Handle Instance, const void *valid_inputs, void *outputs_written) {
280 instance *mod = (instance *)Instance;
281 return mod->impl_message_run(valid_inputs, outputs_written);
283 static void cb_run(LV2_Handle Instance, uint32_t SampleCount) {
284 instance *const mod = (instance *)Instance;
285 if (mod->set_srate) {
286 mod->set_sample_rate(mod->srate_to_set);
287 mod->activate();
288 mod->set_srate = false;
290 mod->params_changed();
291 uint32_t offset = 0;
292 if (mod->event_data)
294 // printf("Event data: count %d\n", mod->event_data->event_count);
295 struct LV2_Midi_Event: public LV2_Event {
296 unsigned char data[1];
298 unsigned char *data = (unsigned char *)(mod->event_data->data);
299 for (uint32_t i = 0; i < mod->event_data->event_count; i++) {
300 LV2_Midi_Event *item = (LV2_Midi_Event *)data;
301 uint32_t ts = item->frames;
302 // printf("Event: timestamp %d subframes %d type %d vs %d\n", item->frames, item->subframes, item->type, mod->midi_event_type);
303 if (ts > offset)
305 process_slice(mod, offset, ts);
306 offset = ts;
308 if (item->type == mod->midi_event_type)
310 // printf("Midi message %x %x %x %x %d\n", item->data[0], item->data[1], item->data[2], item->data[3], item->size);
311 switch(item->data[0] >> 4)
313 case 8: mod->note_off(item->data[1], item->data[2]); break;
314 case 9: mod->note_on(item->data[1], item->data[2]); break;
315 case 11: mod->control_change(item->data[1], item->data[2]); break;
316 case 12: mod->program_change(item->data[1]); break;
317 case 14: mod->pitch_bend(item->data[1] + 128 * item->data[2] - 8192); break;
320 else
321 if (item->type == 0 && mod->event_feature)
322 mod->event_feature->lv2_event_unref(mod->event_feature->callback_data, item);
323 // printf("timestamp %f item size %d first byte %x\n", item->timestamp, item->size, item->data[0]);
324 data += ((sizeof(LV2_Event) + item->size + 7))&~7;
327 process_slice(mod, offset, SampleCount);
329 static void cb_cleanup(LV2_Handle Instance) {
330 instance *const mod = (instance *)Instance;
331 delete mod;
333 static const void *cb_ext_data(const char *URI) {
334 if (!strcmp(URI, "http://foltman.com/ns/calf-plugin-instance"))
335 return &calf_descriptor;
336 if (!strcmp(URI, LV2_CONTEXT_MESSAGE))
337 return &message_context;
338 return NULL;
340 static lv2_wrapper &get() {
341 static lv2_wrapper instance;
342 return instance;
348 #endif
349 #endif