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
26 #include <jack/jack.h>
27 #include <jack/midiport.h>
38 std::vector
<jack_host_base
*> plugins
;
39 calf_utils::ptmutex mutex
;
41 jack_client_t
*client
;
42 int input_nr
, output_nr
, midi_nr
;
43 std::string input_name
, output_name
, midi_name
;
48 input_nr
= output_nr
= midi_nr
= 1;
49 input_name
= "input_%d";
50 output_name
= "output_%d";
51 midi_name
= "midi_%d";
56 void add(jack_host_base
*plugin
)
58 calf_utils::ptlock
lock(mutex
);
59 plugins
.push_back(plugin
);
64 calf_utils::ptlock
lock(mutex
);
65 plugins
.erase(plugins
.begin()+item
);
68 void open(const char *client_name
)
71 client
= jack_client_open(client_name
, JackNullOption
, &status
);
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
));
86 jack_activate(client
);
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
);
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
{
113 typedef int (*process_func
)(jack_nframes_t nframes
, void *p
);
118 port() : handle(NULL
), data(NULL
) {}
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;
138 void set_params(const float *params
) {
139 memcpy(get_params(), params
, get_param_count() * sizeof(float));
147 void open(jack_client
*_client
)
149 client
= _client
; //jack_client_open(client_name, JackNullOption, &status);
159 virtual void create_ports() {
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");
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");
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
;
201 jack_port_unregister(client
->client
, midi_port
.handle
);
205 virtual ~jack_host_base() {
211 float level
, falloff
;
219 inline void update(float *src
, unsigned int len
)
222 for (unsigned int i
= 0; i
< len
; i
++)
223 tmp
= std::max(tmp
* falloff
, (double)fabs(src
[i
]));
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
{
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
];
248 for (int i
= 0; i
< Module::param_count
; i
++) {
249 param_values
[i
] = Module::param_props
[i
].def_value
;
250 Module::params
[i
] = ¶m_values
[i
];
261 virtual void init_module() {
262 Module::set_sample_rate(client
->sample_rate
);
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
)
272 switch(buffer
[0] >> 4)
275 Module::note_off(buffer
[1], buffer
[2]);
279 Module::note_off(buffer
[1], 0);
281 Module::note_on(buffer
[1], buffer
[2]);
284 Module::program_change(buffer
[1]);
287 Module::control_change(buffer
[1], buffer
[2]);
290 value
= buffer
[1] + 128 * buffer
[2] - 8192;
291 Module::pitch_bend(value
);
295 void process_part(unsigned int time
, unsigned int len
)
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
);
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
);
314 midi_meter
= new_meter
;
316 virtual float get_level(unsigned int port
) {
318 return input_vus
[port
].level
;
320 if (port
< out_count
)
321 return output_vus
[port
].level
;
323 if (port
== 0 && Module::support_midi
)
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
);
335 Module::params_changed();
339 unsigned int time
= 0;
340 if (Module::support_midi
)
342 jack_midi_event_t event
;
344 int count
= jack_midi_get_event_count(midi_port
.data
, nframes
);
346 int count
= jack_midi_get_event_count(midi_port
.data
);
348 for (int i
= 0; i
< count
; i
++)
351 jack_midi_event_get(&event
, midi_port
.data
, i
, nframes
);
353 jack_midi_event_get(&event
, midi_port
.data
, i
);
355 unsigned int len
= event
.time
- time
;
356 process_part(time
, len
);
359 handle_event(event
.buffer
, event
.size
);
364 process_part(time
, nframes
- time
);
365 Module::params_reset();
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
;
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
);