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>
32 namespace calf_plugins
{
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 name
, 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 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);
80 std::string
get_name()
82 return std::string(jack_get_client_name(client
));
87 jack_activate(client
);
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
);
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
{
114 typedef int (*process_func
)(jack_nframes_t nframes
, void *p
);
119 port() : handle(NULL
), data(NULL
) {}
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
) {
137 instance_name
= _instance_name
;
143 void set_params(const float *params
) {
144 memcpy(get_params(), params
, get_param_count() * sizeof(float));
152 void open(jack_client
*_client
);
154 virtual void create_ports();
158 virtual ~jack_host_base() {
164 float level
, falloff
;
172 inline void update(float *src
, unsigned int len
)
175 for (unsigned int i
= 0; i
< len
; i
++)
176 tmp
= std::max(tmp
* falloff
, (double)fabs(src
[i
]));
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
{
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
];
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
] = ¶m_values
[i
];
208 progress_report
= _priface
;
209 Module::post_instantiate();
218 virtual void init_module() {
219 Module::set_sample_rate(client
->sample_rate
);
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
)
229 switch(buffer
[0] >> 4)
232 Module::note_off(buffer
[1], buffer
[2]);
236 Module::note_off(buffer
[1], 0);
238 Module::note_on(buffer
[1], buffer
[2]);
241 Module::control_change(buffer
[1], buffer
[2]);
244 Module::program_change(buffer
[1]);
247 value
= buffer
[1] + 128 * buffer
[2] - 8192;
248 Module::pitch_bend(value
);
252 void process_part(unsigned int time
, unsigned int len
)
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
);
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
);
271 midi_meter
= new_meter
;
273 virtual float get_level(unsigned int port
) {
275 return input_vus
[port
].level
;
277 if (port
< out_count
)
278 return output_vus
[port
].level
;
280 if (port
== 0 && Module::support_midi
)
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
);
292 Module::params_changed();
296 unsigned int time
= 0;
297 if (Module::support_midi
)
299 jack_midi_event_t event
;
301 int count
= jack_midi_get_event_count(midi_port
.data
, nframes
);
303 int count
= jack_midi_get_event_count(midi_port
.data
);
305 for (int i
= 0; i
< count
; i
++)
308 jack_midi_event_get(&event
, midi_port
.data
, i
, nframes
);
310 jack_midi_event_get(&event
, midi_port
.data
, i
);
312 unsigned int len
= event
.time
- time
;
313 process_part(time
, len
);
316 handle_event(event
.buffer
, event
.size
);
321 process_part(time
, nframes
- time
);
322 Module::params_reset();
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
;
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
);