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)
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
21 #ifndef __CALF_JACKHOST_H
22 #define __CALF_JACKHOST_H
36 std::vector
<jack_host_base
*> plugins
;
37 calf_utils::ptmutex mutex
;
39 jack_client_t
*client
;
40 int input_nr
, output_nr
, midi_nr
;
41 std::string input_name
, output_name
, midi_name
;
46 input_nr
= output_nr
= midi_nr
= 1;
47 input_name
= "input_%d";
48 output_name
= "output_%d";
49 midi_name
= "midi_%d";
54 void add(jack_host_base
*plugin
)
56 calf_utils::ptlock
lock(mutex
);
57 plugins
.push_back(plugin
);
62 calf_utils::ptlock
lock(mutex
);
63 plugins
.erase(plugins
.begin()+item
);
66 void open(const char *client_name
)
69 client
= jack_client_open(client_name
, JackNullOption
, &status
);
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
));
84 jack_activate(client
);
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
);
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
{
111 typedef int (*process_func
)(jack_nframes_t nframes
, void *p
);
116 port() : handle(NULL
), data(NULL
) {}
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;
136 void set_params(const float *params
) {
137 memcpy(get_params(), params
, get_param_count() * sizeof(float));
145 void open(jack_client
*_client
)
147 client
= _client
; //jack_client_open(client_name, JackNullOption, &status);
157 virtual void create_ports() {
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");
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");
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
;
199 jack_port_unregister(client
->client
, midi_port
.handle
);
203 virtual ~jack_host_base() {
209 float level
, falloff
;
217 inline void update(float *src
, unsigned int len
)
220 for (unsigned int i
= 0; i
< len
; i
++)
221 tmp
= std::max(tmp
* falloff
, (double)fabs(src
[i
]));
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
{
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
];
246 for (int i
= 0; i
< Module::param_count
; i
++) {
247 param_values
[i
] = Module::param_props
[i
].def_value
;
248 Module::params
[i
] = ¶m_values
[i
];
259 virtual void init_module() {
260 Module::set_sample_rate(client
->sample_rate
);
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
)
270 switch(buffer
[0] >> 4)
273 Module::note_off(buffer
[1], buffer
[2]);
277 Module::note_off(buffer
[1], 0);
279 Module::note_on(buffer
[1], buffer
[2]);
282 Module::program_change(buffer
[1]);
285 Module::control_change(buffer
[1], buffer
[2]);
288 value
= buffer
[1] + 128 * buffer
[2] - 8192;
289 Module::pitch_bend(value
);
293 void process_part(unsigned int time
, unsigned int len
)
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
);
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
);
312 midi_meter
= new_meter
;
314 virtual float get_level(unsigned int port
) {
316 return input_vus
[port
].level
;
318 if (port
< out_count
)
319 return output_vus
[port
].level
;
321 if (port
== 0 && Module::support_midi
)
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
);
333 Module::params_changed();
337 unsigned int time
= 0;
338 if (Module::support_midi
)
340 jack_midi_event_t event
;
342 int count
= jack_midi_get_event_count(midi_port
.data
, nframes
);
344 int count
= jack_midi_get_event_count(midi_port
.data
);
346 for (int i
= 0; i
< count
; i
++)
349 jack_midi_event_get(&event
, midi_port
.data
, i
, nframes
);
351 jack_midi_event_get(&event
, midi_port
.data
, i
);
353 unsigned int len
= event
.time
- time
;
354 process_part(time
, len
);
357 handle_event(event
.buffer
, event
.size
);
362 process_part(time
, nframes
- time
);
363 Module::params_reset();
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
;
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();
437 configure(p
[0], p
[1]);
442 extern jack_host_base
*create_jack_host(const char *name
);