1 /* gnu_javax_sound_midi_dssi_DSSISynthesizer.c - DSSI Synth
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath 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 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 /* The original get_port_default() and set_control() routines were
39 * copied from the DSSI source distribution and are covered by the
40 * following copyright and license...
42 * Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton.
44 * Permission to use, copy, modify, distribute, and sell this software
45 * for any purpose is hereby granted without fee, provided that the
46 * above copyright notice and this permission notice are included in
47 * all copies or substantial portions of the software.
51 #include <gnu_javax_sound_midi_dssi_DSSISynthesizer.h>
54 #include "dssi_data.h"
56 /* Define this for debug output. */
57 #undef DEBUG_DSSI_PROVIDER
59 static void set_control (dssi_data
*data
, snd_seq_event_t
*event
);
63 * The jack callback routine.
65 * This function is called by the jack audio system in its own thread
66 * whenever it needs new audio data.
70 process (jack_nframes_t nframes
, void *arg
)
72 dssi_data
*data
= (dssi_data
*) arg
;
74 jack_default_audio_sample_t
*buffer
;
76 /* Look through the event buffer to see if any control values
78 for ( index
= data
->midiEventReadIndex
;
79 index
!= data
->midiEventWriteIndex
;
80 index
= (index
+ 1) % EVENT_BUFFER_SIZE
)
82 if (data
->midiEventBuffer
[index
].type
== SND_SEQ_EVENT_CONTROLLER
)
83 set_control (data
, & data
->midiEventBuffer
[index
]);
86 if (data
->desc
->run_synth
)
88 /* Call the synth audio processing routine. */
92 &data
->midiEventBuffer
[data
->midiEventReadIndex
],
93 data
->midiEventWriteIndex
- data
->midiEventReadIndex
);
96 if (data
->desc
->run_multiple_synths
)
98 snd_seq_event_t
*events
=
99 &data
->midiEventBuffer
[data
->midiEventReadIndex
];
100 unsigned long event_count
=
101 data
->midiEventWriteIndex
- data
->midiEventReadIndex
;
103 /* Call the synth audio processing routine. */
104 data
->desc
->run_multiple_synths
106 & (data
->plugin_handle
),
112 /* Update the read index on our circular buffer. */
113 data
->midiEventReadIndex
= data
->midiEventWriteIndex
;
115 /* Copy output from the synth to jack.
117 FIXME: This is hack that only gets one channel from the synth and
118 send that to both jack ports (until we handle stero synths
121 FIXME: Can we avoid this copying? */
122 buffer
= jack_port_get_buffer(data
->jack_left_output_port
, nframes
);
123 memcpy (buffer
, data
->left_buffer
, nframes
* sizeof(LADSPA_Data
));
124 buffer
= jack_port_get_buffer(data
->jack_right_output_port
, nframes
);
125 memcpy (buffer
, data
->left_buffer
, nframes
* sizeof(LADSPA_Data
));
132 * Calculate a reasonable default value for a specific control port.
133 * This is mostly copied from the DSSI example code. Copyright info
134 * is found at the top of this file.
138 get_port_default (const LADSPA_Descriptor
*plugin
,
139 int port
, jack_nframes_t sample_rate
)
141 LADSPA_PortRangeHint hint
= plugin
->PortRangeHints
[port
];
142 float lower
= hint
.LowerBound
*
143 (LADSPA_IS_HINT_SAMPLE_RATE(hint
.HintDescriptor
) ? sample_rate
: 1.0f
);
144 float upper
= hint
.UpperBound
*
145 (LADSPA_IS_HINT_SAMPLE_RATE(hint
.HintDescriptor
) ? sample_rate
: 1.0f
);
147 if (!LADSPA_IS_HINT_HAS_DEFAULT(hint
.HintDescriptor
))
149 if (!LADSPA_IS_HINT_BOUNDED_BELOW(hint
.HintDescriptor
) ||
150 !LADSPA_IS_HINT_BOUNDED_ABOVE(hint
.HintDescriptor
))
152 /* No hint, its not bounded, wild guess */
156 if (lower
<= 0.0f
&& upper
>= 0.0f
)
158 /* It spans 0.0, 0.0 is often a good guess */
162 /* No clues, return minimum */
166 /* Try all the easy ones */
168 if (LADSPA_IS_HINT_DEFAULT_0(hint
.HintDescriptor
))
170 else if (LADSPA_IS_HINT_DEFAULT_1(hint
.HintDescriptor
))
172 else if (LADSPA_IS_HINT_DEFAULT_100(hint
.HintDescriptor
))
174 else if (LADSPA_IS_HINT_DEFAULT_440(hint
.HintDescriptor
))
177 /* All the others require some bounds */
179 if (LADSPA_IS_HINT_BOUNDED_BELOW(hint
.HintDescriptor
)
180 && (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint
.HintDescriptor
)))
183 if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint
.HintDescriptor
))
185 if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint
.HintDescriptor
))
188 if (LADSPA_IS_HINT_BOUNDED_BELOW(hint
.HintDescriptor
))
190 if (LADSPA_IS_HINT_DEFAULT_LOW(hint
.HintDescriptor
))
191 return lower
* 0.75f
+ upper
* 0.25f
;
192 else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint
.HintDescriptor
))
193 return lower
* 0.5f
+ upper
* 0.5f
;
194 else if (LADSPA_IS_HINT_DEFAULT_HIGH(hint
.HintDescriptor
))
195 return lower
* 0.25f
+ upper
* 0.75f
;
204 * Set a control value by mapping the MIDI event to a suitable value
206 * This is mostly copied from the DSSI example code. Copyright info
207 * is found at the top of this file.
211 set_control(dssi_data
*data
, snd_seq_event_t
*event
)
213 unsigned control
= event
->data
.control
.param
;
214 unsigned port
= data
->control_port_map
[control
];
216 const LADSPA_Descriptor
*p
= data
->desc
->LADSPA_Plugin
;
218 LADSPA_PortRangeHintDescriptor d
= p
->PortRangeHints
[port
].HintDescriptor
;
220 LADSPA_Data lb
= p
->PortRangeHints
[port
].LowerBound
*
221 (LADSPA_IS_HINT_SAMPLE_RATE(p
->PortRangeHints
[port
].HintDescriptor
) ?
222 data
->sample_rate
: 1.0f
);
224 LADSPA_Data ub
= p
->PortRangeHints
[port
].UpperBound
*
225 (LADSPA_IS_HINT_SAMPLE_RATE(p
->PortRangeHints
[port
].HintDescriptor
) ?
226 data
->sample_rate
: 1.0f
);
228 float value
= (float)event
->data
.control
.value
;
230 if (!LADSPA_IS_HINT_BOUNDED_BELOW(d
))
232 if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d
))
234 /* unbounded: might as well leave the value alone. */
238 /* bounded above only. just shift the range. */
239 value
= ub
- 127.0f
+ value
;
244 if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d
))
246 /* bounded below only. just shift the range. */
251 /* bounded both ends. more interesting. */
252 if (LADSPA_IS_HINT_LOGARITHMIC(d
))
254 const float llb
= logf(lb
);
255 const float lub
= logf(ub
);
257 value
= expf(llb
+ ((lub
- llb
) * value
/ 127.0f
));
261 value
= lb
+ ((ub
- lb
) * value
/ 127.0f
);
266 #ifdef DEBUG_DSSI_PROVIDER
267 printf("MIDI controller %d=%d -> control in %u=%f\n",
268 event
->data
.control
.param
,
269 event
->data
.control
.value
,
270 data
->control_value_map
[control
], value
);
273 data
->control_values
[data
->control_value_map
[control
]] = value
;
277 * Open a new synthesizer. This currently involves instantiating a
278 * new synth, creating a new jack client connection, and activating
282 JNIEXPORT
void JNICALL
283 Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_open_1
284 (JNIEnv
*env
, jclass clazz
__attribute__((unused
)), jlong handle
)
286 unsigned int port_count
, j
, cindex
;
289 dssi_data
*data
= (dssi_data
*) (long) handle
;
290 if ((data
->jack_client
= jack_client_new (data
->desc
->LADSPA_Plugin
->Label
)) == 0)
292 /* JCL_ThrowException (env, "javax/sound/midi/MidiUnavailableException", */
293 JCL_ThrowException (env
, "java/io/IOException",
294 "can't create jack client");
298 /* Get the jack sample rate, which may be used in default control port
299 value calculations. */
300 data
->sample_rate
= jack_get_sample_rate (data
->jack_client
);
302 data
->plugin_handle
=
303 (data
->desc
->LADSPA_Plugin
->instantiate
)(data
->desc
->LADSPA_Plugin
,
306 if (jack_set_process_callback (data
->jack_client
, process
, data
) != 0)
308 JCL_ThrowException (env
, "java/io/IOException",
309 "can't set jack process callback");
313 data
->jack_left_output_port
=
314 jack_port_register (data
->jack_client
, "output_left",
315 JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
316 data
->jack_right_output_port
=
317 jack_port_register (data
->jack_client
, "output_right",
318 JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
320 /* Count the number of controls and audio ouput ports. */
321 port_count
= data
->control_count
= 0;
322 for (j
= 0; j
< data
->desc
->LADSPA_Plugin
->PortCount
; j
++)
324 LADSPA_PortDescriptor pod
=
325 data
->desc
->LADSPA_Plugin
->PortDescriptors
[j
];
327 if (LADSPA_IS_PORT_AUDIO(pod
) && LADSPA_IS_PORT_OUTPUT(pod
))
329 else if (LADSPA_IS_PORT_CONTROL(pod
) && LADSPA_IS_PORT_INPUT(pod
))
330 data
->control_count
++;
333 /* Allocate the array of control values. */
334 data
->control_values
=
335 (LADSPA_Data
*) JCL_malloc (env
,
336 data
->control_count
* sizeof (LADSPA_Data
));
338 /* Initialize the MIDI control map. */
339 memset (data
->control_value_map
, 0, data
->control_count
* sizeof(unsigned));
341 /* Create buffers for each port. */
342 for (cindex
= 0, j
= 0; j
< data
->desc
->LADSPA_Plugin
->PortCount
; j
++)
344 LADSPA_PortDescriptor pod
=
345 data
->desc
->LADSPA_Plugin
->PortDescriptors
[j
];
346 if (LADSPA_IS_PORT_AUDIO(pod
) && LADSPA_IS_PORT_OUTPUT(pod
))
349 (float *) calloc(jack_get_buffer_size(data
->jack_client
),
351 (data
->desc
->LADSPA_Plugin
->connect_port
)(data
->plugin_handle
, j
,
355 if (LADSPA_IS_PORT_CONTROL(pod
) && LADSPA_IS_PORT_INPUT(pod
))
357 /* This is an input control port. Connect it to a properly
358 initialized value in our controller value array. */
359 (data
->desc
->LADSPA_Plugin
->connect_port
)
360 (data
->plugin_handle
, j
, &(data
->control_values
[cindex
]));
361 data
->control_values
[cindex
] =
362 get_port_default (data
->desc
->LADSPA_Plugin
,
363 j
, data
->sample_rate
);
365 /* Set up the mapping between MIDI controllers and this
367 if (data
->desc
->get_midi_controller_for_port
)
369 controller
= data
->desc
->
370 get_midi_controller_for_port(data
->plugin_handle
, j
);
372 if ((controller
!= DSSI_NONE
) && DSSI_IS_CC(controller
))
374 data
->control_value_map
[DSSI_CC_NUMBER(controller
)] = cindex
;
375 data
->control_port_map
[DSSI_CC_NUMBER(controller
)] = j
;
377 #ifdef DEBUG_DSSI_PROVIDER
378 printf ("MIDI Controller 0x%x [%s] = %g\n",
379 DSSI_CC_NUMBER(controller
),
380 data
->desc
->LADSPA_Plugin
->PortNames
[j
],
381 data
->control_values
[cindex
]);
390 (data
->desc
->LADSPA_Plugin
->activate
)(data
->plugin_handle
);
392 if (jack_activate (data
->jack_client
))
393 JCL_ThrowException (env
, "java/io/IOException",
394 "can't activate jack client");
396 /* Try to connect the synth output to hardware audio ports. */
397 ports
= jack_get_ports (data
->jack_client
, NULL
, NULL
,
398 JackPortIsPhysical
| JackPortIsInput
);
401 if (ports
[0] && ports
[1])
403 /* Don't bother checking return values. Failing is OK. */
404 jack_connect (data
->jack_client
,
405 jack_port_name (data
->jack_left_output_port
),
407 jack_connect (data
->jack_client
,
408 jack_port_name (data
->jack_right_output_port
),
416 * This is called when we receive a new MIDI CONTROL CHANGE message.
417 * Simply stick an appropriate event in the event buffer. This will
418 * get processed in the jack callback function.
420 JNIEXPORT
void JNICALL
421 Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_controlChange_1
422 (JNIEnv
*env
__attribute__((unused
)), jclass clazz
__attribute__((unused
)),
423 jlong handle
, jint channel
, jint control
, jint value
)
425 dssi_data
*data
= JLONG_TO_PTR(dssi_data
,handle
);
427 /* Insert this event in the event buffer. */
428 snd_seq_event_t
*ev
= & data
->midiEventBuffer
[data
->midiEventWriteIndex
];
430 /* Set the event value. */
431 snd_seq_ev_set_controller (ev
, channel
, control
, value
);
433 data
->midiEventWriteIndex
=
434 (data
->midiEventWriteIndex
+ 1) % EVENT_BUFFER_SIZE
;
438 * This is called when we receive a new MIDI NOTE ON message. Simply
439 * stick an appropriate event in the event buffer. This will get
440 * processed in the jack callback function.
442 JNIEXPORT
void JNICALL
443 Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_noteOn_1
444 (JNIEnv
*env
__attribute__((unused
)), jclass clazz
__attribute__((unused
)),
445 jlong handle
, jint channel
, jint note
, jint velocity
)
447 dssi_data
*data
= JLONG_TO_PTR(dssi_data
,handle
);
449 /* Insert this event in the event buffer. */
450 snd_seq_event_t
*ev
= & data
->midiEventBuffer
[data
->midiEventWriteIndex
];
452 ev
->type
= SND_SEQ_EVENT_NOTEON
;
453 ev
->data
.control
.channel
= channel
;
454 ev
->data
.note
.note
= note
;
455 ev
->data
.note
.velocity
= velocity
;
457 data
->midiEventWriteIndex
=
458 (data
->midiEventWriteIndex
+ 1) % EVENT_BUFFER_SIZE
;
462 * This is called when we receive a new MIDI NOTE OFF message. Simply
463 * stick an appropriate event in the event buffer. This will get
464 * processed in the jack callback function.
466 JNIEXPORT
void JNICALL
467 Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_noteOff_1
468 (JNIEnv
*env
__attribute__((unused
)),
469 jclass clazz
__attribute__((unused
)),
470 jlong handle
, jint channel
, jint note
, jint velocity
)
472 dssi_data
*data
= JLONG_TO_PTR(dssi_data
,handle
);
474 /* Insert this event in the event buffer. */
475 snd_seq_event_t
*ev
= & data
->midiEventBuffer
[data
->midiEventWriteIndex
];
477 ev
->type
= SND_SEQ_EVENT_NOTEOFF
;
478 ev
->data
.control
.channel
= channel
;
479 ev
->data
.note
.note
= note
;
480 ev
->data
.note
.velocity
= velocity
;
482 data
->midiEventWriteIndex
=
483 (data
->midiEventWriteIndex
+ 1) % EVENT_BUFFER_SIZE
;
486 JNIEXPORT
void JNICALL
487 Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_setPolyPressure_1
488 (JNIEnv
*env
__attribute__((unused
)), jclass clazz
__attribute__((unused
)),
489 jlong handle
__attribute__((unused
)), jint channel
__attribute__((unused
)),
490 jint note
__attribute__((unused
)), jint velocity
__attribute__((unused
)))
494 JNIEXPORT jint JNICALL
495 Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_getPolyPressure_1
496 (JNIEnv
*env
__attribute__((unused
)), jclass clazz
__attribute__((unused
)),
497 jlong handle
__attribute__((unused
)), jint channel
__attribute__((unused
)),
498 jint note
__attribute__((unused
)))
503 JNIEXPORT
void JNICALL
504 Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_close_1
505 (JNIEnv
*env
__attribute__((unused
)), jclass clazz
__attribute__((unused
)),
506 jlong handle
__attribute__((unused
)))
510 /* FIXME: These next three functions are really inefficient because
511 we're instantiating and cleaning up plugin instances just to query
514 JNIEXPORT jstring JNICALL
515 Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_getProgramName_1
516 (JNIEnv
*env
, jclass clazz
__attribute__((unused
)),
517 jlong handle
, jint index
)
519 LADSPA_Handle lhandle
;
520 jstring name
= (jstring
) NULL
;
521 dssi_data
*data
= JLONG_TO_PTR(dssi_data
, handle
);
522 if (data
->desc
->get_program
== NULL
)
525 (data
->desc
->LADSPA_Plugin
->instantiate
)(data
->desc
->LADSPA_Plugin
,
527 const DSSI_Program_Descriptor
*program
=
528 (data
->desc
->get_program
)(lhandle
, (unsigned long) index
);
530 name
= (*env
)->NewStringUTF (env
, program
->Name
);
531 (data
->desc
->LADSPA_Plugin
->cleanup
)(lhandle
);
536 JNIEXPORT jint JNICALL
537 Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_getProgramBank_1
538 (JNIEnv
*env
__attribute__((unused
)), jclass clazz
__attribute__((unused
)),
539 jlong handle
, jint index
)
541 LADSPA_Handle lhandle
;
543 dssi_data
*data
= JLONG_TO_PTR(dssi_data
, handle
);
545 (data
->desc
->LADSPA_Plugin
->instantiate
)(data
->desc
->LADSPA_Plugin
,
547 const DSSI_Program_Descriptor
*program
=
548 (data
->desc
->get_program
)(lhandle
, (unsigned long) index
);
550 result
= (jint
) program
->Bank
;
551 (data
->desc
->LADSPA_Plugin
->cleanup
)(lhandle
);
555 JNIEXPORT jint JNICALL
556 Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_getProgramProgram_1
557 (JNIEnv
*env
__attribute__((unused
)), jclass clazz
__attribute__((unused
)),
558 jlong handle
, jint index
)
560 LADSPA_Handle lhandle
;
562 dssi_data
*data
= JLONG_TO_PTR(dssi_data
, handle
);
564 (data
->desc
->LADSPA_Plugin
->instantiate
)(data
->desc
->LADSPA_Plugin
,
566 const DSSI_Program_Descriptor
*program
=
567 (data
->desc
->get_program
)(lhandle
, (unsigned long) index
);
569 result
= (jint
) program
->Program
;
570 (data
->desc
->LADSPA_Plugin
->cleanup
)(lhandle
);
575 JNIEXPORT
void JNICALL
576 Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_selectProgram_1
577 (JNIEnv
*env
__attribute__((unused
)), jclass clazz
__attribute__((unused
)),
578 jlong handle
, jint bank
, jint program
)
580 dssi_data
*data
= JLONG_TO_PTR(dssi_data
, handle
);
582 (data
->desc
->select_program
)(data
->plugin_handle
,
583 (unsigned) bank
, (unsigned) program
);