summaryrefslogtreecommitdiff
path: root/portmidi/pm_java
diff options
context:
space:
mode:
Diffstat (limited to 'portmidi/pm_java')
-rw-r--r--portmidi/pm_java/CMakeLists.txt56
-rw-r--r--portmidi/pm_java/README.txt62
-rw-r--r--portmidi/pm_java/jportmidi/JPortMidi.java541
-rw-r--r--portmidi/pm_java/jportmidi/JPortMidiApi.java117
-rw-r--r--portmidi/pm_java/jportmidi/JPortMidiException.java12
-rw-r--r--portmidi/pm_java/make.bat50
-rw-r--r--portmidi/pm_java/pmjni/jportmidi_JportMidiApi.h293
-rw-r--r--portmidi/pm_java/pmjni/pmjni.c354
-rw-r--r--portmidi/pm_java/pmjni/pmjni.rc63
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
+