diff options
Diffstat (limited to 'portmidi/pm_java')
| -rw-r--r-- | portmidi/pm_java/CMakeLists.txt | 56 | ||||
| -rw-r--r-- | portmidi/pm_java/README.txt | 62 | ||||
| -rw-r--r-- | portmidi/pm_java/jportmidi/JPortMidi.java | 541 | ||||
| -rw-r--r-- | portmidi/pm_java/jportmidi/JPortMidiApi.java | 117 | ||||
| -rw-r--r-- | portmidi/pm_java/jportmidi/JPortMidiException.java | 12 | ||||
| -rw-r--r-- | portmidi/pm_java/make.bat | 50 | ||||
| -rw-r--r-- | portmidi/pm_java/pmjni/jportmidi_JportMidiApi.h | 293 | ||||
| -rw-r--r-- | portmidi/pm_java/pmjni/pmjni.c | 354 | ||||
| -rw-r--r-- | portmidi/pm_java/pmjni/pmjni.rc | 63 |
9 files changed, 1548 insertions, 0 deletions
diff --git a/portmidi/pm_java/CMakeLists.txt b/portmidi/pm_java/CMakeLists.txt new file mode 100644 index 0000000..55a20f4 --- /dev/null +++ b/portmidi/pm_java/CMakeLists.txt @@ -0,0 +1,56 @@ +# pm_java/CMakeLists.txt -- builds pmjni + +find_package(Java) +message(STATUS "Java_JAVA_EXECUTABLE is " ${Java_JAVA_EXECUTABLE}) + +# Build pmjni +# this CMakeLists.txt is only loaded if BUILD_JAVA_NATIVE_INTERFACE +# This jni library includes portmidi sources to give just +# one library for JPortMidi users to manage rather than two. +if(UNIX) + include(FindJNI) + # message(STATUS "JAVA_JVM_LIB_PATH is " ${JAVA_JVM_LIB_PATH}) + # message(STATUS "JAVA_INCLUDE_PATH is " ${JAVA_INCLUDE_PATH}) + # note: should use JAVA_JVM_LIB_PATH, but it is not set properly + # note: user might need to set JAVA_INCLUDE_PATH manually + # + # this will probably break on BSD and other Unix systems; the fix + # depends on whether FindJNI can find Java or not. If yes, then + # we should try to rely on automatically set JAVA_INCLUDE_PATH and + # JAVA_INCLUDE_PATH2; if no, then we need to make both JAVA_INCLUDE_PATH + # and JAVA_INCLUDE_PATH2 set by user (will need clear documentation + # because JAVA_INCLUDE_PATH2 is pretty obscure) + set(JAVA_INCLUDE_PATH ${JAVA_INCLUDE_PATH-UNKNOWN} + CACHE STRING "where to find Java SDK include directory") + # libjvm.so is found relative to JAVA_INCLUDE_PATH: + if (HAIKU) + set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH}/haiku) + else() + set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH}/linux) + endif() +elseif(WIN32) + include(FindJNI) + # note: should use JAVA_JVM_LIB_PATH, but it is not set properly + set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../lib/jvm.lib) + + set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) + # message(STATUS "JAVA_INCLUDE_PATHS: " ${JAVA_INCLUDE_PATHS}) + # message(STATUS "JAVAVM_LIB: " ${JAVAVM_LIB}) +endif() + +add_library(pmjni SHARED pmjni/pmjni.c) +target_sources(pmjni PRIVATE ${PM_LIB_PUBLIC_SRC} ${PM_LIB_PRIVATE_SRC}) +message(STATUS "Java paths ${JAVA_INCLUDE_PATHS}") +# message(STATUS "Java pmjni src: pmjni/pmjni.c ${PM_LIB_SHARED_SRC} " +# "${PM_LIB_PRIVATE_SRC}") +target_include_directories(pmjni PUBLIC ${JAVA_INCLUDE_PATHS}) +target_link_libraries(pmjni ${PM_NEEDED_LIBS}) +set_target_properties(pmjni PROPERTIES + VERSION ${LIBRARY_VERSION} + SOVERSION ${LIBRARY_SOVERSION} + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" + EXECUTABLE_EXTENSION "jnilib" + MACOSX_RPATH ON) + diff --git a/portmidi/pm_java/README.txt b/portmidi/pm_java/README.txt new file mode 100644 index 0000000..d1e5ad5 --- /dev/null +++ b/portmidi/pm_java/README.txt @@ -0,0 +1,62 @@ +README.txt
+Roger B. Dannenberg
+16 Jun 2009
+updated 2021
+
+This directory implements a JNI library so that Java programs can use
+the PortMidi API. This was mainly created to implement PmDefaults, a
+program to set default input and output devices for PortMidi
+applications. Because it is rarely used, PmDefaults was dropped from
+PortMidi starting with v3. I recommend you implement per-application
+preferences and store default PortMidi device numbers for input and
+output there. (Or better yet, store device *names* since numbers can
+change if you plug in or remove USB devices.)
+
+Even without PmDefaults, a PortMidi API for Java is probably an
+improvement over other Java libraries, but there is very little MIDI
+development in Java, so I have not maintained this API. The only thing
+probably seriously wrong now is an interface to the
+Pm_CreateVirtualInput and Pm_CreateVirtualOutput functions, which are
+new additions.
+
+I will leave the code here, and if there is a demand, please either
+update it or let your needs be known. Perhaps I or someone can help.
+
+==================================================================
+
+BUILDING Java EXTERNAL LIBRARY
+
+You must have a JDK installed (Java development kit including javac
+(the Java compiler), jni.h, etc.
+
+Test java on the command line, e.g., type: javac -version
+
+Enable these options in the main CMakeLists.txt file (run CMake
+from your top-level repository directory):
+ BUILD_JAVA_NATIVE_INTERFACE
+In my Ubuntu linux with jdk-15, ccmake was unable to find my JDK, so
+I have to manually set CMake variables as follows (type 't' to see
+these in ccmake):
+ JAVA_AWT_INCLUDE_PATH /usr/lib/jvm/jdk-15/include
+ JAVA_AWT_LIBRARY /usr/lib/jvm/jdk-15/lib
+ JAVA_INCLUDE_PATH /usr/lib/jvm/jdk-15/include
+ JAVA_INCLUDE_PATH2 /usr/lib/jvm/jdk-15/include
+ JAVA_JVM_LIBRARY /usr/lib/jvm/jdk-15/lib
+Of course, your paths may differ.
+
+
+---- old implementation notes ----
+
+For Windows, we use the free software JavaExe.exe. The copy here was
+downloaded from
+
+http://software.techrepublic.com.com/abstract.aspx?kw=javaexe&docid=767485
+
+I found this page by visiting http://software.techrepublic.com.com and
+searching in the "Software" category for "JavaExe"
+
+JavaExe works by placing the JavaExe.exe file in the directory with the
+Java application jar file and then *renaming* JavaExe.exe to the name
+of the jar file, but keeping the .exe extension. (See make.bat for this
+step.) Documentation for JavaExe can be obtained by downloading the
+whole program from the URL(s) above.
diff --git a/portmidi/pm_java/jportmidi/JPortMidi.java b/portmidi/pm_java/jportmidi/JPortMidi.java new file mode 100644 index 0000000..7116e19 --- /dev/null +++ b/portmidi/pm_java/jportmidi/JPortMidi.java @@ -0,0 +1,541 @@ +package jportmidi; + +/* PortMidi is a general class intended for any Java program using + the PortMidi library. It encapsulates JPortMidiApi with a more + object-oriented interface. A single PortMidi object can manage + up to one input stream and one output stream. + + This class is not safely callable from multiple threads. It + is the client's responsibility to periodically call the Poll + method which checks for midi input and handles it. +*/ + +import jportmidi.*; +import jportmidi.JPortMidiApi.*; + +public class JPortMidi { + + // timecode to send message immediately + public final int NOW = 0; + + // midi codes + public final int MIDI_NOTE_OFF = 0x80; + public final int MIDI_NOTE_ON = 0x90; + public final int CTRL_ALL_OFF = 123; + public final int MIDI_PITCH_BEND = 0xE0; + public final int MIDI_CLOCK = 0xF8; + public final int MIDI_CONTROL = 0xB0; + public final int MIDI_PROGRAM = 0xC0; + public final int MIDI_START = 0xFA; + public final int MIDI_STOP = 0xFC; + public final int MIDI_POLY_TOUCH = 0xA0; + public final int MIDI_TOUCH = 0xD0; + + // error code -- cannot refresh device list while stream is open: + public final int pmStreamOpen = -5000; + public final int pmOutputNotOpen = -4999; + + // access to JPortMidiApi is through a single, global instance + private static JPortMidiApi pm; + // a reference count tracks how many objects have it open + private static int pmRefCount = 0; + private static int openCount = 0; + + public int error; // user can check here for error codes + private PortMidiStream input; + private PortMidiStream output; + private PmEvent buffer; + protected int timestamp; // remember timestamp from incoming messages + protected boolean trace = false; // used to print midi msgs for debugging + + + public JPortMidi() throws JPortMidiException { + if (pmRefCount == 0) { + pm = new JPortMidiApi(); + pmRefCount++; + System.out.println("Calling Pm_Initialize"); + checkError(pm.Pm_Initialize()); + System.out.println("Called Pm_Initialize"); + } + buffer = new PmEvent(); + } + + public boolean getTrace() { return trace; } + + // set the trace flag and return previous value + public boolean setTrace(boolean flag) { + boolean previous = trace; + trace = flag; + return previous; + } + + // WARNING: you must not call this if any devices are open + public void refreshDeviceLists() + throws JPortMidiException + { + if (openCount > 0) { + throw new JPortMidiException(pmStreamOpen, + "RefreshDeviceLists called while stream is open"); + } + if (trace) System.out.println("Pm_Terminate"); + checkError(pm.Pm_Terminate()); + if (trace) System.out.println("Pm_Initialize"); + checkError(pm.Pm_Initialize()); + } + + // there is no control over when/whether this is called, but it seems + // to be a good idea to close things when this object is collected + public void finalize() { + if (input != null) { + error = pm.Pm_Close(input); + } + if (input != null) { + int rslt = pm.Pm_Close(output); + // we may lose an error code from closing output, but don't + // lose any real error from closing input... + if (error == pm.pmNoError) error = rslt; + } + pmRefCount--; + if (pmRefCount == 0) { + error = pm.Pm_Terminate(); + } + } + + int checkError(int err) throws JPortMidiException + { + // note that Pm_Read and Pm_Write return positive result values + // which are not errors, so compare with >= + if (err >= pm.pmNoError) return err; + if (err == pm.pmHostError) { + throw new JPortMidiException(err, pm.Pm_GetHostErrorText()); + } else { + throw new JPortMidiException(err, pm.Pm_GetErrorText(err)); + } + } + + // ******** ACCESS TO TIME *********** + + public void timeStart(int resolution) throws JPortMidiException { + checkError(pm.Pt_TimeStart(resolution)); + } + + public void timeStop() throws JPortMidiException { + checkError(pm.Pt_TimeStop()); + } + + public int timeGet() { + return pm.Pt_Time(); + } + + public boolean timeStarted() { + return pm.Pt_TimeStarted(); + } + + // ******* QUERY DEVICE INFORMATION ********* + + public int countDevices() throws JPortMidiException { + return checkError(pm.Pm_CountDevices()); + } + + public int getDefaultInputDeviceID() throws JPortMidiException { + return checkError(pm.Pm_GetDefaultInputDeviceID()); + } + + public int getDefaultOutputDeviceID() throws JPortMidiException { + return checkError(pm.Pm_GetDefaultOutputDeviceID()); + } + + public String getDeviceInterf(int i) { + return pm.Pm_GetDeviceInterf(i); + } + + public String getDeviceName(int i) { + return pm.Pm_GetDeviceName(i); + } + + public boolean getDeviceInput(int i) { + return pm.Pm_GetDeviceInput(i); + } + + public boolean getDeviceOutput(int i) { + return pm.Pm_GetDeviceOutput(i); + } + + // ********** MIDI INTERFACE ************ + + public boolean isOpenInput() { + return input != null; + } + + public void openInput(int inputDevice, int bufferSize) + throws JPortMidiException + { + openInput(inputDevice, "", bufferSize); + } + + public void openInput(int inputDevice, String inputDriverInfo, int bufferSize) + throws JPortMidiException + { + if (isOpenInput()) pm.Pm_Close(input); + else input = new PortMidiStream(); + if (trace) { + System.out.println("openInput " + getDeviceName(inputDevice)); + } + checkError(pm.Pm_OpenInput(input, inputDevice, + inputDriverInfo, bufferSize)); + // if no exception, then increase count of open streams + openCount++; + } + + public boolean isOpenOutput() { + return output != null; + } + + public void openOutput(int outputDevice, int bufferSize, int latency) + throws JPortMidiException + { + openOutput(outputDevice, "", bufferSize, latency); + } + + public void openOutput(int outputDevice, String outputDriverInfo, + int bufferSize, int latency) throws JPortMidiException { + if (isOpenOutput()) pm.Pm_Close(output); + else output = new PortMidiStream(); + if (trace) { + System.out.println("openOutput " + getDeviceName(outputDevice)); + } + checkError(pm.Pm_OpenOutput(output, outputDevice, outputDriverInfo, + bufferSize, latency)); + // if no exception, then increase count of open streams + openCount++; + } + + public void setFilter(int filters) throws JPortMidiException { + if (input == null) return; // no effect if input not open + checkError(pm.Pm_SetFilter(input, filters)); + } + + public void setChannelMask(int mask) throws JPortMidiException { + if (input == null) return; // no effect if input not open + checkError(pm.Pm_SetChannelMask(input, mask)); + } + + public void abort() throws JPortMidiException { + if (output == null) return; // no effect if output not open + checkError(pm.Pm_Abort(output)); + } + + // In keeping with the idea that this class represents an input and output, + // there are separate Close methods for input and output streams, avoiding + // the need for clients to ever deal directly with a stream object + public void closeInput() throws JPortMidiException { + if (input == null) return; // no effect if input not open + checkError(pm.Pm_Close(input)); + input = null; + openCount--; + } + + public void closeOutput() throws JPortMidiException { + if (output == null) return; // no effect if output not open + checkError(pm.Pm_Close(output)); + output = null; + openCount--; + } + + // Poll should be called by client to process input messages (if any) + public void poll() throws JPortMidiException { + if (input == null) return; // does nothing until input is opened + while (true) { + int rslt = pm.Pm_Read(input, buffer); + checkError(rslt); + if (rslt == 0) return; // no more messages + handleMidiIn(buffer); + } + } + + public void writeShort(int when, int msg) throws JPortMidiException { + if (output == null) + throw new JPortMidiException(pmOutputNotOpen, + "Output stream not open"); + if (trace) { + System.out.println("writeShort: " + Integer.toHexString(msg)); + } + checkError(pm.Pm_WriteShort(output, when, msg)); + } + + public void writeSysEx(int when, byte msg[]) throws JPortMidiException { + if (output == null) + throw new JPortMidiException(pmOutputNotOpen, + "Output stream not open"); + if (trace) { + System.out.print("writeSysEx: "); + for (int i = 0; i < msg.length; i++) { + System.out.print(Integer.toHexString(msg[i])); + } + System.out.print("\n"); + } + checkError(pm.Pm_WriteSysEx(output, when, msg)); + } + + public int midiChanMessage(int chan, int status, int data1, int data2) { + return (((data2 << 16) & 0xFF0000) | + ((data1 << 8) & 0xFF00) | + (status & 0xF0) | + (chan & 0xF)); + } + + public int midiMessage(int status, int data1, int data2) { + return ((((data2) << 16) & 0xFF0000) | + (((data1) << 8) & 0xFF00) | + ((status) & 0xFF)); + } + + public void midiAllOff(int channel) throws JPortMidiException { + midiAllOff(channel, NOW); + } + + public void midiAllOff(int chan, int when) throws JPortMidiException { + writeShort(when, midiChanMessage(chan, MIDI_CONTROL, CTRL_ALL_OFF, 0)); + } + + public void midiPitchBend(int chan, int value) throws JPortMidiException { + midiPitchBend(chan, value, NOW); + } + + public void midiPitchBend(int chan, int value, int when) + throws JPortMidiException { + writeShort(when, + midiChanMessage(chan, MIDI_PITCH_BEND, value, value >> 7)); + } + + public void midiClock() throws JPortMidiException { + midiClock(NOW); + } + + public void midiClock(int when) throws JPortMidiException { + writeShort(when, midiMessage(MIDI_CLOCK, 0, 0)); + } + + public void midiControl(int chan, int control, int value) + throws JPortMidiException { + midiControl(chan, control, value, NOW); + } + + public void midiControl(int chan, int control, int value, int when) + throws JPortMidiException { + writeShort(when, midiChanMessage(chan, MIDI_CONTROL, control, value)); + } + + public void midiNote(int chan, int pitch, int vel) + throws JPortMidiException { + midiNote(chan, pitch, vel, NOW); + } + + public void midiNote(int chan, int pitch, int vel, int when) + throws JPortMidiException { + writeShort(when, midiChanMessage(chan, MIDI_NOTE_ON, pitch, vel)); + } + + public void midiProgram(int chan, int program) + throws JPortMidiException { + midiProgram(chan, program, NOW); + } + + public void midiProgram(int chan, int program, int when) + throws JPortMidiException { + writeShort(when, midiChanMessage(chan, MIDI_PROGRAM, program, 0)); + } + + public void midiStart() + throws JPortMidiException { + midiStart(NOW); + } + + public void midiStart(int when) + throws JPortMidiException { + writeShort(when, midiMessage(MIDI_START, 0, 0)); + } + + public void midiStop() + throws JPortMidiException { + midiStop(NOW); + } + + public void midiStop(int when) + throws JPortMidiException { + writeShort(when, midiMessage(MIDI_STOP, 0, 0)); + } + + public void midiPolyTouch(int chan, int key, int value) + throws JPortMidiException { + midiPolyTouch(chan, key, value, NOW); + } + + public void midiPolyTouch(int chan, int key, int value, int when) + throws JPortMidiException { + writeShort(when, midiChanMessage(chan, MIDI_POLY_TOUCH, key, value)); + } + + public void midiTouch(int chan, int value) + throws JPortMidiException { + midiTouch(chan, value, NOW); + } + + public void midiTouch(int chan, int value, int when) + throws JPortMidiException { + writeShort(when, midiChanMessage(chan, MIDI_TOUCH, value, 0)); + } + + // ****** now we implement the message handlers ****** + + // an array for incoming sysex messages that can grow. + // The downside is that after getting a message, we + + private byte sysexBuffer[] = null; + private int sysexBufferIndex = 0; + + void sysexBufferReset() { + sysexBufferIndex = 0; + if (sysexBuffer == null) sysexBuffer = new byte[256]; + } + + void sysexBufferCheck() { + if (sysexBuffer.length < sysexBufferIndex + 4) { + byte bigger[] = new byte[sysexBuffer.length * 2]; + for (int i = 0; i < sysexBufferIndex; i++) { + bigger[i] = sysexBuffer[i]; + } + sysexBuffer = bigger; + } + // now we have space to write some bytes + } + + // call this to insert Sysex and EOX status bytes + // call sysexBufferAppendBytes to insert anything else + void sysexBufferAppendStatus(byte status) { + sysexBuffer[sysexBufferIndex++] = status; + } + + void sysexBufferAppendBytes(int msg, int len) { + for (int i = 0; i < len; i++) { + byte b = (byte) msg; + if ((msg & 0x80) != 0) { + if (b == 0xF7) { // end of sysex + sysexBufferAppendStatus(b); + sysex(sysexBuffer, sysexBufferIndex); + return; + } + // recursively handle embedded real-time messages + PmEvent buffer = new PmEvent(); + buffer.timestamp = timestamp; + buffer.message = b; + handleMidiIn(buffer); + } else { + sysexBuffer[sysexBufferIndex++] = b; + } + msg = msg >> 8; + } + } + + void sysexBegin(int msg) { + sysexBufferReset(); // start from 0, we have at least 256 bytes now + sysexBufferAppendStatus((byte) (msg & 0xFF)); // first byte is special + sysexBufferAppendBytes(msg >> 8, 3); // process remaining bytes + } + + public void handleMidiIn(PmEvent buffer) + { + if (trace) { + System.out.println("handleMidiIn: " + + Integer.toHexString(buffer.message)); + } + // rather than pass timestamps to every handler, where typically + // timestamps are ignored, just save the timestamp as a member + // variable where methods can access it if they want it + timestamp = buffer.timestamp; + int status = buffer.message & 0xFF; + if (status < 0x80) { + sysexBufferCheck(); // make enough space + sysexBufferAppendBytes(buffer.message, 4); // process 4 bytes + return; + } + int command = status & 0xF0; + int channel = status & 0x0F; + int data1 = (buffer.message >> 8) & 0xFF; + int data2 = (buffer.message >> 16) & 0xFF; + switch (command) { + case MIDI_NOTE_OFF: + noteOff(channel, data1, data2); break; + case MIDI_NOTE_ON: + if (data2 > 0) { + noteOn(channel, data1, data2); break; + } else { + noteOff(channel, data1); + } + break; + case MIDI_CONTROL: + control(channel, data1, data2); break; + case MIDI_POLY_TOUCH: + polyTouch(channel, data1, data2); break; + case MIDI_TOUCH: + touch(channel, data1); break; + case MIDI_PITCH_BEND: + pitchBend(channel, (data1 + (data2 << 7)) - 8192); break; + case MIDI_PROGRAM: + program(channel, data1); break; + case 0xF0: + switch (channel) { + case 0: sysexBegin(buffer.message); break; + case 1: mtcQuarterFrame(data1); + case 2: songPosition(data1 + (data2 << 7)); break; + case 3: songSelect(data1); break; + case 4: /* unused */ break; + case 5: /* unused */ break; + case 6: tuneRequest(); break; + case 7: sysexBufferAppendBytes(buffer.message, buffer.message); break; + case 8: clock(); break; + case 9: tick(); break; + case 0xA: clockStart(); break; + case 0xB: clockContinue(); break; + case 0xC: clockStop(); break; + case 0xD: /* unused */ break; + case 0xE: activeSense(); break; + case 0xF: reset(); break; + } + } + } + + // the value ranges from +8181 to -8192. The interpretation is + // synthesizer dependent. Often the range is +/- one whole step + // (two semitones), but the range is usually adjustable within + // the synthesizer. + void pitchBend(int channel, int value) { return; } + void control(int channel, int control, int value) { return; } + void noteOn(int channel, int pitch, int velocity) { return; } + // you can handle velocity in note-off if you want, but the default + // is to drop the velocity and call the simpler NoteOff handler + void noteOff(int channel, int pitch, int velocity) { + noteOff(channel, pitch); + } + // if the subclass wants to implement NoteOff with velocity, it + // should override the following to make sure all NoteOffs are handled + void noteOff(int channel, int pitch) { return; } + void program(int channel, int program) { return; } + // the byte array may be bigger than the message, length tells how + // many bytes in the array are part of the message + void sysex(byte[] msg, int length) { return; } + void polyTouch(int channel, int key, int value) { return; } + void touch(int channel, int value) { return; } + void mtcQuarterFrame(int value) { return; } + // the value is a 14-bit integer representing 16th notes + void songPosition(int value) { return; } + void songSelect(int value) { return; } + void tuneRequest() { return; } + void clock() { return; } // represents 1/24th of a quarter note + void tick() { return; } // represents 10ms + void clockStart() { return; } + void clockStop() { return; } + void clockContinue() { return; } + void activeSense() { return; } + void reset() { return; } +} diff --git a/portmidi/pm_java/jportmidi/JPortMidiApi.java b/portmidi/pm_java/jportmidi/JPortMidiApi.java new file mode 100644 index 0000000..45dd9d9 --- /dev/null +++ b/portmidi/pm_java/jportmidi/JPortMidiApi.java @@ -0,0 +1,117 @@ +package jportmidi; + +public class JPortMidiApi { + public static class PortMidiStream { + private long address; + } + public static class PmEvent { + public int message; + public int timestamp; + } + + // PmError bindings + public final int pmNoError = 0; + public final int pmNoData = 0; + public final int pmGotData = -1; + public final int pmHostError = -10000; + public final int pmInvalidDeviceId = -9999; + public final int pmInsufficientMemory = -9998; + public final int pmBufferTooSmall = -9997; + public final int pmBufferOverflow = -9996; + public final int pmBadPtr = -9995; + public final int pmBadData = -9994; + public final int pmInternalError = -9993; + public final int pmBufferMaxSize = -9992; + + static public native int Pm_Initialize(); + static public native int Pm_Terminate(); + static public native int Pm_HasHostError(PortMidiStream stream); + static public native String Pm_GetErrorText(int errnum); + static public native String Pm_GetHostErrorText(); + final int pmNoDevice = -1; + static public native int Pm_CountDevices(); + static public native int Pm_GetDefaultInputDeviceID(); + static public native int Pm_GetDefaultOutputDeviceID(); + static public native String Pm_GetDeviceInterf(int i); + static public native String Pm_GetDeviceName(int i); + static public native boolean Pm_GetDeviceInput(int i); + static public native boolean Pm_GetDeviceOutput(int i); + static public native int Pm_OpenInput(PortMidiStream stream, + int inputDevice, + String inputDriverInfo, + int bufferSize); + static public native int Pm_OpenOutput(PortMidiStream stream, + int outputDevice, + String outnputDriverInfo, + int bufferSize, + int latency); + final static public int PM_FILT_ACTIVE = (1 << 0x0E); + final static public int PM_FILT_SYSEX = (1 << 0x00); + final static public int PM_FILT_CLOCK = (1 << 0x08); + final static public int PM_FILT_PLAY = + (1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B); + final static public int PM_FILT_TICK = (1 << 0x09); + final static public int PM_FILT_FD = (1 << 0x0D); + final static public int PM_FILT_UNDEFINED = PM_FILT_FD; + final static public int PM_FILT_RESET = (1 << 0x0F); + final static public int PM_FILT_REALTIME = + PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_CLOCK; + final static public int PM_FILT_NOTE = (1 << 0x19) | (1 << 0x18); + final static public int PM_FILT_CHANNEL_AFTERTOUCH = (1 << 0x1D); + final static public int PM_FILT_POLY_AFTERTOUCH = (1 << 0x1A); + final static public int PM_FILT_AFTERTOUCH = + (PM_FILT_CHANNEL_AFTERTOUCH | PM_FILT_POLY_AFTERTOUCH); + final static public int PM_FILT_PROGRAM = (1 << 0x1C); + final static public int PM_FILT_CONTROL = (1 << 0x1B); + final static public int PM_FILT_PITCHBEND = (1 << 0x1E); + final static public int PM_FILT_MTC = (1 << 0x01); + final static public int PM_FILT_SONG_POSITION = (1 << 0x02); + final static public int PM_FILT_SONG_SELECT = (1 << 0x03); + final static public int PM_FILT_TUNE = (1 << 0x06); + final static public int PM_FILT_SYSTEMCOMMON = + (PM_FILT_MTC | PM_FILT_SONG_POSITION | + PM_FILT_SONG_SELECT | PM_FILT_TUNE); + static public native int Pm_SetFilter(PortMidiStream stream, int filters); + static public int Pm_Channel(int channel) { return 1 << channel; } + final static public native int Pm_SetChannelMask(PortMidiStream stream, + int mask); + final static public native int Pm_Abort(PortMidiStream stream); + final static public native int Pm_Close(PortMidiStream stream); + static public int Pm_Message(int status, int data1, int data2) { + return (((data2 << 16) & 0xFF0000) | + ((data1 << 8) & 0xFF00) | + (status & 0xFF)); + } + static public int Pm_MessageStatus(int msg) { + return msg & 0xFF; + } + static public int Pm_MessageData1(int msg) { + return (msg >> 8) & 0xFF; + } + static public int Pm_MessageData2(int msg) { + return (msg >> 16) & 0xFF; + } + // only supports reading one buffer at a time + static public native int Pm_Read(PortMidiStream stream, PmEvent buffer); + static public native int Pm_Poll(PortMidiStream stream); + // only supports writing one buffer at a time + static public native int Pm_Write(PortMidiStream stream, PmEvent buffer); + static public native int Pm_WriteShort(PortMidiStream stream, + int when, int msg); + static public native int Pm_WriteSysEx(PortMidiStream stream, + int when, byte msg[]); + + public final int ptNoError = 0; + public final int ptAlreadyStarted = -10000; + public final int ptAlreadyStopped = -9999; + public final int PtInsufficientMemory = -9998; + static public native int Pt_TimeStart(int resolution); + static public native int Pt_TimeStop(); + static public native int Pt_Time(); + static public native boolean Pt_TimeStarted(); + static { + System.out.println("Loading pmjni"); + System.loadLibrary("pmjni"); + System.out.println("done loading pmjni"); + } +} diff --git a/portmidi/pm_java/jportmidi/JPortMidiException.java b/portmidi/pm_java/jportmidi/JPortMidiException.java new file mode 100644 index 0000000..9be8aaf --- /dev/null +++ b/portmidi/pm_java/jportmidi/JPortMidiException.java @@ -0,0 +1,12 @@ +// JPortMidiException -- thrown by JPortMidi methods + +package jportmidi; + +public class JPortMidiException extends Exception { + public int error = 0; + public JPortMidiException(int err, String msg) { + super(msg); + error = err; + } +} + diff --git a/portmidi/pm_java/make.bat b/portmidi/pm_java/make.bat new file mode 100644 index 0000000..ff15c2b --- /dev/null +++ b/portmidi/pm_java/make.bat @@ -0,0 +1,50 @@ +@echo off
+
+rem This is an out-of-date script for Windows to build a Java application
+rem (PmDefaults) with PortMidi external library.xb
+
+rem Compile the java PortMidi interface classes.
+javac jportmidi/*.java
+
+rem Compile the pmdefaults application.
+javac -classpath . pmdefaults/*.java
+
+rem Temporarily copy the portmusic_logo.png file here to add to the jar file.
+copy pmdefaults\portmusic_logo.png . > nul
+
+rem Create a directory to hold the distribution.
+mkdir win32
+
+rem Attempt to copy the interface DLL to the distribution directory.
+
+if exist "..\release\pmjni.dll" goto have-dll
+
+echo "ERROR: pmjni.dll not found!"
+exit /b 1
+
+:have-dll
+copy "..\release\pmjni.dll" win32\pmjni.dll > nul
+
+rem Create a java archive (jar) file of the distribution.
+jar cmf pmdefaults\manifest.txt win32\pmdefaults.jar pmdefaults\*.class portmusic_logo.png jportmidi\*.class
+
+rem Clean up the temporary image file now that it is in the jar file.
+del portmusic_logo.png
+
+rem Copy the java execution code obtained from
+rem http://devwizard.free.fr/html/en/JavaExe.html to the distribution
+rem directory. The copy also renames the file to our desired executable
+rem name.
+copy JavaExe.exe win32\pmdefaults.exe > nul
+
+rem Integrate the icon into the executable using UpdateRsrcJavaExe from
+rem http://devwizard.free.fr
+UpdateRsrcJavaExe -run -exe=win32\pmdefaults.exe -ico=pmdefaults\pmdefaults.ico
+
+rem Copy the 32-bit windows read me file to the distribution directory.
+copy pmdefaults\readme-win32.txt win32\README.txt > nul
+
+rem Copy the license file to the distribution directory.
+copy pmdefaults\pmdefaults-license.txt win32\license.txt > nul
+
+echo "You can run pmdefaults.exe in win32"
diff --git a/portmidi/pm_java/pmjni/jportmidi_JportMidiApi.h b/portmidi/pm_java/pmjni/jportmidi_JportMidiApi.h new file mode 100644 index 0000000..2208be6 --- /dev/null +++ b/portmidi/pm_java/pmjni/jportmidi_JportMidiApi.h @@ -0,0 +1,293 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class jportmidi_JPortMidiApi */ + +#ifndef _Included_jportmidi_JPortMidiApi +#define _Included_jportmidi_JPortMidiApi +#ifdef __cplusplus +extern "C" { +#endif +#undef jportmidi_JPortMidiApi_PM_FILT_ACTIVE +#define jportmidi_JPortMidiApi_PM_FILT_ACTIVE 16384L +#undef jportmidi_JPortMidiApi_PM_FILT_SYSEX +#define jportmidi_JPortMidiApi_PM_FILT_SYSEX 1L +#undef jportmidi_JPortMidiApi_PM_FILT_CLOCK +#define jportmidi_JPortMidiApi_PM_FILT_CLOCK 256L +#undef jportmidi_JPortMidiApi_PM_FILT_PLAY +#define jportmidi_JPortMidiApi_PM_FILT_PLAY 7168L +#undef jportmidi_JPortMidiApi_PM_FILT_TICK +#define jportmidi_JPortMidiApi_PM_FILT_TICK 512L +#undef jportmidi_JPortMidiApi_PM_FILT_FD +#define jportmidi_JPortMidiApi_PM_FILT_FD 8192L +#undef jportmidi_JPortMidiApi_PM_FILT_UNDEFINED +#define jportmidi_JPortMidiApi_PM_FILT_UNDEFINED 8192L +#undef jportmidi_JPortMidiApi_PM_FILT_RESET +#define jportmidi_JPortMidiApi_PM_FILT_RESET 32768L +#undef jportmidi_JPortMidiApi_PM_FILT_REALTIME +#define jportmidi_JPortMidiApi_PM_FILT_REALTIME 16641L +#undef jportmidi_JPortMidiApi_PM_FILT_NOTE +#define jportmidi_JPortMidiApi_PM_FILT_NOTE 50331648L +#undef jportmidi_JPortMidiApi_PM_FILT_CHANNEL_AFTERTOUCH +#define jportmidi_JPortMidiApi_PM_FILT_CHANNEL_AFTERTOUCH 536870912L +#undef jportmidi_JPortMidiApi_PM_FILT_POLY_AFTERTOUCH +#define jportmidi_JPortMidiApi_PM_FILT_POLY_AFTERTOUCH 67108864L +#undef jportmidi_JPortMidiApi_PM_FILT_AFTERTOUCH +#define jportmidi_JPortMidiApi_PM_FILT_AFTERTOUCH 603979776L +#undef jportmidi_JPortMidiApi_PM_FILT_PROGRAM +#define jportmidi_JPortMidiApi_PM_FILT_PROGRAM 268435456L +#undef jportmidi_JPortMidiApi_PM_FILT_CONTROL +#define jportmidi_JPortMidiApi_PM_FILT_CONTROL 134217728L +#undef jportmidi_JPortMidiApi_PM_FILT_PITCHBEND +#define jportmidi_JPortMidiApi_PM_FILT_PITCHBEND 1073741824L +#undef jportmidi_JPortMidiApi_PM_FILT_MTC +#define jportmidi_JPortMidiApi_PM_FILT_MTC 2L +#undef jportmidi_JPortMidiApi_PM_FILT_SONG_POSITION +#define jportmidi_JPortMidiApi_PM_FILT_SONG_POSITION 4L +#undef jportmidi_JPortMidiApi_PM_FILT_SONG_SELECT +#define jportmidi_JPortMidiApi_PM_FILT_SONG_SELECT 8L +#undef jportmidi_JPortMidiApi_PM_FILT_TUNE +#define jportmidi_JPortMidiApi_PM_FILT_TUNE 64L +#undef jportmidi_JPortMidiApi_PM_FILT_SYSTEMCOMMON +#define jportmidi_JPortMidiApi_PM_FILT_SYSTEMCOMMON 78L +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_Initialize + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Initialize + (JNIEnv *, jclass); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_Terminate + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Terminate + (JNIEnv *, jclass); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_HasHostError + * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1HasHostError + (JNIEnv *, jclass, jobject); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_GetErrorText + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetErrorText + (JNIEnv *, jclass, jint); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_GetHostErrorText + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetHostErrorText + (JNIEnv *, jclass); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_CountDevices + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1CountDevices + (JNIEnv *, jclass); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_GetDefaultInputDeviceID + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultInputDeviceID + (JNIEnv *, jclass); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_GetDefaultOutputDeviceID + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultOutputDeviceID + (JNIEnv *, jclass); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_GetDeviceInterf + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInterf + (JNIEnv *, jclass, jint); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_GetDeviceName + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceName + (JNIEnv *, jclass, jint); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_GetDeviceInput + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInput + (JNIEnv *, jclass, jint); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_GetDeviceOutput + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceOutput + (JNIEnv *, jclass, jint); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_OpenInput + * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;ILjava/lang/String;I)I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenInput + (JNIEnv *, jclass, jobject, jint, jstring, jint); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_OpenOutput + * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;ILjava/lang/String;II)I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenOutput + (JNIEnv *, jclass, jobject, jint, jstring, jint, jint); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_SetFilter + * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;I)I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetFilter + (JNIEnv *, jclass, jobject, jint); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_SetChannelMask + * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;I)I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetChannelMask + (JNIEnv *, jclass, jobject, jint); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_Abort + * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Abort + (JNIEnv *, jclass, jobject); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_Close + * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Close + (JNIEnv *, jclass, jobject); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_Read + * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;Ljportmidi/JPortMidiApi/PmEvent;)I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Read + (JNIEnv *, jclass, jobject, jobject); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_Poll + * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Poll + (JNIEnv *, jclass, jobject); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_Write + * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;Ljportmidi/JPortMidiApi/PmEvent;)I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Write + (JNIEnv *, jclass, jobject, jobject); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_WriteShort + * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;II)I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteShort + (JNIEnv *, jclass, jobject, jint, jint); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pm_WriteSysEx + * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;I[B)I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteSysEx + (JNIEnv *, jclass, jobject, jint, jbyteArray); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pt_TimeStart + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStart + (JNIEnv *, jclass, jint); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pt_TimeStop + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStop + (JNIEnv *, jclass); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pt_Time + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1Time + (JNIEnv *, jclass); + +/* + * Class: jportmidi_JPortMidiApi + * Method: Pt_TimeStarted + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStarted + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class jportmidi_JPortMidiApi_PmEvent */ + +#ifndef _Included_jportmidi_JPortMidiApi_PmEvent +#define _Included_jportmidi_JPortMidiApi_PmEvent +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class jportmidi_JPortMidiApi_PortMidiStream */ + +#ifndef _Included_jportmidi_JPortMidiApi_PortMidiStream +#define _Included_jportmidi_JPortMidiApi_PortMidiStream +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif diff --git a/portmidi/pm_java/pmjni/pmjni.c b/portmidi/pm_java/pmjni/pmjni.c new file mode 100644 index 0000000..c60cffb --- /dev/null +++ b/portmidi/pm_java/pmjni/pmjni.c @@ -0,0 +1,354 @@ +#include "portmidi.h" +#include "porttime.h" +#include "jportmidi_JportMidiApi.h" +#include <stdio.h> + +// these macros assume JNIEnv *env is declared and valid: +// +#define CLASS(c, obj) jclass c = (*env)->GetObjectClass(env, obj) +#define ADDRESS_FID(fid, c) \ + jfieldID fid = (*env)->GetFieldID(env, c, "address", "J") +// Uses Java Long (64-bit) to make sure there is room to store a +// pointer. Cast this to a C long (either 32 or 64 bit) to match +// the size of a pointer. Finally cast int to pointer. All this +// is supposed to avoid C compiler warnings and (worse) losing +// address bits. +#define PMSTREAM(obj, fid) ((PmStream *) (intptr_t) (*env)->GetLongField(env, obj, fid)) +// Cast stream to long to convert integer to pointer, then expand +// integer to 64-bit jlong. This avoids compiler warnings. +#define SET_PMSTREAM(obj, fid, stream) \ + (*env)->SetLongField(env, obj, fid, (jlong) (intptr_t) stream) + + +/* + * Method: Pm_Initialize + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Initialize + (JNIEnv *env, jclass cl) +{ + return Pm_Initialize(); +} + + +/* + * Method: Pm_Terminate + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Terminate + (JNIEnv *env, jclass cl) +{ + return Pm_Terminate(); +} + + +/* + * Method: Pm_HasHostError + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1HasHostError + (JNIEnv *env, jclass cl, jobject jstream) +{ + CLASS(c, jstream); + ADDRESS_FID(fid, c); + return Pm_HasHostError(PMSTREAM(jstream, fid)); +} + + +/* + * Method: Pm_GetErrorText + */ +JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetErrorText + (JNIEnv *env, jclass cl, jint i) +{ + return (*env)->NewStringUTF(env, Pm_GetErrorText(i)); +} + + +/* + * Method: Pm_GetHostErrorText + */ +JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetHostErrorText + (JNIEnv *env, jclass cl) +{ + char msg[PM_HOST_ERROR_MSG_LEN]; + Pm_GetHostErrorText(msg, PM_HOST_ERROR_MSG_LEN); + return (*env)->NewStringUTF(env, msg); +} + + +/* + * Method: Pm_CountDevices + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1CountDevices + (JNIEnv *env, jclass cl) +{ + return Pm_CountDevices(); +} + + +/* + * Method: Pm_GetDefaultInputDeviceID + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultInputDeviceID + (JNIEnv *env, jclass cl) +{ + return Pm_GetDefaultInputDeviceID(); +} + + +/* + * Method: Pm_GetDefaultOutputDeviceID + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultOutputDeviceID + (JNIEnv *env, jclass cl) +{ + return Pm_GetDefaultOutputDeviceID(); +} + + +/* + * Method: Pm_GetDeviceInterf + */ +JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInterf + (JNIEnv *env, jclass cl, jint i) +{ + const PmDeviceInfo *info = Pm_GetDeviceInfo(i); + if (!info) return NULL; + return (*env)->NewStringUTF(env, info->interf); +} + + +/* + * Method: Pm_GetDeviceName + */ +JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceName + (JNIEnv *env, jclass cl, jint i) +{ + const PmDeviceInfo *info = Pm_GetDeviceInfo(i); + if (!info) return NULL; + return (*env)->NewStringUTF(env, info->name); +} + + +/* + * Method: Pm_GetDeviceInput + */ +JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInput + (JNIEnv *env, jclass cl, jint i) +{ + const PmDeviceInfo *info = Pm_GetDeviceInfo(i); + if (!info) return (jboolean) 0; + return (jboolean) info->input; +} + + +/* + * Method: Pm_GetDeviceOutput + */ +JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceOutput + (JNIEnv *env, jclass cl, jint i) +{ + const PmDeviceInfo *info = Pm_GetDeviceInfo(i); + if (!info) return (jboolean) 0; + return (jboolean) info->output; +} + + +/* + * Method: Pm_OpenInput + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenInput + (JNIEnv *env, jclass cl, + jobject jstream, jint index, jstring extras, jint bufsiz) +{ + PmError rslt; + PortMidiStream *stream; + CLASS(c, jstream); + ADDRESS_FID(fid, c); + rslt = Pm_OpenInput(&stream, index, NULL, bufsiz, NULL, NULL); + SET_PMSTREAM(jstream, fid, stream); + return rslt; +} + + +/* + * Method: Pm_OpenOutput + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenOutput + (JNIEnv *env, jclass cl, jobject jstream, jint index, jstring extras, + jint bufsiz, jint latency) +{ + PmError rslt; + PortMidiStream *stream; + CLASS(c, jstream); + ADDRESS_FID(fid, c); + rslt = Pm_OpenOutput(&stream, index, NULL, bufsiz, NULL, NULL, latency); + SET_PMSTREAM(jstream, fid, stream); + return rslt; +} + + +/* + * Method: Pm_SetFilter + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetFilter + (JNIEnv *env, jclass cl, jobject jstream, jint filters) +{ + CLASS(c, jstream); + ADDRESS_FID(fid, c); + return Pm_SetFilter(PMSTREAM(jstream, fid), filters); +} + + +/* + * Method: Pm_SetChannelMask + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetChannelMask + (JNIEnv *env, jclass cl, jobject jstream, jint mask) +{ + CLASS(c, jstream); + ADDRESS_FID(fid, c); + return Pm_SetChannelMask(PMSTREAM(jstream, fid), mask); +} + + +/* + * Method: Pm_Abort + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Abort + (JNIEnv *env, jclass cl, jobject jstream) +{ + CLASS(c, jstream); + ADDRESS_FID(fid, c); + return Pm_Abort(PMSTREAM(jstream, fid)); +} + + +/* + * Method: Pm_Close + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Close + (JNIEnv *env, jclass cl, jobject jstream) +{ + CLASS(c, jstream); + ADDRESS_FID(fid, c); + return Pm_Close(PMSTREAM(jstream, fid)); +} + + +/* + * Method: Pm_Read + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Read + (JNIEnv *env, jclass cl, jobject jstream, jobject jpmevent) +{ + CLASS(jstream_class, jstream); + ADDRESS_FID(address_fid, jstream_class); + jclass jpmevent_class = (*env)->GetObjectClass(env, jpmevent); + jfieldID message_fid = + (*env)->GetFieldID(env, jpmevent_class, "message", "I"); + jfieldID timestamp_fid = + (*env)->GetFieldID(env, jpmevent_class, "timestamp", "I"); + PmEvent buffer; + PmError rslt = Pm_Read(PMSTREAM(jstream, address_fid), &buffer, 1); + (*env)->SetIntField(env, jpmevent, message_fid, buffer.message); + (*env)->SetIntField(env, jpmevent, timestamp_fid, buffer.timestamp); + return rslt; +} + + +/* + * Method: Pm_Poll + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Poll + (JNIEnv *env, jclass cl, jobject jstream) +{ + CLASS(c, jstream); + ADDRESS_FID(fid, c); + return Pm_Poll(PMSTREAM(jstream, fid)); +} + + +/* + * Method: Pm_Write + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Write + (JNIEnv *env, jclass cl, jobject jstream, jobject jpmevent) +{ + CLASS(jstream_class, jstream); + ADDRESS_FID(address_fid, jstream_class); + jclass jpmevent_class = (*env)->GetObjectClass(env, jpmevent); + jfieldID message_fid = + (*env)->GetFieldID(env, jpmevent_class, "message", "I"); + jfieldID timestamp_fid = + (*env)->GetFieldID(env, jpmevent_class, "timestamp", "I"); + // note that we call WriteShort because it's simpler than constructing + // a buffer and passing it to Pm_Write + return Pm_WriteShort(PMSTREAM(jstream, address_fid), + (*env)->GetIntField(env, jpmevent, timestamp_fid), + (*env)->GetIntField(env, jpmevent, message_fid)); +} + + +/* + * Method: Pm_WriteShort + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteShort + (JNIEnv *env, jclass cl, jobject jstream, jint when, jint msg) +{ + CLASS(c, jstream); + ADDRESS_FID(fid, c); + return Pm_WriteShort(PMSTREAM(jstream, fid), when, msg); +} + + +/* + * Method: Pm_WriteSysEx + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteSysEx + (JNIEnv *env, jclass cl, jobject jstream, jint when, jbyteArray jmsg) +{ + CLASS(c, jstream); + ADDRESS_FID(fid, c); + jbyte *bytes = (*env)->GetByteArrayElements(env, jmsg, 0); + PmError rslt = Pm_WriteSysEx(PMSTREAM(jstream, fid), when, + (unsigned char *) bytes); + (*env)->ReleaseByteArrayElements(env, jmsg, bytes, 0); + return rslt; +} + +/* + * Method: Pt_TimeStart + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStart + (JNIEnv *env, jclass c, jint resolution) +{ + return Pt_Start(resolution, NULL, NULL); +} + +/* + * Method: Pt_TimeStop + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStop + (JNIEnv *env, jclass c) + { + return Pt_Stop(); + } + +/* + * Method: Pt_Time + */ +JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1Time + (JNIEnv *env, jclass c) + { + return Pt_Time(); + } + +/* + * Method: Pt_TimeStarted + */ +JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStarted + (JNIEnv *env, jclass c) +{ + return Pt_Started(); +} + + diff --git a/portmidi/pm_java/pmjni/pmjni.rc b/portmidi/pm_java/pmjni/pmjni.rc new file mode 100644 index 0000000..1b7522b --- /dev/null +++ b/portmidi/pm_java/pmjni/pmjni.rc @@ -0,0 +1,63 @@ +// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
|
