mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-04-19 06:02:03 +00:00
Fixed Jack driver in "audio.jack.multi=yes" mode.
This mode allows multiple audio outputs, typically one for each MIDI input channel. It was unavailable while using audio feedback callback, for instance in QSynth when peak level meters were enabled. This has been fixed by Bernat, and backported from the FluidSynth-2.x branch (ticket #21, changeset 154)
This commit is contained in:
parent
b49458e817
commit
5b4387e332
2 changed files with 49 additions and 267 deletions
|
@ -53,24 +53,18 @@
|
|||
*/
|
||||
typedef struct {
|
||||
fluid_audio_driver_t driver;
|
||||
fluid_synth_t* synth;
|
||||
jack_client_t *client;
|
||||
int audio_channels;
|
||||
int effects_channels;
|
||||
jack_port_t **output_ports;
|
||||
int num_output_ports;
|
||||
float **output_bufs;
|
||||
jack_port_t **fx_ports;
|
||||
int num_fx_ports;
|
||||
float **fx_bufs;
|
||||
jack_port_t **input_ports;
|
||||
int num_input_ports;
|
||||
float **input_bufs;
|
||||
fluid_audio_func_t callback;
|
||||
void* data;
|
||||
} fluid_jack_audio_driver_t;
|
||||
|
||||
|
||||
fluid_audio_driver_t*
|
||||
new_fluid_jack_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, void* data);
|
||||
int delete_fluid_jack_audio_driver(fluid_audio_driver_t* p);
|
||||
void fluid_jack_audio_driver_shutdown(void *arg);
|
||||
int fluid_jack_audio_driver_srate(jack_nframes_t nframes, void *arg);
|
||||
|
@ -93,6 +87,11 @@ fluid_jack_audio_driver_settings(fluid_settings_t* settings)
|
|||
fluid_audio_driver_t*
|
||||
new_fluid_jack_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
||||
{
|
||||
return new_fluid_jack_audio_driver2(settings, NULL, synth);
|
||||
}
|
||||
|
||||
fluid_audio_driver_t*
|
||||
new_fluid_jack_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, void* data) {
|
||||
fluid_jack_audio_driver_t* dev = NULL;
|
||||
char name[64];
|
||||
int i, audio_count, fx_count;
|
||||
|
@ -110,7 +109,8 @@ new_fluid_jack_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
|||
}
|
||||
FLUID_MEMSET(dev, 0, sizeof(fluid_jack_audio_driver_t));
|
||||
|
||||
dev->synth = synth;
|
||||
dev->callback = func;
|
||||
dev->data = data;
|
||||
|
||||
/* try to become a client of the JACK server */
|
||||
|
||||
|
@ -152,15 +152,16 @@ new_fluid_jack_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
|||
if (!fluid_settings_str_equal(settings, "audio.jack.multi", "yes")) {
|
||||
|
||||
/* create the two audio output ports */
|
||||
dev->num_output_ports = 2;
|
||||
dev->num_output_ports = 1;
|
||||
|
||||
dev->output_ports = FLUID_ARRAY(jack_port_t*, dev->num_output_ports);
|
||||
dev->output_ports = FLUID_ARRAY(jack_port_t*, 2 * dev->num_output_ports);
|
||||
if (dev->output_ports == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Jack server not running?");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(dev->output_ports, 0, dev->num_output_ports * sizeof(jack_port_t*));
|
||||
dev->output_bufs = FLUID_ARRAY(float*, 2 * dev->num_output_ports);
|
||||
FLUID_MEMSET(dev->output_ports, 0, 2 * dev->num_output_ports * sizeof(jack_port_t*));
|
||||
|
||||
dev->output_ports[0] = jack_port_register(dev->client, "left",
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
|
@ -171,7 +172,7 @@ new_fluid_jack_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
|||
JackPortIsOutput, 0);
|
||||
} else {
|
||||
|
||||
dev->num_output_ports = fluid_synth_count_audio_channels(synth);
|
||||
fluid_settings_getint(settings, "synth.audio-channels", &dev->num_output_ports);
|
||||
|
||||
dev->output_ports = FLUID_ARRAY(jack_port_t*, 2 * dev->num_output_ports);
|
||||
if (dev->output_ports == NULL) {
|
||||
|
@ -199,33 +200,6 @@ new_fluid_jack_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
|||
JackPortIsOutput, 0);
|
||||
}
|
||||
|
||||
dev->num_fx_ports = fluid_synth_count_effects_channels(synth);
|
||||
|
||||
dev->fx_ports = FLUID_ARRAY(jack_port_t*, 2 * dev->num_fx_ports);
|
||||
if (dev->fx_ports == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
dev->fx_bufs = FLUID_ARRAY(float*, 2 * dev->num_fx_ports);
|
||||
if (dev->fx_bufs == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(dev->fx_ports, 0, 2 * dev->num_fx_ports * sizeof(jack_port_t*));
|
||||
|
||||
for (i = 0; i < dev->num_fx_ports; i++) {
|
||||
sprintf(name, "fxl_%02d", i);
|
||||
dev->fx_ports[2 * i] = jack_port_register(dev->client, name,
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsOutput, 0);
|
||||
|
||||
sprintf(name, "fxr_%02d", i);
|
||||
dev->fx_ports[2 * i + 1] = jack_port_register(dev->client, name,
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsOutput, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* tell the JACK server that we are ready to roll */
|
||||
|
@ -258,10 +232,8 @@ new_fluid_jack_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
|||
int err;
|
||||
int connected = 0;
|
||||
|
||||
for (i = 0; jack_ports[i] && (connected < 2); ++i) {
|
||||
err = jack_connect (dev->client, jack_port_name
|
||||
(connected == 0 ? dev->output_ports[0]
|
||||
: dev->output_ports[1]), jack_ports[i]);
|
||||
for (i = 0; jack_ports[i] && i<2 * dev->num_output_ports; ++i) {
|
||||
err = jack_connect (dev->client, jack_port_name(dev->output_ports[i]), jack_ports[i]);
|
||||
if (err) {
|
||||
FLUID_LOG(FLUID_ERR, "Error connecting jack port");
|
||||
} else {
|
||||
|
@ -283,181 +255,6 @@ new_fluid_jack_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
fluid_audio_driver_t*
|
||||
new_fluid_jack_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, void* data)
|
||||
{
|
||||
fluid_jack_audio_driver_t* dev = NULL;
|
||||
char name[64];
|
||||
int i, audio_count, fx_count;
|
||||
/* for looking up ports */
|
||||
const char ** jack_ports;
|
||||
char* client_name;
|
||||
int nin, nout;
|
||||
int autoconnect = 0;
|
||||
|
||||
|
||||
dev = FLUID_NEW(fluid_jack_audio_driver_t);
|
||||
if (dev == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
FLUID_MEMSET(dev, 0, sizeof(fluid_jack_audio_driver_t));
|
||||
|
||||
|
||||
dev->callback = func;
|
||||
dev->data = data;
|
||||
|
||||
/* try to become a client of the JACK server */
|
||||
|
||||
if (fluid_settings_getstr(settings, "audio.jack.id", &client_name)
|
||||
&& (client_name != NULL)
|
||||
&& (strlen(client_name) > 0)) {
|
||||
snprintf(name, 64, "%s", client_name);
|
||||
} else {
|
||||
snprintf(name, 64, "fluidsynth");
|
||||
}
|
||||
|
||||
if ((dev->client = jack_client_new(name)) == 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Jack server not running?");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
/* set callbacks */
|
||||
jack_set_process_callback(dev->client, fluid_jack_audio_driver_process2, (void*) dev);
|
||||
jack_set_buffer_size_callback(dev->client, fluid_jack_audio_driver_bufsize, (void*) dev);
|
||||
jack_set_sample_rate_callback(dev->client, fluid_jack_audio_driver_srate, (void*) dev);
|
||||
jack_on_shutdown(dev->client, fluid_jack_audio_driver_shutdown, (void*) dev);
|
||||
|
||||
/* display the current sample rate. once the client is activated
|
||||
(see below), you should rely on your own sample rate
|
||||
callback (see above) for this value.
|
||||
*/
|
||||
FLUID_LOG(FLUID_DBG, "Jack engine sample rate: %lu", jack_get_sample_rate(dev->client));
|
||||
|
||||
fluid_settings_getint(settings, "audio.output-channels", &dev->num_output_ports);
|
||||
fluid_settings_getint(settings, "audio.input-channels", &dev->num_input_ports);
|
||||
|
||||
/* create output ports */
|
||||
if (dev->num_output_ports > 0) {
|
||||
dev->output_ports = FLUID_ARRAY(jack_port_t*, dev->num_output_ports);
|
||||
if (dev->output_ports == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
dev->output_bufs = FLUID_ARRAY(float*, dev->num_output_ports);
|
||||
if (dev->output_bufs == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
for (i = 0; i < dev->num_output_ports; i++) {
|
||||
sprintf(name, "out_%02d", i);
|
||||
dev->output_ports[i] = jack_port_register(dev->client, name,
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsOutput, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* create input ports */
|
||||
if (dev->num_input_ports > 0) {
|
||||
dev->input_ports = FLUID_ARRAY(jack_port_t*, dev->num_input_ports);
|
||||
if (dev->input_ports == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
dev->input_bufs = FLUID_ARRAY(float*, dev->num_input_ports);
|
||||
if (dev->input_bufs == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
for (i = 0; i < dev->num_input_ports; i++) {
|
||||
sprintf(name, "in_%02d", i);
|
||||
dev->input_ports[i] = jack_port_register(dev->client, name,
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsInput, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* effects are not used */
|
||||
dev->num_fx_ports = 0;
|
||||
dev->fx_ports = NULL;
|
||||
dev->fx_bufs = NULL;
|
||||
|
||||
/* tell the JACK server that we are ready to roll */
|
||||
if (jack_activate(dev->client)) {
|
||||
FLUID_LOG(FLUID_ERR, "Cannot activate the fluidsynth as a JACK client");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
/* connect the ports. */
|
||||
|
||||
|
||||
/* FIXME: should be done by a patchbay application */
|
||||
|
||||
/* find some physical ports and connect to them */
|
||||
fluid_settings_getint (settings, "audio.jack.autoconnect", &autoconnect);
|
||||
if (autoconnect) {
|
||||
if (dev->num_output_ports > 0) {
|
||||
jack_ports = jack_get_ports(dev->client, NULL, NULL, JackPortIsInput|JackPortIsPhysical);
|
||||
if (jack_ports) {
|
||||
int err;
|
||||
int connected = 0;
|
||||
|
||||
for (i = 0; jack_ports[i] && (connected < dev->num_output_ports); ++i) {
|
||||
err = jack_connect (dev->client,
|
||||
jack_port_name(dev->output_ports[i]),
|
||||
jack_ports[i]);
|
||||
if (err) {
|
||||
FLUID_LOG(FLUID_ERR, "Error connecting jack port");
|
||||
} else {
|
||||
connected++;
|
||||
}
|
||||
}
|
||||
|
||||
free (jack_ports); /* free the jack port array */
|
||||
} else {
|
||||
FLUID_LOG(FLUID_WARN, "Could not connect to any physical jack ports; "
|
||||
"fluidsynth is unconnected");
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->num_input_ports > 0) {
|
||||
jack_ports = jack_get_ports(dev->client, NULL, NULL, JackPortIsOutput|JackPortIsPhysical);
|
||||
if (jack_ports) {
|
||||
int err;
|
||||
int connected = 0;
|
||||
|
||||
for (i = 0; jack_ports[i] && (connected < dev->num_input_ports); ++i) {
|
||||
err = jack_connect (dev->client,
|
||||
jack_ports[i],
|
||||
jack_port_name(dev->input_ports[i]));
|
||||
if (err) {
|
||||
FLUID_LOG(FLUID_ERR, "Error connecting jack port");
|
||||
} else {
|
||||
connected++;
|
||||
}
|
||||
}
|
||||
|
||||
free (jack_ports); /* free the jack port array */
|
||||
|
||||
}
|
||||
} else {
|
||||
FLUID_LOG(FLUID_WARN, "Could not connect to any physical jack ports; "
|
||||
"fluidsynth is unconnected");
|
||||
}
|
||||
}
|
||||
|
||||
return (fluid_audio_driver_t*) dev;
|
||||
|
||||
error_recovery:
|
||||
|
||||
delete_fluid_jack_audio_driver((fluid_audio_driver_t*) dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* delete_fluid_jack_audio_driver
|
||||
*/
|
||||
|
@ -483,14 +280,6 @@ delete_fluid_jack_audio_driver(fluid_audio_driver_t* p)
|
|||
FLUID_FREE(dev->output_ports);
|
||||
}
|
||||
|
||||
if (dev->fx_bufs) {
|
||||
FLUID_FREE(dev->fx_bufs);
|
||||
}
|
||||
|
||||
if (dev->fx_ports) {
|
||||
FLUID_FREE(dev->fx_ports);
|
||||
}
|
||||
|
||||
FLUID_FREE(dev);
|
||||
return 0;
|
||||
}
|
||||
|
@ -501,14 +290,23 @@ fluid_jack_audio_driver_process(jack_nframes_t nframes, void *arg)
|
|||
{
|
||||
fluid_jack_audio_driver_t* dev = (fluid_jack_audio_driver_t*) arg;
|
||||
|
||||
if (dev->fx_ports == NULL) {
|
||||
if (dev->callback!=NULL) {
|
||||
int i;
|
||||
for (i = 0; i < dev->num_output_ports*2; i++) {
|
||||
dev->output_bufs[i] = (float*) jack_port_get_buffer(dev->output_ports[i], nframes);
|
||||
}
|
||||
return (*dev->callback)(dev->data, nframes,
|
||||
0, NULL, 2 * dev->num_output_ports, dev->output_bufs);
|
||||
}
|
||||
|
||||
if (dev->num_output_ports == 1) {
|
||||
float *left;
|
||||
float *right;
|
||||
|
||||
left = (float*) jack_port_get_buffer(dev->output_ports[0], nframes);
|
||||
right = (float*) jack_port_get_buffer(dev->output_ports[1], nframes);
|
||||
|
||||
fluid_synth_write_float(dev->synth, nframes, left, 0, 1, right, 0, 1);
|
||||
fluid_synth_write_float(dev->data, nframes, left, 0, 1, right, 0, 1);
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -518,39 +316,16 @@ fluid_jack_audio_driver_process(jack_nframes_t nframes, void *arg)
|
|||
dev->output_bufs[i] = (float*) jack_port_get_buffer(dev->output_ports[2*i], nframes);
|
||||
dev->output_bufs[k] = (float*) jack_port_get_buffer(dev->output_ports[2*i+1], nframes);
|
||||
}
|
||||
for (i = 0, k = dev->num_fx_ports; i < dev->num_fx_ports; i++, k++) {
|
||||
dev->fx_bufs[i] = (float*) jack_port_get_buffer(dev->fx_ports[2*i], nframes);
|
||||
dev->fx_bufs[k] = (float*) jack_port_get_buffer(dev->fx_ports[2*i+1], nframes);
|
||||
}
|
||||
|
||||
fluid_synth_nwrite_float(dev->synth, nframes,
|
||||
fluid_synth_nwrite_float(dev->data, nframes,
|
||||
dev->output_bufs,
|
||||
dev->output_bufs + dev->num_output_ports,
|
||||
dev->fx_bufs,
|
||||
dev->fx_bufs + dev->num_fx_ports);
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fluid_jack_audio_driver_process2(jack_nframes_t nframes, void *arg)
|
||||
{
|
||||
fluid_jack_audio_driver_t* dev = (fluid_jack_audio_driver_t*) arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dev->num_output_ports; i++) {
|
||||
dev->output_bufs[i] = (float*) jack_port_get_buffer(dev->output_ports[i], nframes);
|
||||
}
|
||||
for (i = 0; i < dev->num_input_ports; i++) {
|
||||
dev->input_bufs[i] = (float*) jack_port_get_buffer(dev->input_ports[i], nframes);
|
||||
}
|
||||
|
||||
return (*dev->callback)(dev->data, nframes,
|
||||
dev->num_input_ports, dev->input_bufs,
|
||||
dev->num_output_ports, dev->output_bufs);
|
||||
}
|
||||
|
||||
int
|
||||
fluid_jack_audio_driver_bufsize(jack_nframes_t nframes, void *arg)
|
||||
{
|
||||
|
|
|
@ -1600,13 +1600,11 @@ void fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
|
|||
*/
|
||||
int
|
||||
fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
|
||||
float** left, float** right,
|
||||
float** fx_left, float** fx_right)
|
||||
float** left, float** right,
|
||||
float** fx_left, float** fx_right)
|
||||
{
|
||||
fluid_real_t** left_in = synth->left_buf;
|
||||
fluid_real_t** right_in = synth->right_buf;
|
||||
fluid_real_t** fx_left_in = synth->fx_left_buf;
|
||||
fluid_real_t** fx_right_in = synth->fx_right_buf;
|
||||
double time = fluid_utime();
|
||||
int i, num, available, count, bytes;
|
||||
|
||||
|
@ -1628,10 +1626,6 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
|
|||
FLUID_MEMCPY(left[i], left_in[i] + synth->cur, bytes);
|
||||
FLUID_MEMCPY(right[i], right_in[i] + synth->cur, bytes);
|
||||
}
|
||||
for (i = 0; i < synth->effects_channels; i++) {
|
||||
FLUID_MEMCPY(fx_left[i], fx_left_in[i] + synth->cur, bytes);
|
||||
FLUID_MEMCPY(fx_right[i], fx_right_in[i] + synth->cur, bytes);
|
||||
}
|
||||
count += num;
|
||||
num += synth->cur; /* if we're now done, num becomes the new synth->cur below */
|
||||
}
|
||||
|
@ -1647,10 +1641,6 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
|
|||
FLUID_MEMCPY(left[i] + count, left_in[i], bytes);
|
||||
FLUID_MEMCPY(right[i] + count, right_in[i], bytes);
|
||||
}
|
||||
for (i = 0; i < synth->effects_channels; i++) {
|
||||
FLUID_MEMCPY(fx_left[i] + count, fx_left_in[i], bytes);
|
||||
FLUID_MEMCPY(fx_right[i] + count, fx_right_in[i], bytes);
|
||||
}
|
||||
|
||||
count += num;
|
||||
}
|
||||
|
@ -1666,11 +1656,28 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int fluid_synth_process(fluid_synth_t* synth, int len,
|
||||
int nin, float** in,
|
||||
int nout, float** out)
|
||||
{
|
||||
return fluid_synth_write_float(synth, len, out[0], 0, 1, out[1], 0, 1);
|
||||
if (nout==2) {
|
||||
return fluid_synth_write_float(synth, len, out[0], 0, 1, out[1], 0, 1);
|
||||
}
|
||||
else {
|
||||
float **left, **right;
|
||||
int i;
|
||||
left = FLUID_ARRAY(float*, nout/2);
|
||||
right = FLUID_ARRAY(float*, nout/2);
|
||||
for(i=0; i<nout/2; i++) {
|
||||
left[i] = out[2*i];
|
||||
right[i] = out[2*i+1];
|
||||
}
|
||||
fluid_synth_nwrite_float(synth, len, left, right, NULL, NULL);
|
||||
FLUID_FREE(left);
|
||||
FLUID_FREE(right);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue