Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / classpath / native / jni / midi-dssi / gnu_javax_sound_midi_dssi_DSSISynthesizer.c
blobec1477ec8dbed2ab93bee6d548fb5e83c4549f7c
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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.
50 #include <config.h>
51 #include <gnu_javax_sound_midi_dssi_DSSISynthesizer.h>
52 #include <math.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);
62 /**
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.
69 static int
70 process (jack_nframes_t nframes, void *arg)
72 dssi_data *data = (dssi_data *) arg;
73 int index;
74 jack_default_audio_sample_t *buffer;
76 /* Look through the event buffer to see if any control values
77 need changing. */
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. */
89 data->desc->run_synth
90 (data->plugin_handle,
91 nframes,
92 &data->midiEventBuffer[data->midiEventReadIndex],
93 data->midiEventWriteIndex - data->midiEventReadIndex);
95 else
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),
107 nframes,
108 &events,
109 &event_count);
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
119 properly).
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));
127 return 0;
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.
137 static LADSPA_Data
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 */
153 return 0.0f;
156 if (lower <= 0.0f && upper >= 0.0f)
158 /* It spans 0.0, 0.0 is often a good guess */
159 return 0.0f;
162 /* No clues, return minimum */
163 return lower;
166 /* Try all the easy ones */
168 if (LADSPA_IS_HINT_DEFAULT_0(hint.HintDescriptor))
169 return 0.0f;
170 else if (LADSPA_IS_HINT_DEFAULT_1(hint.HintDescriptor))
171 return 1.0f;
172 else if (LADSPA_IS_HINT_DEFAULT_100(hint.HintDescriptor))
173 return 100.0f;
174 else if (LADSPA_IS_HINT_DEFAULT_440(hint.HintDescriptor))
175 return 440.0f;
177 /* All the others require some bounds */
179 if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)
180 && (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint.HintDescriptor)))
181 return lower;
183 if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor))
185 if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint.HintDescriptor))
186 return upper;
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;
199 /* fallback */
200 return 0.0f;
204 * Set a control value by mapping the MIDI event to a suitable value
205 * for this control.
206 * This is mostly copied from the DSSI example code. Copyright info
207 * is found at the top of this file.
210 static void
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. */
236 else
238 /* bounded above only. just shift the range. */
239 value = ub - 127.0f + value;
242 else
244 if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d))
246 /* bounded below only. just shift the range. */
247 value = lb + value;
249 else
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));
259 else
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);
271 #endif
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
279 * both.
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;
287 const char **ports;
288 int controller = 0;
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");
295 return;
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,
304 data->sample_rate);
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");
310 return;
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))
328 port_count++;
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))
348 data->left_buffer =
349 (float *) calloc(jack_get_buffer_size(data->jack_client),
350 sizeof(float));
351 (data->desc->LADSPA_Plugin->connect_port)(data->plugin_handle, j,
352 data->left_buffer);
354 else
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
366 contoller value. */
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]);
382 #endif
386 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);
399 if (ports)
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),
406 ports[0]);
407 jack_connect (data->jack_client,
408 jack_port_name (data->jack_right_output_port),
409 ports[1]);
411 free(ports);
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)))
500 return 0;
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
512 values. */
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)
523 return NULL;
524 lhandle =
525 (data->desc->LADSPA_Plugin->instantiate)(data->desc->LADSPA_Plugin,
526 48000);
527 const DSSI_Program_Descriptor *program =
528 (data->desc->get_program)(lhandle, (unsigned long) index);
529 if (program)
530 name = (*env)->NewStringUTF (env, program->Name);
531 (data->desc->LADSPA_Plugin->cleanup)(lhandle);
533 return name;
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;
542 jint result = -1;
543 dssi_data *data = JLONG_TO_PTR(dssi_data, handle);
544 lhandle =
545 (data->desc->LADSPA_Plugin->instantiate)(data->desc->LADSPA_Plugin,
546 48000);
547 const DSSI_Program_Descriptor *program =
548 (data->desc->get_program)(lhandle, (unsigned long) index);
549 if (program)
550 result = (jint) program->Bank;
551 (data->desc->LADSPA_Plugin->cleanup)(lhandle);
552 return result;
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;
561 jint result = -1;
562 dssi_data *data = JLONG_TO_PTR(dssi_data, handle);
563 lhandle =
564 (data->desc->LADSPA_Plugin->instantiate)(data->desc->LADSPA_Plugin,
565 48000);
566 const DSSI_Program_Descriptor *program =
567 (data->desc->get_program)(lhandle, (unsigned long) index);
568 if (program)
569 result = (jint) program->Program;
570 (data->desc->LADSPA_Plugin->cleanup)(lhandle);
571 return result;
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);