I'm about to check in the following patch collection, most of which I've already posted to the list for comment.
Thanks, AG 2005-10-06 Anthony Green <[EMAIL PROTECTED]> * INSTALL: Describe midi provider dependencies. * native/jni/midi-dssi/README: New file. * LICENSE (terms): Add notice about code copied from the DSSI distribution. * examples/gnu/classpath/examples/midi/Demo.java: New file. * native/jni/midi-dssi/dssi_data.h (dssi_data): Add control_count, control_port_map, control_value_map, sample_rate, and control_values fields. * native/jni/midi-dssi/gnu_javax_sound_midi_dssi_DSSISynthesizer.c (DEBUG_DSSI_PROVIDER): New macro. (get_port_default): New function. (set_control): New function. (Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_open_1): Remove debug output. Reformat. Allocate the control ports and assign proper default values. (Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_noteOn_1): Use JLONG_TO_PTR. (Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_noteOff_1): Ditto. * gnu/javax/sound/midi/dssi/DSSISynthesizer.java (Channel.controlChange): Implement. (controlChange_): New native method. * include/gnu_javax_sound_midi_dssi_DSSISynthesizer.h: Rebuilt. * gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java: Make instance final. Index: LICENSE =================================================================== RCS file: /cvsroot/classpath/classpath/LICENSE,v retrieving revision 1.7 diff -u -r1.7 LICENSE --- LICENSE 2 Jul 2005 20:32:07 -0000 1.7 +++ LICENSE 7 Oct 2005 02:47:11 -0000 @@ -284,3 +284,17 @@ shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. + + +The file native/jni/midi-dssi/gnu_javax_sound_midi_dssi_DSSISynthesizer.c +contains two functions (get_port_default and set_control) derived from +example code in the DSSI distribution (http://dssi.sourceforge.net). +The original DSSI example code is distributed under the following +terms: + + Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. + + Permission to use, copy, modify, distribute, and sell this software + for any purpose is hereby granted without fee, provided that the + above copyright notice and this permission notice are included in + all copies or substantial portions of the software. Index: gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java,v retrieving revision 1.1 diff -u -r1.1 AlsaMidiSequencerDevice.java --- gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java 3 Oct 2005 01:53:12 -0000 1.1 +++ gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java 7 Oct 2005 02:47:12 -0000 @@ -64,7 +64,7 @@ public class AlsaMidiSequencerDevice implements Sequencer { // The singleton instance. - public static AlsaMidiSequencerDevice instance = new AlsaMidiSequencerDevice(); + public final static AlsaMidiSequencerDevice instance = new AlsaMidiSequencerDevice(); // A pointer to a native chunk of memory private long nativeState; Index: gnu/javax/sound/midi/dssi/DSSISynthesizer.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/javax/sound/midi/dssi/DSSISynthesizer.java,v retrieving revision 1.1 diff -u -r1.1 DSSISynthesizer.java --- gnu/javax/sound/midi/dssi/DSSISynthesizer.java 3 Oct 2005 01:53:12 -0000 1.1 +++ gnu/javax/sound/midi/dssi/DSSISynthesizer.java 7 Oct 2005 02:47:12 -0000 @@ -85,6 +85,10 @@ else channels[smessage.getChannel()].noteOff(smessage.getData1()); break; + case ShortMessage.CONTROL_CHANGE: + channels[smessage.getChannel()].controlChange(smessage.getData1(), + smessage.getData2()); + break; default: System.out.println ("Unhandled message: " + message.getStatus()); break; @@ -106,6 +110,7 @@ static native void noteOff_(long handle, int channel, int noteNumber, int velocity); static native void setPolyPressure_(long handle, int channel, int noteNumber, int pressure); static native int getPolyPressure_(long handle, int channel, int noteNumber); + static native void controlChange_(long handle, int channel, int control, int value); static native void open_(long handle); static native void close_(long handle); @@ -184,13 +189,10 @@ return 0; } - /* (non-Javadoc) - * @see javax.sound.midi.MidiChannel#controlChange(int, int) - */ + /* @see javax.sound.midi.MidiChannel#controlChange(int, int) */ public void controlChange(int controller, int value) { - // TODO Auto-generated method stub - + controlChange_(sohandle, channel, controller, value); } /* (non-Javadoc) Index: include/gnu_javax_sound_midi_dssi_DSSISynthesizer.h =================================================================== RCS file: /cvsroot/classpath/classpath/include/gnu_javax_sound_midi_dssi_DSSISynthesizer.h,v retrieving revision 1.1 diff -u -r1.1 gnu_javax_sound_midi_dssi_DSSISynthesizer.h --- include/gnu_javax_sound_midi_dssi_DSSISynthesizer.h 3 Oct 2005 01:53:12 -0000 1.1 +++ include/gnu_javax_sound_midi_dssi_DSSISynthesizer.h 7 Oct 2005 02:47:12 -0000 @@ -14,6 +14,7 @@ JNIEXPORT void JNICALL Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_noteOff_1 (JNIEnv *env, jclass, jlong, jint, jint, jint); JNIEXPORT void JNICALL Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_setPolyPressure_1 (JNIEnv *env, jclass, jlong, jint, jint, jint); JNIEXPORT jint JNICALL Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_getPolyPressure_1 (JNIEnv *env, jclass, jlong, jint, jint); +JNIEXPORT void JNICALL Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_controlChange_1 (JNIEnv *env, jclass, jlong, jint, jint, jint); JNIEXPORT void JNICALL Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_open_1 (JNIEnv *env, jclass, jlong); JNIEXPORT void JNICALL Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_close_1 (JNIEnv *env, jclass, jlong); Index: native/jni/midi-dssi/dssi_data.h =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/midi-dssi/dssi_data.h,v retrieving revision 1.2 diff -u -r1.2 dssi_data.h --- native/jni/midi-dssi/dssi_data.h 4 Oct 2005 12:24:08 -0000 1.2 +++ native/jni/midi-dssi/dssi_data.h 7 Oct 2005 02:47:14 -0000 @@ -100,5 +100,22 @@ float *left_buffer; float *right_buffer; + /* The number of input controls for this synth. */ + unsigned control_count; + + /* An array of control values, control_count in length. */ + LADSPA_Data *control_values; + + /* A mapping of MIDI controllers to control values. There are a + maximum of 128 MIDI controllers. */ + unsigned control_value_map[128]; + + /* A mapping of MIDI controllers to LADSPA ports. There are a + maximum of 128 MIDI controllers. */ + unsigned control_port_map[128]; + + /* The sample rate. */ + jack_nframes_t sample_rate; + } dssi_data; Index: native/jni/midi-dssi/gnu_javax_sound_midi_dssi_DSSISynthesizer.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/midi-dssi/gnu_javax_sound_midi_dssi_DSSISynthesizer.c,v retrieving revision 1.2 diff -u -r1.2 gnu_javax_sound_midi_dssi_DSSISynthesizer.c --- native/jni/midi-dssi/gnu_javax_sound_midi_dssi_DSSISynthesizer.c 4 Oct 2005 12:24:08 -0000 1.2 +++ native/jni/midi-dssi/gnu_javax_sound_midi_dssi_DSSISynthesizer.c 7 Oct 2005 02:47:14 -0000 @@ -35,11 +35,30 @@ obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ +/* The original get_port_default() and set_control() routines were + * copied from the DSSI source distribution and are covered by the + * following copyright and license... + * + * Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. + * + * Permission to use, copy, modify, distribute, and sell this software + * for any purpose is hereby granted without fee, provided that the + * above copyright notice and this permission notice are included in + * all copies or substantial portions of the software. + */ + #include <config.h> #include <gnu_javax_sound_midi_dssi_DSSISynthesizer.h> +#include <math.h> #include "dssi_data.h" +/* Define this for debug output. */ +#undef DEBUG_DSSI_PROVIDER + +static void set_control (dssi_data *data, snd_seq_event_t *event); + + /** * The jack callback routine. * @@ -50,15 +69,19 @@ static int process (jack_nframes_t nframes, void *arg) { - struct timeval tv; dssi_data *data = (dssi_data *) arg; int index; jack_default_audio_sample_t *buffer; - /* Look through the event buffer to see if anything needs doing. */ + /* Look through the event buffer to see if any control values + need changing. */ for ( index = data->midiEventReadIndex; index != data->midiEventWriteIndex; - index = (index + 1) % EVENT_BUFFER_SIZE); + index = (index + 1) % EVENT_BUFFER_SIZE) + { + if (data->midiEventBuffer[index].type == SND_SEQ_EVENT_CONTROLLER) + set_control (data, & data->midiEventBuffer[index]); + } /* Call the synth audio processing routine. */ data->desc->run_synth(data->plugin_handle, @@ -84,8 +107,151 @@ return 0; } -/* FIXME: Temporary hack. */ -float mctrl = 0.9f; + +/** + * Calculate a reasonable default value for a specific control port. + * This is mostly copied from the DSSI example code. Copyright info + * is found at the top of this file. + * + */ +static LADSPA_Data +get_port_default (const LADSPA_Descriptor *plugin, + int port, jack_nframes_t sample_rate) +{ + LADSPA_PortRangeHint hint = plugin->PortRangeHints[port]; + float lower = hint.LowerBound * + (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor) ? sample_rate : 1.0f); + float upper = hint.UpperBound * + (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor) ? sample_rate : 1.0f); + + if (!LADSPA_IS_HINT_HAS_DEFAULT(hint.HintDescriptor)) + { + if (!LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) || + !LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) + { + /* No hint, its not bounded, wild guess */ + return 0.0f; + } + + if (lower <= 0.0f && upper >= 0.0f) + { + /* It spans 0.0, 0.0 is often a good guess */ + return 0.0f; + } + + /* No clues, return minimum */ + return lower; + } + + /* Try all the easy ones */ + + if (LADSPA_IS_HINT_DEFAULT_0(hint.HintDescriptor)) + return 0.0f; + else if (LADSPA_IS_HINT_DEFAULT_1(hint.HintDescriptor)) + return 1.0f; + else if (LADSPA_IS_HINT_DEFAULT_100(hint.HintDescriptor)) + return 100.0f; + else if (LADSPA_IS_HINT_DEFAULT_440(hint.HintDescriptor)) + return 440.0f; + + /* All the others require some bounds */ + + if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) + && (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint.HintDescriptor))) + return lower; + + if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) + { + if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint.HintDescriptor)) + return upper; + + if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) + { + if (LADSPA_IS_HINT_DEFAULT_LOW(hint.HintDescriptor)) + return lower * 0.75f + upper * 0.25f; + else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint.HintDescriptor)) + return lower * 0.5f + upper * 0.5f; + else if (LADSPA_IS_HINT_DEFAULT_HIGH(hint.HintDescriptor)) + return lower * 0.25f + upper * 0.75f; + } + } + + /* fallback */ + return 0.0f; +} + +/** + * Set a control value by mapping the MIDI event to a suitable value + * for this control. + * This is mostly copied from the DSSI example code. Copyright info + * is found at the top of this file. + * + */ +static void +set_control(dssi_data *data, snd_seq_event_t *event) +{ + unsigned control = event->data.control.param; + unsigned port = data->control_port_map[control]; + + const LADSPA_Descriptor *p = data->desc->LADSPA_Plugin; + + LADSPA_PortRangeHintDescriptor d = p->PortRangeHints[port].HintDescriptor; + + LADSPA_Data lb = p->PortRangeHints[port].LowerBound * + (LADSPA_IS_HINT_SAMPLE_RATE(p->PortRangeHints[port].HintDescriptor) ? + data->sample_rate : 1.0f); + + LADSPA_Data ub = p->PortRangeHints[port].UpperBound * + (LADSPA_IS_HINT_SAMPLE_RATE(p->PortRangeHints[port].HintDescriptor) ? + data->sample_rate : 1.0f); + + float value = (float)event->data.control.value; + + if (!LADSPA_IS_HINT_BOUNDED_BELOW(d)) + { + if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) + { + /* unbounded: might as well leave the value alone. */ + } + else + { + /* bounded above only. just shift the range. */ + value = ub - 127.0f + value; + } + } + else + { + if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) + { + /* bounded below only. just shift the range. */ + value = lb + value; + } + else + { + /* bounded both ends. more interesting. */ + if (LADSPA_IS_HINT_LOGARITHMIC(d)) + { + const float llb = logf(lb); + const float lub = logf(ub); + + value = expf(llb + ((lub - llb) * value / 127.0f)); + } + else + { + value = lb + ((ub - lb) * value / 127.0f); + } + } + } + +#ifdef DEBUG_DSSI_PROVIDER + printf("MIDI controller %d=%d -> control in %u=%f\n", + event->data.control.param, + event->data.control.value, + data->control_value_map[control], value); +#endif + + data->control_values[data->control_value_map[control]] = value; +} /** * Open a new synthesizer. This currently involves instantiating a @@ -97,7 +263,7 @@ Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_open_1 (JNIEnv *env, jclass clazz __attribute__((unused)), jlong handle) { - unsigned int port_count, j; + unsigned int port_count, j, cindex, controller = 0; dssi_data *data = (dssi_data *) (long) handle; if ((data->jack_client = jack_client_new (data->desc->LADSPA_Plugin->Label)) == 0) { @@ -106,9 +272,14 @@ "can't create jack client"); return; } + + /* Get the jack sample rate, which may be used in default control port + value calculations. */ + data->sample_rate = jack_get_sample_rate (data->jack_client); - data->plugin_handle = (data->desc->LADSPA_Plugin->instantiate)(data->desc->LADSPA_Plugin, - jack_get_sample_rate (data->jack_client)); + data->plugin_handle = + (data->desc->LADSPA_Plugin->instantiate)(data->desc->LADSPA_Plugin, + data->sample_rate); if (jack_set_process_callback (data->jack_client, process, data) != 0) { @@ -123,9 +294,9 @@ data->jack_right_output_port = jack_port_register (data->jack_client, "output_right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - - /* Count the number of output audio ports. */ - port_count = 0; + + /* Count the number of controls and audio ouput ports. */ + port_count = data->control_count = 0; for (j = 0; j < data->desc->LADSPA_Plugin->PortCount; j++) { LADSPA_PortDescriptor pod = @@ -133,11 +304,20 @@ if (LADSPA_IS_PORT_AUDIO(pod) && LADSPA_IS_PORT_OUTPUT(pod)) port_count++; + else if (LADSPA_IS_PORT_CONTROL(pod) && LADSPA_IS_PORT_INPUT(pod)) + data->control_count++; } - printf ("LADSPA output ports = %d\n", port_count); + + /* Allocate the array of control values. */ + data->control_values = + (LADSPA_Data *) JCL_malloc (env, + data->control_count * sizeof (LADSPA_Data)); + + /* Initialize the MIDI control map. */ + memset (data->control_value_map, 0, data->control_count * sizeof(unsigned)); /* Create buffers for each port. */ - for (j = 0; j < data->desc->LADSPA_Plugin->PortCount; j++) + for (cindex = 0, j = 0; j < data->desc->LADSPA_Plugin->PortCount; j++) { LADSPA_PortDescriptor pod = data->desc->LADSPA_Plugin->PortDescriptors[j]; @@ -152,11 +332,39 @@ else if (LADSPA_IS_PORT_CONTROL(pod) && LADSPA_IS_PORT_INPUT(pod)) { + /* This is an input control port. Connect it to a properly + initialized value in our controller value array. */ (data->desc->LADSPA_Plugin->connect_port) - (data->plugin_handle, j, &mctrl); + (data->plugin_handle, j, &(data->control_values[cindex])); + data->control_values[cindex] = + get_port_default (data->desc->LADSPA_Plugin, + j, data->sample_rate); + + /* Set up the mapping between MIDI controllers and this + contoller value. */ + if (data->desc->get_midi_controller_for_port) + { + controller = data->desc-> + get_midi_controller_for_port(data->plugin_handle, j); + + if (DSSI_IS_CC(controller)) + { + data->control_value_map[DSSI_CC_NUMBER(controller)] = cindex; + data->control_port_map[DSSI_CC_NUMBER(controller)] = j; + } + } + +#ifdef DEBUG_DSSI_PROVIDER + printf ("MIDI Controller 0x%x [%s] = %g\n", + DSSI_CC_NUMBER(controller), + data->desc->LADSPA_Plugin->PortNames[j], + data->control_values[cindex]); +#endif + + cindex++; } } - + (data->desc->LADSPA_Plugin->activate)(data->plugin_handle); if (jack_activate (data->jack_client)) @@ -165,6 +373,28 @@ } /** + * This is called when we receive a new MIDI CONTROL CHANGE message. + * Simply stick an appropriate event in the event buffer. This will + * get processed in the jack callback function. + */ +JNIEXPORT void JNICALL +Java_gnu_javax_sound_midi_dssi_DSSISynthesizer_controlChange_1 + (JNIEnv *env __attribute__((unused)), jclass clazz __attribute__((unused)), + jlong handle, jint channel, jint control, jint value) +{ + dssi_data *data = JLONG_TO_PTR(dssi_data,handle); + + /* Insert this event in the event buffer. */ + snd_seq_event_t *ev = & data->midiEventBuffer[data->midiEventWriteIndex]; + + /* Set the event value. */ + snd_seq_ev_set_controller (ev, channel, control, value); + + data->midiEventWriteIndex = + (data->midiEventWriteIndex + 1) % EVENT_BUFFER_SIZE; +} + +/** * This is called when we receive a new MIDI NOTE ON message. Simply * stick an appropriate event in the event buffer. This will get * processed in the jack callback function. @@ -174,7 +404,7 @@ (JNIEnv *env __attribute__((unused)), jclass clazz __attribute__((unused)), jlong handle, jint channel, jint note, jint velocity) { - dssi_data *data = (dssi_data *) (long) handle; + dssi_data *data = JLONG_TO_PTR(dssi_data,handle); /* Insert this event in the event buffer. */ snd_seq_event_t *ev = & data->midiEventBuffer[data->midiEventWriteIndex]; @@ -199,7 +429,7 @@ jclass clazz __attribute__((unused)), jlong handle, jint channel, jint note, jint velocity) { - dssi_data *data = (dssi_data *) (long) handle; + dssi_data *data = JLONG_TO_PTR(dssi_data,handle); /* Insert this event in the event buffer. */ snd_seq_event_t *ev = & data->midiEventBuffer[data->midiEventWriteIndex]; Index: examples/gnu/classpath/examples/midi/Demo.java =================================================================== RCS file: examples/gnu/classpath/examples/midi/Demo.java diff -N examples/gnu/classpath/examples/midi/Demo.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ examples/gnu/classpath/examples/midi/Demo.java 7 Oct 2005 02:52:07 -0000 @@ -0,0 +1,137 @@ +/* Demo.java -- And example of MIDI support + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath examples. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. */ + +package gnu.classpath.examples.midi; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.sound.midi.*; + +/** + * An example how javax.sound.midi facilities work. + */ +public class Demo extends Frame implements ItemListener +{ + Choice midiInChoice = new Choice(); + Choice midiOutChoice = new Choice(); + + MidiDevice inDevice = null; + MidiDevice outDevice = null; + + ArrayList inDevices = new ArrayList(); + ArrayList outDevices = new ArrayList(); + + public Demo () throws Exception + { + MenuBar mb = new MenuBar (); + Menu menu = new Menu ("File"); + MenuItem quit = new MenuItem("Quit", new MenuShortcut('Q')); + quit.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + System.exit(0); + } + }); + menu.add (quit); + mb.add(menu); + + setTitle("synthcity: the GNU Classpath MIDI Demo"); + setLayout(new FlowLayout()); + + MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); + + for (int i = 0; i < infos.length; i++) + { + MidiDevice device = MidiSystem.getMidiDevice(infos[i]); + if (device.getMaxReceivers() > 0) + { + midiOutChoice.addItem(infos[i].getDescription()); + outDevices.add(device); + } + if (device.getMaxTransmitters() > 0) + { + midiInChoice.addItem(infos[i].getDescription()); + inDevices.add(device); + } + } + + setMenuBar (mb); + add(new Label("MIDI IN: ")); + add(midiInChoice); + add(new Label(" MIDI OUT: ")); + add(midiOutChoice); + + midiInChoice.addItemListener(this); + midiOutChoice.addItemListener(this); + + pack(); + show(); + } + + public void itemStateChanged (ItemEvent e) + { + try + { + if (e.getItemSelectable() == midiInChoice) + { + if (inDevice != null) + inDevice.close(); + inDevice = (MidiDevice) + inDevices.get(midiInChoice.getSelectedIndex()); + } + + if (e.getItemSelectable() == midiOutChoice) + { + if (outDevice != null) + outDevice.close(); + outDevice = (MidiDevice) + outDevices.get(midiOutChoice.getSelectedIndex()); + } + + if (inDevice != null && outDevice != null) + { + if (! inDevice.isOpen()) + inDevice.open(); + if (! outDevice.isOpen()) + outDevice.open(); + Transmitter t = inDevice.getTransmitter(); + if (t == null) + System.err.println (inDevice + ".getTransmitter() == null"); + Receiver r = outDevice.getReceiver(); + if (r == null) + System.err.println (outDevice + ".getReceiver() == null"); + + if (t != null && r != null) + t.setReceiver (r); + } + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + + public static void main (String args[]) throws Exception + { + new Demo(); + } +} Index: native/jni/midi-dssi/README =================================================================== RCS file: native/jni/midi-dssi/README diff -N native/jni/midi-dssi/README --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ native/jni/midi-dssi/README 7 Oct 2005 02:52:07 -0000 @@ -0,0 +1,134 @@ +The file native/jni/midi-dssi/gnu_javax_sound_midi_dssi_DSSISynthesizer.c +contains two functions (get_port_default and set_control) derived from +example code in the DSSI distribution (http://dssi.sourceforge.net). +The original DSSI example code is distributed under the following +terms: + + Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. + + Permission to use, copy, modify, distribute, and sell this software + for any purpose is hereby granted without fee, provided that the + above copyright notice and this permission notice are included in + all copies or substantial portions of the software. + + +The rest of this file contain the original versions of these +functions. + + +LADSPA_Data get_port_default(const LADSPA_Descriptor *plugin, int port) +{ + LADSPA_PortRangeHint hint = plugin->PortRangeHints[port]; + float lower = hint.LowerBound * + (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor) ? sample_rate : 1.0f); + float upper = hint.UpperBound * + (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor) ? sample_rate : 1.0f); + + if (!LADSPA_IS_HINT_HAS_DEFAULT(hint.HintDescriptor)) { + if (!LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) || + !LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) { + /* No hint, its not bounded, wild guess */ + return 0.0f; + } + + if (lower <= 0.0f && upper >= 0.0f) { + /* It spans 0.0, 0.0 is often a good guess */ + return 0.0f; + } + + /* No clues, return minimum */ + return lower; + } + + /* Try all the easy ones */ + + if (LADSPA_IS_HINT_DEFAULT_0(hint.HintDescriptor)) { + return 0.0f; + } else if (LADSPA_IS_HINT_DEFAULT_1(hint.HintDescriptor)) { + return 1.0f; + } else if (LADSPA_IS_HINT_DEFAULT_100(hint.HintDescriptor)) { + return 100.0f; + } else if (LADSPA_IS_HINT_DEFAULT_440(hint.HintDescriptor)) { + return 440.0f; + } + + /* All the others require some bounds */ + + if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) { + if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint.HintDescriptor)) { + return lower; + } + } + if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) { + if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint.HintDescriptor)) { + return upper; + } + if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) { + if (LADSPA_IS_HINT_DEFAULT_LOW(hint.HintDescriptor)) { + return lower * 0.75f + upper * 0.25f; + } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint.HintDescriptor)) { + return lower * 0.5f + upper * 0.5f; + } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hint.HintDescriptor)) { + return lower * 0.25f + upper * 0.75f; + } + } + } + + /* fallback */ + return 0.0f; +} + + +void +setControl(d3h_instance_t *instance, long controlIn, snd_seq_event_t *event) +{ + long port = pluginControlInPortNumbers[controlIn]; + + const LADSPA_Descriptor *p = instance->plugin->descriptor->LADSPA_Plugin; + + LADSPA_PortRangeHintDescriptor d = p->PortRangeHints[port].HintDescriptor; + + LADSPA_Data lb = p->PortRangeHints[port].LowerBound * + (LADSPA_IS_HINT_SAMPLE_RATE(p->PortRangeHints[port].HintDescriptor) ? + sample_rate : 1.0f); + + LADSPA_Data ub = p->PortRangeHints[port].UpperBound * + (LADSPA_IS_HINT_SAMPLE_RATE(p->PortRangeHints[port].HintDescriptor) ? + sample_rate : 1.0f); + + float value = (float)event->data.control.value; + + if (!LADSPA_IS_HINT_BOUNDED_BELOW(d)) { + if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) { + /* unbounded: might as well leave the value alone. */ + } else { + /* bounded above only. just shift the range. */ + value = ub - 127.0f + value; + } + } else { + if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) { + /* bounded below only. just shift the range. */ + value = lb + value; + } else { + /* bounded both ends. more interesting. */ + if (LADSPA_IS_HINT_LOGARITHMIC(d)) { + const float llb = logf(lb); + const float lub = logf(ub); + + value = expf(llb + ((lub - llb) * value / 127.0f)); + } else { + value = lb + ((ub - lb) * value / 127.0f); + } + } + } + + if (verbose) { + printf("%s: %s MIDI controller %d=%d -> control in %ld=%f\n", myName, + instance->friendly_name, event->data.control.param, + event->data.control.value, controlIn, value); + } + + pluginControlIns[controlIn] = value; + pluginPortUpdated[controlIn] = 1; +} + Index: INSTALL =================================================================== RCS file: /cvsroot/classpath/classpath/INSTALL,v retrieving revision 1.32 diff -u -r1.32 INSTALL --- INSTALL 6 Sep 2005 23:01:55 -0000 1.32 +++ INSTALL 7 Oct 2005 03:14:06 -0000 @@ -79,6 +79,29 @@ - texinfo 4.2 or higher. + For building the ALSA midi provider code you will need + ALSA. http://www.alsa-project.org. + + For building the DSSI midi synthesizer provider code you will + need DSSI from http://dssi.sourceforge.net. This, in turn, + introduces many dependencies, including: + + - liblo: the Lightweight OSC implementation + http://plugin.org.uk/liblo/ + + - LADSPA: Linux Audio Developer's Simple Plugin API + http://www.ladspa.org + + - the JACK Audio Connection Kit: A low latency audio server + http://jackit.sourceforge.net + + - libsndfile: an audio file I/O library + http://www.mega-nerd.com/libsndfile/ + + - fluidsynth: a real-time SoundFont 2 based soft-synth + http://www.fluidsynth.org/ + + This package was designed to use the GNU standard for configuration and makefiles. To build and install do the following: _______________________________________________ Classpath-patches mailing list Classpath-patches@gnu.org http://lists.gnu.org/mailman/listinfo/classpath-patches