+ Monosynth: add inertia for pitch wheel
[calf.git] / src / calf / jackhost.h
blobdeeb1824802a6294864014415ab7c2e1feccdc51
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 calf_plugins {
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 name, 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 calf_utils::text_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);
77 name = get_name();
80 std::string get_name()
82 return std::string(jack_get_client_name(client));
85 void activate()
87 jack_activate(client);
90 void deactivate()
92 jack_deactivate(client);
95 void delete_plugins();
97 void connect(const std::string &p1, const std::string &p2)
99 if (jack_connect(client, p1.c_str(), p2.c_str()) != 0)
100 throw calf_utils::text_exception("Could not connect JACK ports "+p1+" and "+p2);
103 void close()
105 jack_client_close(client);
108 static int do_jack_process(jack_nframes_t nframes, void *p);
109 static int do_jack_bufsize(jack_nframes_t numsamples, void *p);
112 class jack_host_base: public plugin_ctl_iface {
113 public:
114 typedef int (*process_func)(jack_nframes_t nframes, void *p);
115 struct port {
116 jack_port_t *handle;
117 float *data;
118 std::string name;
119 port() : handle(NULL), data(NULL) {}
120 ~port() { }
122 jack_client *client;
123 bool changed;
124 port midi_port;
125 std::string name;
126 std::string instance_name;
127 virtual port *get_inputs()=0;
128 virtual port *get_outputs()=0;
129 virtual port *get_midi_port() { return get_midi() ? &midi_port : NULL; }
130 virtual float *get_params()=0;
131 virtual void init_module()=0;
132 virtual void cache_ports()=0;
133 virtual int process(jack_nframes_t nframes)=0;
135 jack_host_base(const std::string &_name, const std::string &_instance_name) {
136 name = _name;
137 instance_name = _instance_name;
139 client = NULL;
140 changed = true;
143 void set_params(const float *params) {
144 memcpy(get_params(), params, get_param_count() * sizeof(float));
145 changed = true;
148 void set_params() {
149 changed = true;
152 void open(jack_client *_client);
154 virtual void create_ports();
156 void close();
158 virtual ~jack_host_base() {
162 struct vumeter
164 float level, falloff;
166 vumeter()
168 falloff = 0.999f;
169 level = 0;
172 inline void update(float *src, unsigned int len)
174 double tmp = level;
175 for (unsigned int i = 0; i < len; i++)
176 tmp = std::max(tmp * falloff, (double)fabs(src[i]));
177 level = tmp;
178 dsp::sanitize(level);
180 inline void update_zeros(unsigned int len)
182 level *= pow((double)falloff, (double)len);
183 dsp::sanitize(level);
187 template<class Module>
188 class jack_host: public jack_host_base, public Module {
189 public:
190 using Module::in_count;
191 using Module::out_count;
192 using Module::param_count;
193 using Module::progress_report;
195 port inputs[in_count], outputs[out_count];
196 vumeter input_vus[in_count], output_vus[out_count];
197 float param_values[param_count];
198 float midi_meter;
200 jack_host(const std::string &_name, const std::string &_instance_name, calf_plugins::progress_report_iface *_priface)
201 : jack_host_base(_name, _instance_name)
203 for (int i = 0; i < Module::param_count; i++) {
204 Module::params[i] = &param_values[i];
206 clear_preset();
207 midi_meter = 0;
208 progress_report = _priface;
209 Module::post_instantiate();
212 ~jack_host()
214 if (client)
215 close();
218 virtual void init_module() {
219 Module::set_sample_rate(client->sample_rate);
220 Module::activate();
221 Module::params_changed();
224 virtual parameter_properties* get_param_props(int param_no) { return Module::param_props + param_no; }
226 void handle_event(uint8_t *buffer, uint32_t size)
228 int value;
229 switch(buffer[0] >> 4)
231 case 8:
232 Module::note_off(buffer[1], buffer[2]);
233 break;
234 case 9:
235 if (!buffer[2])
236 Module::note_off(buffer[1], 0);
237 else
238 Module::note_on(buffer[1], buffer[2]);
239 break;
240 case 11:
241 Module::control_change(buffer[1], buffer[2]);
242 break;
243 case 12:
244 Module::program_change(buffer[1]);
245 break;
246 case 14:
247 value = buffer[1] + 128 * buffer[2] - 8192;
248 Module::pitch_bend(value);
249 break;
252 void process_part(unsigned int time, unsigned int len)
254 if (!len)
255 return;
256 for (int i = 0; i < in_count; i++)
257 input_vus[i].update(Module::ins[i] + time, len);
258 unsigned int mask = Module::process(time, len, -1, -1);
259 for (int i = 0; i < out_count; i++)
261 if (!(mask & (1 << i))) {
262 dsp::zero(Module::outs[i] + time, len);
263 output_vus[i].update_zeros(len);
264 } else
265 output_vus[i].update(Module::outs[i] + time, len);
267 // decay linearly for 0.1s
268 float new_meter = midi_meter - len / (0.1 * client->sample_rate);
269 if (new_meter < 0)
270 new_meter = 0;
271 midi_meter = new_meter;
273 virtual float get_level(unsigned int port) {
274 if (port < in_count)
275 return input_vus[port].level;
276 port -= in_count;
277 if (port < out_count)
278 return output_vus[port].level;
279 port -= out_count;
280 if (port == 0 && Module::support_midi)
281 return midi_meter;
282 return 0.f;
284 int process(jack_nframes_t nframes)
286 for (int i=0; i<in_count; i++) {
287 Module::ins[i] = inputs[i].data = (float *)jack_port_get_buffer(inputs[i].handle, nframes);
289 if (Module::support_midi)
290 midi_port.data = (float *)jack_port_get_buffer(midi_port.handle, nframes);
291 if (changed) {
292 Module::params_changed();
293 changed = false;
296 unsigned int time = 0;
297 if (Module::support_midi)
299 jack_midi_event_t event;
300 #ifdef OLD_JACK
301 int count = jack_midi_get_event_count(midi_port.data, nframes);
302 #else
303 int count = jack_midi_get_event_count(midi_port.data);
304 #endif
305 for (int i = 0; i < count; i++)
307 #ifdef OLD_JACK
308 jack_midi_event_get(&event, midi_port.data, i, nframes);
309 #else
310 jack_midi_event_get(&event, midi_port.data, i);
311 #endif
312 unsigned int len = event.time - time;
313 process_part(time, len);
315 midi_meter = 1.f;
316 handle_event(event.buffer, event.size);
318 time = event.time;
321 process_part(time, nframes - time);
322 Module::params_reset();
323 return 0;
326 void cache_ports()
328 for (int i=0; i<out_count; i++) {
329 Module::outs[i] = outputs[i].data = (float *)jack_port_get_buffer(outputs[i].handle, 0);
333 virtual void zero_io() {
334 memset(inputs, 0, sizeof(inputs));
335 memset(outputs, 0, sizeof(outputs));
338 virtual port *get_inputs() { return inputs; }
339 virtual port *get_outputs() { return outputs; }
340 virtual float *get_params() { return param_values; }
341 virtual bool activate_preset(int bank, int program) { return false; }
342 virtual float get_param_value(int param_no) {
343 return param_values[param_no];
345 virtual void set_param_value(int param_no, float value) {
346 param_values[param_no] = value;
347 changed = true;
349 virtual void execute(int cmd_no) {
350 Module::execute(cmd_no);
352 virtual char *configure(const char *key, const char *value) {
353 return Module::configure(key, value);
355 virtual void send_configures(send_configure_iface *sci) {
356 Module::send_configures(sci);
360 extern jack_host_base *create_jack_host(const char *name, const std::string &instance_name, calf_plugins::progress_report_iface *priface);
364 #endif
366 #endif