|
8 | 8 | package org.puredata.android.midi; |
9 | 9 |
|
10 | 10 | import org.puredata.core.PdMidiReceiver; |
11 | | - |
12 | | -import com.noisepages.nettoyeur.midi.MidiReceiver; |
| 11 | +import android.media.midi.MidiInputPort; |
| 12 | +import java.util.Map; |
| 13 | +import java.util.HashMap; |
| 14 | +import java.util.Map.Entry; |
13 | 15 |
|
14 | 16 | /** |
15 | 17 | * Adapter class for connecting MIDI output from Pd to input for AndroidMidi. |
16 | 18 | * |
17 | 19 | * @author Peter Brinkmann ([email protected]) |
| 20 | + * @author Antoine Rousseau ([email protected]) |
18 | 21 | */ |
19 | 22 | public class PdToMidiAdapter implements PdMidiReceiver { |
| 23 | + private Map<Integer, MidiInputPort> inputPorts = new HashMap<Integer, MidiInputPort>(); |
20 | 24 |
|
21 | | - private final MidiReceiver receiver; |
22 | | - |
23 | | - /** |
24 | | - * Constructor. Note that instances of this class still need to be installed with |
25 | | - * PdBase.setMidiReceiver. |
26 | | - * |
27 | | - * @param receiver to forward MIDI messages to |
28 | | - */ |
29 | | - public PdToMidiAdapter(MidiReceiver receiver) { |
30 | | - this.receiver = receiver; |
31 | | - } |
32 | | - |
| 25 | +/** |
| 26 | + * Send Midi messages from Pd to a Midi device |
| 27 | + * @param inputPort input port of the Midi ouput device, as returned by MidiDevice.openInputPort() |
| 28 | + * @param pdPort starting at 0; Midi messages received from Pd whose channel is between |
| 29 | + * (16 * pdPort) and (16 * pdPort + 15) will be sent to the device with the channel reduced by (16 * pdPort) |
| 30 | + * <br><br> |
| 31 | + * Example code: |
| 32 | + * <pre>{@code |
| 33 | +MidiManager midiManager = (MidiManager) getSystemService(MIDI_SERVICE); |
| 34 | +final MidiDeviceInfo[] infos = midiManager.getDevices(); |
| 35 | +if (infos.length == 0) return; |
| 36 | +final MidiDeviceInfo info = infos[0]; // Select the first available device |
| 37 | +midiManager.openDevice(info, new MidiManager.OnDeviceOpenedListener() { |
33 | 38 | @Override |
34 | | - public void receiveProgramChange(int channel, int value) { |
35 | | - receiver.onProgramChange(channel, value); |
| 39 | + public void onDeviceOpened(MidiDevice device) { |
| 40 | + if (device == null) return; |
| 41 | + for (MidiDeviceInfo.PortInfo portInfo : device.getInfo().getPorts()) { |
| 42 | + if (portInfo.getType() == MidiDeviceInfo.PortInfo.TYPE_INPUT) { |
| 43 | + MidiInputPort inputPort = device.openInputPort(portInfo.getPortNumber()); |
| 44 | + if (inputPort != null) { |
| 45 | + pdToMidiAdapter.open(inputPort, 0); // Map the device to Pd Midi port 0 (channel 0-15) |
| 46 | + break; // Only connect to the first available input port |
| 47 | + } |
| 48 | + } |
| 49 | + } |
36 | 50 | } |
37 | | - |
38 | | - @Override |
39 | | - public void receivePolyAftertouch(int channel, int pitch, int value) { |
40 | | - receiver.onPolyAftertouch(channel, pitch, value); |
| 51 | +} |
| 52 | + * }</pre> |
| 53 | + */ |
| 54 | + public void open(MidiInputPort inputPort, int pdPort) { |
| 55 | + close(inputPort); |
| 56 | + close(pdPort); |
| 57 | + inputPorts.put(pdPort, inputPort); |
41 | 58 | } |
42 | | - |
43 | | - @Override |
44 | | - public void receivePitchBend(int channel, int value) { |
45 | | - receiver.onPitchBend(channel, value); |
| 59 | + |
| 60 | +/** |
| 61 | + * Close the connection to a device port |
| 62 | + * @param inputPort input port of the Midi ouput device, that needs to be closed |
| 63 | + */ |
| 64 | + public void close(MidiInputPort inputPort) { |
| 65 | + if(! inputPorts.containsValue(inputPort)) return; |
| 66 | + for (Entry<Integer, MidiInputPort> entry : inputPorts.entrySet()) { |
| 67 | + if (entry.getValue().equals(inputPort)) { |
| 68 | + close(entry.getKey()); |
| 69 | + } |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | +/** |
| 74 | + * Close the connection from a Pd Midi port |
| 75 | + * @param pdPort starting at 0; Midi messages coming from Pd for this port will be ignored, and the associated MidiInputPort will be closed |
| 76 | + */ |
| 77 | + public void close(int pdPort) { |
| 78 | + MidiInputPort inputPort = inputPorts.get(pdPort); |
| 79 | + if(inputPort != null) { |
| 80 | + try { |
| 81 | + inputPort.close(); |
| 82 | + } catch(Exception e) {} |
| 83 | + inputPorts.remove(pdPort); |
| 84 | + } |
46 | 85 | } |
47 | | - |
| 86 | + |
| 87 | +/** @hidden to javadoc*/ |
48 | 88 | @Override |
49 | 89 | public void receiveNoteOn(int channel, int pitch, int velocity) { |
50 | | - receiver.onNoteOn(channel, pitch, velocity); |
| 90 | + write(0x90, channel, pitch, velocity); |
51 | 91 | } |
52 | | - |
| 92 | + |
| 93 | +/** @hidden to javadoc*/ |
53 | 94 | @Override |
54 | | - public void receiveMidiByte(int port, int value) { |
55 | | - receiver.onRawByte((byte) value); |
| 95 | + public void receivePolyAftertouch(int channel, int pitch, int value) { |
| 96 | + write(0xa0, channel, pitch, value); |
56 | 97 | } |
57 | | - |
| 98 | + |
| 99 | +/** @hidden to javadoc*/ |
58 | 100 | @Override |
59 | 101 | public void receiveControlChange(int channel, int controller, int value) { |
60 | | - receiver.onControlChange(channel, controller, value); |
| 102 | + write(0xb0, channel, controller, value); |
61 | 103 | } |
62 | | - |
| 104 | + |
| 105 | +/** @hidden to javadoc*/ |
| 106 | + @Override |
| 107 | + public void receiveProgramChange(int channel, int program) { |
| 108 | + write(0xc0, channel, program); |
| 109 | + } |
| 110 | + |
| 111 | +/** @hidden to javadoc*/ |
63 | 112 | @Override |
64 | 113 | public void receiveAftertouch(int channel, int value) { |
65 | | - receiver.onAftertouch(channel, value); |
| 114 | + write(0xd0, channel, value); |
| 115 | + } |
| 116 | + |
| 117 | +/** @hidden to javadoc*/ |
| 118 | + @Override |
| 119 | + public void receivePitchBend(int channel, int value) { |
| 120 | + value += 8192; |
| 121 | + write(0xe0, channel, (value & 0x7f), (value >> 7)); |
| 122 | + } |
| 123 | + |
| 124 | +/** @hidden to javadoc*/ |
| 125 | + @Override |
| 126 | + public void receiveMidiByte(int port, int value) { |
| 127 | + final byte[] message = {(byte) value}; |
| 128 | + writeMessage(port, message); |
| 129 | + } |
| 130 | + |
| 131 | + private static byte firstByte(int msg, int ch) { |
| 132 | + return (byte) (msg | (ch & 0x0f)); |
| 133 | + } |
| 134 | + |
| 135 | + private void write(int msg, int ch, int a) { |
| 136 | + final byte[] message = {firstByte(msg, ch), (byte) a}; |
| 137 | + writeMessage(ch, message); |
| 138 | + } |
| 139 | + |
| 140 | + private void write(int msg, int ch, int a, int b) { |
| 141 | + final byte[] message = {firstByte(msg, ch), (byte) a, (byte) b}; |
| 142 | + writeMessage(ch, message); |
| 143 | + } |
| 144 | + |
| 145 | + private void writeMessage(int channel, byte[] message) { |
| 146 | + MidiInputPort inputPort = inputPorts.get(channel / 16); |
| 147 | + if(inputPort != null) try { |
| 148 | + inputPort.send(message, 0, message.length); |
| 149 | + } catch(Exception e) {} |
66 | 150 | } |
67 | 151 |
|
| 152 | +/** @hidden to javadoc*/ |
68 | 153 | @Override |
69 | 154 | public boolean beginBlock() { |
70 | | - return receiver.beginBlock(); |
| 155 | + return false; |
71 | 156 | } |
72 | 157 |
|
| 158 | +/** @hidden to javadoc*/ |
73 | 159 | @Override |
74 | 160 | public void endBlock() { |
75 | | - receiver.endBlock(); |
76 | 161 | } |
77 | 162 | } |
0 commit comments