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
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
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
;
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
;
62 midi_event_type
= 0xFFFFFFFF;
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
) {
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
);
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();
161 configure(p[0], p[1]);
168 struct LV2_Calf_Descriptor
{
169 plugin_ctl_iface
*(*get_pci
)(LV2_Handle Instance
);
172 template<class Module
>
175 typedef lv2_instance
<Module
> instance
;
176 static LV2_Descriptor descriptor
;
177 static LV2_Calf_Descriptor calf_descriptor
;
178 static LV2MessageContext message_context
;
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
;
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
;
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;
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
);
252 mod
->post_instantiate();
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
)
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
);
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
);
288 mod
->set_srate
= false;
290 mod
->params_changed();
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);
305 process_slice(mod
, 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;
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
;
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
;
340 static lv2_wrapper
&get() {
341 static lv2_wrapper instance
;