+ Framework: general clean-up and simplification of wrapper-related code, moved vario...
[calf.git] / src / calf / jackhost.h
blob51eb18e9b5267dd1942e9e05015028684e4dd944
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 <jack/jack.h>
27 #include <jack/midiport.h>
28 #include "gui.h"
29 #include "utils.h"
30 #include <pthread.h>
32 namespace synth {
34 class jack_host_base;
36 class jack_client {
37 protected:
38 std::vector<jack_host_base *> plugins;
39 calf_utils::ptmutex mutex;
40 public:
41 jack_client_t *client;
42 int input_nr, output_nr, midi_nr;
43 std::string input_name, output_name, midi_name;
44 int sample_rate;
46 jack_client()
48 input_nr = output_nr = midi_nr = 1;
49 input_name = "input_%d";
50 output_name = "output_%d";
51 midi_name = "midi_%d";
52 sample_rate = 0;
53 client = NULL;
56 void add(jack_host_base *plugin)
58 calf_utils::ptlock lock(mutex);
59 plugins.push_back(plugin);
62 void del(int item)
64 calf_utils::ptlock lock(mutex);
65 plugins.erase(plugins.begin()+item);
68 void open(const char *client_name)
70 jack_status_t status;
71 client = jack_client_open(client_name, JackNullOption, &status);
72 if (!client)
73 throw audio_exception("Could not initialize JACK subsystem");
74 sample_rate = jack_get_sample_rate(client);
75 jack_set_process_callback(client, do_jack_process, this);
76 jack_set_buffer_size_callback(client, do_jack_bufsize, this);
79 std::string get_name()
81 return std::string(jack_get_client_name(client));
84 void activate()
86 jack_activate(client);
89 void deactivate()
91 jack_deactivate(client);
94 void delete_plugins();
96 void connect(const std::string &p1, const std::string &p2)
98 if (jack_connect(client, p1.c_str(), p2.c_str()) != 0)
99 throw audio_exception("Could not connect JACK ports "+p1+" and "+p2);
102 void close()
104 jack_client_close(client);
107 static int do_jack_process(jack_nframes_t nframes, void *p);
108 static int do_jack_bufsize(jack_nframes_t numsamples, void *p);
111 class jack_host_base: public plugin_ctl_iface {
112 public:
113 typedef int (*process_func)(jack_nframes_t nframes, void *p);
114 struct port {
115 jack_port_t *handle;
116 float *data;
117 std::string name;
118 port() : handle(NULL), data(NULL) {}
119 ~port() { }
121 jack_client *client;
122 bool changed;
123 port midi_port;
124 std::string name;
125 virtual port *get_inputs()=0;
126 virtual port *get_outputs()=0;
127 virtual port *get_midi_port() { return get_midi() ? &midi_port : NULL; }
128 virtual float *get_params()=0;
129 virtual void init_module()=0;
130 virtual void cache_ports()=0;
131 virtual int process(jack_nframes_t nframes)=0;
133 jack_host_base() {
134 client = NULL;
135 changed = true;
138 void set_params(const float *params) {
139 memcpy(get_params(), params, get_param_count() * sizeof(float));
140 changed = true;
143 void set_params() {
144 changed = true;
147 void open(jack_client *_client)
149 client = _client; //jack_client_open(client_name, JackNullOption, &status);
151 create_ports();
153 cache_ports();
155 init_module();
156 changed = false;
159 virtual void create_ports() {
160 char buf[32];
161 port *inputs = get_inputs();
162 port *outputs = get_outputs();
163 int in_count = get_input_count(), out_count = get_output_count();
164 for (int i=0; i<in_count; i++) {
165 sprintf(buf, client->input_name.c_str(), client->input_nr++);
166 inputs[i].name = buf;
167 inputs[i].handle = jack_port_register(client->client, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput , 0);
168 inputs[i].data = NULL;
169 if (!inputs[i].handle)
170 throw audio_exception("Could not create JACK input port");
172 for (int i=0; i<out_count; i++) {
173 sprintf(buf, client->output_name.c_str(), client->output_nr++);
174 outputs[i].name = buf;
175 outputs[i].handle = jack_port_register(client->client, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput , 0);
176 outputs[i].data = NULL;
177 if (!outputs[i].handle)
178 throw audio_exception("Could not create JACK output port");
180 if (get_midi()) {
181 sprintf(buf, client->midi_name.c_str(), client->midi_nr++);
182 midi_port.name = buf;
183 midi_port.handle = jack_port_register(client->client, buf, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
184 if (!midi_port.handle)
185 throw audio_exception("Could not create JACK MIDI port");
189 void close() {
190 port *inputs = get_inputs(), *outputs = get_outputs();
191 int input_count = get_input_count(), output_count = get_output_count();
192 for (int i = 0; i < input_count; i++) {
193 jack_port_unregister(client->client, inputs[i].handle);
194 inputs[i].data = NULL;
196 for (int i = 0; i < output_count; i++) {
197 jack_port_unregister(client->client, outputs[i].handle);
198 outputs[i].data = NULL;
200 if (get_midi())
201 jack_port_unregister(client->client, midi_port.handle);
202 client = NULL;
205 virtual ~jack_host_base() {
209 struct vumeter
211 float level, falloff;
213 vumeter()
215 falloff = 0.999f;
216 level = 0;
219 inline void update(float *src, unsigned int len)
221 double tmp = level;
222 for (unsigned int i = 0; i < len; i++)
223 tmp = std::max(tmp * falloff, (double)fabs(src[i]));
224 level = tmp;
225 dsp::sanitize(level);
227 inline void update_zeros(unsigned int len)
229 level *= pow((double)falloff, (double)len);
230 dsp::sanitize(level);
234 template<class Module>
235 class jack_host: public jack_host_base, public Module {
236 public:
237 using Module::in_count;
238 using Module::out_count;
239 using Module::param_count;
241 port inputs[in_count], outputs[out_count];
242 vumeter input_vus[in_count], output_vus[out_count];
243 float param_values[param_count];
244 float midi_meter;
246 jack_host()
248 for (int i = 0; i < Module::param_count; i++) {
249 param_values[i] = Module::param_props[i].def_value;
250 Module::params[i] = &param_values[i];
252 midi_meter = 0;
255 ~jack_host()
257 if (client)
258 close();
261 virtual void init_module() {
262 Module::set_sample_rate(client->sample_rate);
263 Module::activate();
264 Module::params_changed();
267 virtual synth::parameter_properties* get_param_props(int param_no) { return Module::param_props + param_no; }
269 void handle_event(uint8_t *buffer, uint32_t size)
271 int value;
272 switch(buffer[0] >> 4)
274 case 8:
275 Module::note_off(buffer[1], buffer[2]);
276 break;
277 case 9:
278 if (!buffer[2])
279 Module::note_off(buffer[1], 0);
280 else
281 Module::note_on(buffer[1], buffer[2]);
282 break;
283 case 10:
284 Module::program_change(buffer[1]);
285 break;
286 case 11:
287 Module::control_change(buffer[1], buffer[2]);
288 break;
289 case 14:
290 value = buffer[1] + 128 * buffer[2] - 8192;
291 Module::pitch_bend(value);
292 break;
295 void process_part(unsigned int time, unsigned int len)
297 if (!len)
298 return;
299 for (int i = 0; i < in_count; i++)
300 input_vus[i].update(Module::ins[i] + time, len);
301 unsigned int mask = Module::process(time, len, -1, -1);
302 for (int i = 0; i < out_count; i++)
304 if (!(mask & (1 << i))) {
305 dsp::zero(Module::outs[i] + time, len);
306 output_vus[i].update_zeros(len);
307 } else
308 output_vus[i].update(Module::outs[i] + time, len);
310 // decay linearly for 0.1s
311 float new_meter = midi_meter - len / (0.1 * client->sample_rate);
312 if (new_meter < 0)
313 new_meter = 0;
314 midi_meter = new_meter;
316 virtual float get_level(unsigned int port) {
317 if (port < in_count)
318 return input_vus[port].level;
319 port -= in_count;
320 if (port < out_count)
321 return output_vus[port].level;
322 port -= out_count;
323 if (port == 0 && Module::support_midi)
324 return midi_meter;
325 return 0.f;
327 int process(jack_nframes_t nframes)
329 for (int i=0; i<in_count; i++) {
330 Module::ins[i] = inputs[i].data = (float *)jack_port_get_buffer(inputs[i].handle, nframes);
332 if (Module::support_midi)
333 midi_port.data = (float *)jack_port_get_buffer(midi_port.handle, nframes);
334 if (changed) {
335 Module::params_changed();
336 changed = false;
339 unsigned int time = 0;
340 if (Module::support_midi)
342 jack_midi_event_t event;
343 #ifdef OLD_JACK
344 int count = jack_midi_get_event_count(midi_port.data, nframes);
345 #else
346 int count = jack_midi_get_event_count(midi_port.data);
347 #endif
348 for (int i = 0; i < count; i++)
350 #ifdef OLD_JACK
351 jack_midi_event_get(&event, midi_port.data, i, nframes);
352 #else
353 jack_midi_event_get(&event, midi_port.data, i);
354 #endif
355 unsigned int len = event.time - time;
356 process_part(time, len);
358 midi_meter = 1.f;
359 handle_event(event.buffer, event.size);
361 time = event.time;
364 process_part(time, nframes - time);
365 Module::params_reset();
366 return 0;
369 void cache_ports()
371 for (int i=0; i<out_count; i++) {
372 Module::outs[i] = outputs[i].data = (float *)jack_port_get_buffer(outputs[i].handle, 0);
376 virtual void zero_io() {
377 memset(inputs, 0, sizeof(inputs));
378 memset(outputs, 0, sizeof(outputs));
381 virtual port *get_inputs() { return inputs; }
382 virtual port *get_outputs() { return outputs; }
383 virtual float *get_params() { return param_values; }
384 virtual bool activate_preset(int bank, int program) { return false; }
385 virtual float get_param_value(int param_no) {
386 return param_values[param_no];
388 virtual void set_param_value(int param_no, float value) {
389 param_values[param_no] = value;
390 changed = true;
392 virtual void execute(int cmd_no) {
393 Module::execute(cmd_no);
395 virtual char *configure(const char *key, const char *value) {
396 return Module::configure(key, value);
398 virtual void send_configures(send_configure_iface *sci) {
399 Module::send_configures(sci);
403 extern jack_host_base *create_jack_host(const char *name);
405 #endif
409 #endif