+ Framework: separate metadata-related parts out of plugin classes and plugin control...
[calf.git] / src / calf / jackhost.h
blobf1e1eabd2ed35e0d0157c8287fabde318eb41566
1 /* Calf DSP Library Utility Application - calfjackhost
2 * API wrapper for JACK Audio Connection Kit
4 * Copyright (C) 2007 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
21 #ifndef __CALF_JACKHOST_H
22 #define __CALF_JACKHOST_H
24 #if USE_JACK
26 #include "gui.h"
27 #include "utils.h"
28 #include <pthread.h>
30 namespace synth {
32 class jack_host_base;
34 class jack_client {
35 protected:
36 std::vector<jack_host_base *> plugins;
37 calf_utils::ptmutex mutex;
38 public:
39 jack_client_t *client;
40 int input_nr, output_nr, midi_nr;
41 std::string input_name, output_name, midi_name;
42 int sample_rate;
44 jack_client()
46 input_nr = output_nr = midi_nr = 1;
47 input_name = "input_%d";
48 output_name = "output_%d";
49 midi_name = "midi_%d";
50 sample_rate = 0;
51 client = NULL;
54 void add(jack_host_base *plugin)
56 calf_utils::ptlock lock(mutex);
57 plugins.push_back(plugin);
60 void del(int item)
62 calf_utils::ptlock lock(mutex);
63 plugins.erase(plugins.begin()+item);
66 void open(const char *client_name)
68 jack_status_t status;
69 client = jack_client_open(client_name, JackNullOption, &status);
70 if (!client)
71 throw audio_exception("Could not initialize JACK subsystem");
72 sample_rate = jack_get_sample_rate(client);
73 jack_set_process_callback(client, do_jack_process, this);
74 jack_set_buffer_size_callback(client, do_jack_bufsize, this);
77 std::string get_name()
79 return std::string(jack_get_client_name(client));
82 void activate()
84 jack_activate(client);
87 void deactivate()
89 jack_deactivate(client);
92 void delete_plugins();
94 void connect(const std::string &p1, const std::string &p2)
96 if (jack_connect(client, p1.c_str(), p2.c_str()) != 0)
97 throw audio_exception("Could not connect JACK ports "+p1+" and "+p2);
100 void close()
102 jack_client_close(client);
105 static int do_jack_process(jack_nframes_t nframes, void *p);
106 static int do_jack_bufsize(jack_nframes_t numsamples, void *p);
109 class jack_host_base: public plugin_ctl_iface {
110 public:
111 typedef int (*process_func)(jack_nframes_t nframes, void *p);
112 struct port {
113 jack_port_t *handle;
114 float *data;
115 std::string name;
116 port() : handle(NULL), data(NULL) {}
117 ~port() { }
119 jack_client *client;
120 bool changed;
121 port midi_port;
122 std::string name;
123 virtual port *get_inputs()=0;
124 virtual port *get_outputs()=0;
125 virtual port *get_midi_port() { return get_midi() ? &midi_port : NULL; }
126 virtual float *get_params()=0;
127 virtual void init_module()=0;
128 virtual void cache_ports()=0;
129 virtual int process(jack_nframes_t nframes)=0;
131 jack_host_base() {
132 client = NULL;
133 changed = true;
136 void set_params(const float *params) {
137 memcpy(get_params(), params, get_param_count() * sizeof(float));
138 changed = true;
141 void set_params() {
142 changed = true;
145 void open(jack_client *_client)
147 client = _client; //jack_client_open(client_name, JackNullOption, &status);
149 create_ports();
151 cache_ports();
153 init_module();
154 changed = false;
157 virtual void create_ports() {
158 char buf[32];
159 port *inputs = get_inputs();
160 port *outputs = get_outputs();
161 int in_count = get_input_count(), out_count = get_output_count();
162 for (int i=0; i<in_count; i++) {
163 sprintf(buf, client->input_name.c_str(), client->input_nr++);
164 inputs[i].name = buf;
165 inputs[i].handle = jack_port_register(client->client, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput , 0);
166 inputs[i].data = NULL;
167 if (!inputs[i].handle)
168 throw audio_exception("Could not create JACK input port");
170 for (int i=0; i<out_count; i++) {
171 sprintf(buf, client->output_name.c_str(), client->output_nr++);
172 outputs[i].name = buf;
173 outputs[i].handle = jack_port_register(client->client, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput , 0);
174 outputs[i].data = NULL;
175 if (!outputs[i].handle)
176 throw audio_exception("Could not create JACK output port");
178 if (get_midi()) {
179 sprintf(buf, client->midi_name.c_str(), client->midi_nr++);
180 midi_port.name = buf;
181 midi_port.handle = jack_port_register(client->client, buf, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
182 if (!midi_port.handle)
183 throw audio_exception("Could not create JACK MIDI port");
187 void close() {
188 port *inputs = get_inputs(), *outputs = get_outputs();
189 int input_count = get_input_count(), output_count = get_output_count();
190 for (int i = 0; i < input_count; i++) {
191 jack_port_unregister(client->client, inputs[i].handle);
192 inputs[i].data = NULL;
194 for (int i = 0; i < output_count; i++) {
195 jack_port_unregister(client->client, outputs[i].handle);
196 outputs[i].data = NULL;
198 if (get_midi())
199 jack_port_unregister(client->client, midi_port.handle);
200 client = NULL;
203 virtual ~jack_host_base() {
207 struct vumeter
209 float level, falloff;
211 vumeter()
213 falloff = 0.999f;
214 level = 0;
217 inline void update(float *src, unsigned int len)
219 double tmp = level;
220 for (unsigned int i = 0; i < len; i++)
221 tmp = std::max(tmp * falloff, (double)fabs(src[i]));
222 level = tmp;
223 dsp::sanitize(level);
225 inline void update_zeros(unsigned int len)
227 level *= pow((double)falloff, (double)len);
228 dsp::sanitize(level);
232 template<class Module>
233 class jack_host: public jack_host_base, public Module {
234 public:
235 using Module::in_count;
236 using Module::out_count;
237 using Module::param_count;
239 port inputs[in_count], outputs[out_count];
240 vumeter input_vus[in_count], output_vus[out_count];
241 float param_values[param_count];
242 float midi_meter;
244 jack_host()
246 for (int i = 0; i < Module::param_count; i++) {
247 param_values[i] = Module::param_props[i].def_value;
248 Module::params[i] = &param_values[i];
250 midi_meter = 0;
253 ~jack_host()
255 if (client)
256 close();
259 virtual void init_module() {
260 Module::set_sample_rate(client->sample_rate);
261 Module::activate();
262 Module::params_changed();
265 virtual synth::parameter_properties* get_param_props(int param_no) { return Module::param_props + param_no; }
267 void handle_event(uint8_t *buffer, uint32_t size)
269 int value;
270 switch(buffer[0] >> 4)
272 case 8:
273 Module::note_off(buffer[1], buffer[2]);
274 break;
275 case 9:
276 if (!buffer[2])
277 Module::note_off(buffer[1], 0);
278 else
279 Module::note_on(buffer[1], buffer[2]);
280 break;
281 case 10:
282 Module::program_change(buffer[1]);
283 break;
284 case 11:
285 Module::control_change(buffer[1], buffer[2]);
286 break;
287 case 14:
288 value = buffer[1] + 128 * buffer[2] - 8192;
289 Module::pitch_bend(value);
290 break;
293 void process_part(unsigned int time, unsigned int len)
295 if (!len)
296 return;
297 for (int i = 0; i < in_count; i++)
298 input_vus[i].update(Module::ins[i] + time, len);
299 unsigned int mask = Module::process(time, len, -1, -1);
300 for (int i = 0; i < out_count; i++)
302 if (!(mask & (1 << i))) {
303 dsp::zero(Module::outs[i] + time, len);
304 output_vus[i].update_zeros(len);
305 } else
306 output_vus[i].update(Module::outs[i] + time, len);
308 // decay linearly for 0.1s
309 float new_meter = midi_meter - len / (0.1 * client->sample_rate);
310 if (new_meter < 0)
311 new_meter = 0;
312 midi_meter = new_meter;
314 virtual float get_level(unsigned int port) {
315 if (port < in_count)
316 return input_vus[port].level;
317 port -= in_count;
318 if (port < out_count)
319 return output_vus[port].level;
320 port -= out_count;
321 if (port == 0 && Module::support_midi)
322 return midi_meter;
323 return 0.f;
325 int process(jack_nframes_t nframes)
327 for (int i=0; i<in_count; i++) {
328 Module::ins[i] = inputs[i].data = (float *)jack_port_get_buffer(inputs[i].handle, nframes);
330 if (Module::support_midi)
331 midi_port.data = (float *)jack_port_get_buffer(midi_port.handle, nframes);
332 if (changed) {
333 Module::params_changed();
334 changed = false;
337 unsigned int time = 0;
338 if (Module::support_midi)
340 jack_midi_event_t event;
341 #ifdef OLD_JACK
342 int count = jack_midi_get_event_count(midi_port.data, nframes);
343 #else
344 int count = jack_midi_get_event_count(midi_port.data);
345 #endif
346 for (int i = 0; i < count; i++)
348 #ifdef OLD_JACK
349 jack_midi_event_get(&event, midi_port.data, i, nframes);
350 #else
351 jack_midi_event_get(&event, midi_port.data, i);
352 #endif
353 unsigned int len = event.time - time;
354 process_part(time, len);
356 midi_meter = 1.f;
357 handle_event(event.buffer, event.size);
359 time = event.time;
362 process_part(time, nframes - time);
363 Module::params_reset();
364 return 0;
367 void cache_ports()
369 for (int i=0; i<out_count; i++) {
370 Module::outs[i] = outputs[i].data = (float *)jack_port_get_buffer(outputs[i].handle, 0);
374 virtual void zero_io() {
375 memset(inputs, 0, sizeof(inputs));
376 memset(outputs, 0, sizeof(outputs));
379 virtual port *get_inputs() { return inputs; }
380 virtual port *get_outputs() { return outputs; }
381 virtual float *get_params() { return param_values; }
382 virtual int get_input_count() { return Module::in_count; }
383 virtual int get_output_count() { return Module::out_count; }
384 virtual int get_param_count() { return Module::param_count; }
385 virtual bool get_midi() { return Module::support_midi; }
386 virtual bool activate_preset(int bank, int program) { return false; }
387 virtual int get_param_port_offset()
389 return Module::in_count + Module::out_count;
391 virtual float get_param_value(int param_no) {
392 return param_values[param_no];
394 virtual void set_param_value(int param_no, float value) {
395 param_values[param_no] = value;
396 changed = true;
398 virtual const char *get_gui_xml() {
399 return Module::get_gui_xml();
401 virtual line_graph_iface *get_line_graph_iface()
403 return dynamic_cast<line_graph_iface *>(this);
405 virtual const char *get_name()
407 return Module::get_name();
409 virtual const char *get_id()
411 return Module::get_id();
413 virtual const char *get_label()
415 return Module::get_label();
417 virtual plugin_command_info *get_commands() {
418 return Module::get_commands();
420 virtual void execute(int cmd_no) {
421 Module::execute(cmd_no);
423 virtual char *configure(const char *key, const char *value) {
424 return Module::configure(key, value);
426 virtual void send_configures(send_configure_iface *sci) {
427 Module::send_configures(sci);
429 virtual void clear_preset() {
430 for (int i=0; i < Module::param_count; i++)
431 param_values[i] = Module::param_props[i].def_value;
432 // This is never called in practice, at least for now
433 const char **p = Module::get_default_configure_vars();
434 if (p)
436 for(; p[0]; p += 2)
437 configure(p[0], p[1]);
442 extern jack_host_base *create_jack_host(const char *name);
444 #endif
448 #endif