Skip to content

Commit

Permalink
Added support for MidiDevices to return the elapsed time in microseconds
Browse files Browse the repository at this point in the history
since the device was opened, as described in
https://docs.oracle.com/javase/tutorial/sound/MIDI-messages.html
  • Loading branch information
DerekCook committed Jan 9, 2016
1 parent 54f2502 commit d813e69
Show file tree
Hide file tree
Showing 13 changed files with 300 additions and 13 deletions.
2 changes: 2 additions & 0 deletions CoreMIDI4J/Build/Create JNI Header.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
force="yes">

<class name="uk.co.xfactorylibrarians.coremidi4j.CoreMidiClient"/>
<class name="uk.co.xfactorylibrarians.coremidi4j.CoreMidiDestination"/>
<class name="uk.co.xfactorylibrarians.coremidi4j.CoreMidiDeviceProvider"/>
<class name="uk.co.xfactorylibrarians.coremidi4j.CoreMidiInputPort"/>
<class name="uk.co.xfactorylibrarians.coremidi4j.CoreMidiOutputPort"/>
<class name="uk.co.xfactorylibrarians.coremidi4j.CoreMidiSource"/>
</javah>
</target>

Expand Down
Binary file modified CoreMIDI4J/Build/Release/CoreMIDI4J.jar
Binary file not shown.
Binary file modified CoreMIDI4J/Build/Release/CoreMidi4J.zip
Binary file not shown.
Binary file modified CoreMIDI4J/Build/Release/libCoreMidi4J.dylib
Binary file not shown.
40 changes: 38 additions & 2 deletions CoreMIDI4J/Native/CoreMidi4J/CoreMidi4J.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@ JNIEXPORT jint JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiClient_c
JNIEXPORT void JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiClient_disposeClient
(JNIEnv *, jobject, jint);

#ifdef __cplusplus
}
#endif
#endif
/* Header for class uk_co_xfactorylibrarians_coremidi4j_CoreMidiDestination */

#ifndef _Included_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDestination
#define _Included_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDestination
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: uk_co_xfactorylibrarians_coremidi4j_CoreMidiDestination
* Method: getMicroSecondTime
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDestination_getMicroSecondTime
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
Expand All @@ -34,8 +53,6 @@ JNIEXPORT void JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiClient_d
#ifdef __cplusplus
extern "C" {
#endif
#undef uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_BUFFER_SIZE
#define uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_BUFFER_SIZE 2048L
#undef uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_DEVICE_MAP_SIZE
#define uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_DEVICE_MAP_SIZE 20L
/* Inaccessible static: midiProperties */
Expand Down Expand Up @@ -153,3 +170,22 @@ JNIEXPORT void JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiOutputPo
}
#endif
#endif
/* Header for class uk_co_xfactorylibrarians_coremidi4j_CoreMidiSource */

#ifndef _Included_uk_co_xfactorylibrarians_coremidi4j_CoreMidiSource
#define _Included_uk_co_xfactorylibrarians_coremidi4j_CoreMidiSource
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: uk_co_xfactorylibrarians_coremidi4j_CoreMidiSource
* Method: getMicroSecondTime
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiSource_getMicroSecondTime
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
16 changes: 16 additions & 0 deletions CoreMIDI4J/Native/CoreMidi4J/CoreMidi4J.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

/* Begin PBXBuildFile section */
650999561C303B4100879DFB /* libCoreMidi4J.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 65E46C1D1B89DB8200CC6075 /* libCoreMidi4J.dylib */; };
655485591C4172B3002975D6 /* CoreMidiSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 655485571C4172B3002975D6 /* CoreMidiSource.cpp */; };
6554855A1C4172B3002975D6 /* CoreMidiSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 655485581C4172B3002975D6 /* CoreMidiSource.h */; };
6554855D1C417683002975D6 /* CoreMidiDestination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6554855B1C417683002975D6 /* CoreMidiDestination.cpp */; };
6554855E1C417683002975D6 /* CoreMidiDestination.h in Headers */ = {isa = PBXBuildFile; fileRef = 6554855C1C417683002975D6 /* CoreMidiDestination.h */; };
65E46C271B89DBAF00CC6075 /* CoreMidi4J.h in Headers */ = {isa = PBXBuildFile; fileRef = 65E46C251B89DBAF00CC6075 /* CoreMidi4J.h */; };
65E46C291B89DC6700CC6075 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65E46C281B89DC6700CC6075 /* Cocoa.framework */; };
65E46C2B1B89DC7200CC6075 /* CoreMIDI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65E46C2A1B89DC7200CC6075 /* CoreMIDI.framework */; };
Expand Down Expand Up @@ -35,6 +39,10 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
655485571C4172B3002975D6 /* CoreMidiSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CoreMidiSource.cpp; path = CoreMidi4J.xcodeproj/../CoreMidiSource.cpp; sourceTree = "<group>"; tabWidth = 2; };
655485581C4172B3002975D6 /* CoreMidiSource.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CoreMidiSource.h; path = CoreMidi4J.xcodeproj/../CoreMidiSource.h; sourceTree = "<group>"; tabWidth = 2; };
6554855B1C417683002975D6 /* CoreMidiDestination.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CoreMidiDestination.cpp; path = CoreMidi4J.xcodeproj/../CoreMidiDestination.cpp; sourceTree = "<group>"; tabWidth = 2; };
6554855C1C417683002975D6 /* CoreMidiDestination.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CoreMidiDestination.h; path = CoreMidi4J.xcodeproj/../CoreMidiDestination.h; sourceTree = "<group>"; tabWidth = 2; };
65E46C1D1B89DB8200CC6075 /* libCoreMidi4J.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libCoreMidi4J.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
65E46C251B89DBAF00CC6075 /* CoreMidi4J.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = CoreMidi4J.h; sourceTree = "<group>"; tabWidth = 2; wrapsLines = 0; };
65E46C281B89DC6700CC6075 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
Expand Down Expand Up @@ -72,12 +80,16 @@
65E46C251B89DBAF00CC6075 /* CoreMidi4J.h */,
65EE982D1C2414BE000DDF1A /* CoreMidiClient.cpp */,
65EE982E1C2414BE000DDF1A /* CoreMidiClient.h */,
6554855B1C417683002975D6 /* CoreMidiDestination.cpp */,
6554855C1C417683002975D6 /* CoreMidiDestination.h */,
65EE98261C240C66000DDF1A /* CoreMidiDeviceProvider.cpp */,
65EE98311C241529000DDF1A /* CoreMidiDeviceProvider.h */,
65EE98361C241615000DDF1A /* CoreMidiInputPort.cpp */,
65EE98371C241615000DDF1A /* CoreMidiInputPort.h */,
65EE98321C2415B1000DDF1A /* CoreMidiOutputPort.cpp */,
65EE98331C2415B1000DDF1A /* CoreMidiOutputPort.h */,
655485571C4172B3002975D6 /* CoreMidiSource.cpp */,
655485581C4172B3002975D6 /* CoreMidiSource.h */,
65EE982B1C2412C4000DDF1A /* CoreMidi4JUtilities.cpp */,
65EE982A1C240D37000DDF1A /* CoreMidi4JUtilities.h */,
65E46C1E1B89DB8200CC6075 /* Products */,
Expand All @@ -102,7 +114,9 @@
65EE98351C2415B1000DDF1A /* CoreMidiOutputPort.h in Headers */,
65E46C271B89DBAF00CC6075 /* CoreMidi4J.h in Headers */,
65EE98391C241615000DDF1A /* CoreMidiInputPort.h in Headers */,
6554855E1C417683002975D6 /* CoreMidiDestination.h in Headers */,
65EE98301C2414BE000DDF1A /* CoreMidiClient.h in Headers */,
6554855A1C4172B3002975D6 /* CoreMidiSource.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -165,7 +179,9 @@
files = (
65EE98281C240C66000DDF1A /* CoreMidiDeviceProvider.cpp in Sources */,
65EE982C1C2412C4000DDF1A /* CoreMidi4JUtilities.cpp in Sources */,
655485591C4172B3002975D6 /* CoreMidiSource.cpp in Sources */,
65EE982F1C2414BE000DDF1A /* CoreMidiClient.cpp in Sources */,
6554855D1C417683002975D6 /* CoreMidiDestination.cpp in Sources */,
65EE98341C2415B1000DDF1A /* CoreMidiOutputPort.cpp in Sources */,
65EE98381C241615000DDF1A /* CoreMidiInputPort.cpp in Sources */,
);
Expand Down
Binary file not shown.
62 changes: 62 additions & 0 deletions CoreMIDI4J/Native/CoreMidi4J/CoreMidiDestination.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Title: CoreMIDI4J
* Description: Core MIDI Device Provider for Java on OS X
* Copyright: Copyright (c) 2015-2016
* Company: x.factory Librarians
*
* @author Derek Cook
*
* CoreMIDI4J is an open source Service Provider Interface for supporting external MIDI devices on MAC OS X
*
* This file is part of the XCODE project that provides the native implementation of CoreMIDI4J
*
* CREDITS - This library uses principles established by OSXMIDI4J, but converted so it operates at the JNI level with no additional libraries required
*
*/

#include "CoreMidiDestination.h"

/*
* Obtains the current system time in microseconds.
*
* Class: uk_co_xfactorylibrarians_coremidi4j_CoreMidiDestination
* Method: getMicroSecondTime
* Signature: ()J
*
* @return The current system time in microseconds.
*
*/

JNIEXPORT jlong JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDestination_getMicroSecondTime(JNIEnv *, jobject) {

static mach_timebase_info_data_t sTimebaseInfo; // Will hold conversion factor for timestamps

// If this is the first time we've run, get the timebase.
// We can use denom == 0 to indicate that sTimebaseInfo is
// uninitialised because it makes no sense to have a zero
// denominator in a fraction.
if ( sTimebaseInfo.denom == 0 ) {

(void) mach_timebase_info(&sTimebaseInfo);

}

uint64_t currentMachTime = mach_absolute_time();

// Convert the timestamp from Mach Absolute Time Units to microseconds,
// as expected by Java MIDI. The first step is based on Apple Tech Q&A 1398,
// https://developer.apple.com/library/mac/qa/qa1398/_index.html
//
// Because we are converting to microseconds rather than nanoseconds, we can start
// by dividing by 1000, which should eliminate the risk of overflow described in the
// comment below (copied in from the Q&A), which evidently should not have been an issue
// until 584.9 years after the most recent system boot anyway, according to
// http://lists.apple.com/archives/darwin-kernel/2012/Sep/msg00008.html
//
// Do the maths. We hope that the multiplication doesn't
// overflow; the price you pay for working in fixed point.
uint64_t timestamp = (currentMachTime / 1000) * sTimebaseInfo.numer / sTimebaseInfo.denom;

return timestamp;

}
27 changes: 27 additions & 0 deletions CoreMIDI4J/Native/CoreMidi4J/CoreMidiDestination.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Title: CoreMIDI4J
* Description: Core MIDI Device Provider for Java on OS X
* Copyright: Copyright (c) 2015-2016
* Company: x.factory Librarians
*
* @author Derek Cook
*
* CoreMIDI4J is an open source Service Provider Interface for supporting external MIDI devices on MAC OS X
*
* This file is part of the XCODE project that provides the native implementation of CoreMIDI4J
*
* CREDITS - This library uses principles established by OSXMIDI4J, but converted so it operates at the JNI level with no additional libraries required
*
*/

#ifndef ____CoreMidiDestination__
#define ____CoreMidiDestination__

#include "CoreMidi4J.h"
#include "CoreMidi4JUtilities.h"

#include <stdio.h>
#include <mach/mach.h>
#include <mach/mach_time.h>

#endif /* defined(____CoreMidiDestination__) */
63 changes: 63 additions & 0 deletions CoreMIDI4J/Native/CoreMidi4J/CoreMidiSource.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* Title: CoreMIDI4J
* Description: Core MIDI Device Provider for Java on OS X
* Copyright: Copyright (c) 2015-2016
* Company: x.factory Librarians
*
* @author Derek Cook
*
* CoreMIDI4J is an open source Service Provider Interface for supporting external MIDI devices on MAC OS X
*
* This file is part of the XCODE project that provides the native implementation of CoreMIDI4J
*
* CREDITS - This library uses principles established by OSXMIDI4J, but converted so it operates at the JNI level with no additional libraries required
*
*/

#include "CoreMidiSource.h"

/*
* Obtains the current system time in microseconds.
*
* Class: uk_co_xfactorylibrarians_coremidi4j_CoreMidiSource
* Method: getMicroSecondTime
* Signature: ()J
*
* @return The current system time in microseconds.
*
*/

JNIEXPORT jlong JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiSource_getMicroSecondTime(JNIEnv *, jobject) {

static mach_timebase_info_data_t sTimebaseInfo; // Will hold conversion factor for timestamps

// If this is the first time we've run, get the timebase.
// We can use denom == 0 to indicate that sTimebaseInfo is
// uninitialised because it makes no sense to have a zero
// denominator in a fraction.
if ( sTimebaseInfo.denom == 0 ) {

(void) mach_timebase_info(&sTimebaseInfo);

}

uint64_t currentMachTime = mach_absolute_time();

// Convert the timestamp from Mach Absolute Time Units to microseconds,
// as expected by Java MIDI. The first step is based on Apple Tech Q&A 1398,
// https://developer.apple.com/library/mac/qa/qa1398/_index.html
//
// Because we are converting to microseconds rather than nanoseconds, we can start
// by dividing by 1000, which should eliminate the risk of overflow described in the
// comment below (copied in from the Q&A), which evidently should not have been an issue
// until 584.9 years after the most recent system boot anyway, according to
// http://lists.apple.com/archives/darwin-kernel/2012/Sep/msg00008.html
//
// Do the maths. We hope that the multiplication doesn't
// overflow; the price you pay for working in fixed point.
uint64_t timestamp = (currentMachTime / 1000) * sTimebaseInfo.numer / sTimebaseInfo.denom;

return timestamp;

}

27 changes: 27 additions & 0 deletions CoreMIDI4J/Native/CoreMidi4J/CoreMidiSource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Title: CoreMIDI4J
* Description: Core MIDI Device Provider for Java on OS X
* Copyright: Copyright (c) 2015-2016
* Company: x.factory Librarians
*
* @author Derek Cook
*
* CoreMIDI4J is an open source Service Provider Interface for supporting external MIDI devices on MAC OS X
*
* This file is part of the XCODE project that provides the native implementation of CoreMIDI4J
*
* CREDITS - This library uses principles established by OSXMIDI4J, but converted so it operates at the JNI level with no additional libraries required
*
*/

#ifndef ____CoreMidiSource__
#define ____CoreMidiSource__

#include "CoreMidi4J.h"
#include "CoreMidi4JUtilities.h"

#include <stdio.h>
#include <mach/mach.h>
#include <mach/mach_time.h>

#endif /* defined(____CoreMidiSource__) */
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class CoreMidiDestination implements MidiDevice {
private final CoreMidiDeviceInfo info;

private boolean isOpen;
private long startTime; // The system time in microseconds when the port was opened

/**
* Default constructor.
Expand Down Expand Up @@ -72,6 +73,9 @@ public Info getDeviceInfo() {
public void open() throws MidiUnavailableException {

isOpen = true;

// Get the system time in microseconds
startTime = this.getMicroSecondTime();

}

Expand Down Expand Up @@ -105,20 +109,19 @@ public boolean isOpen() {
}

/**
* Obtains the current time-stamp of the device, in microseconds.
* This interface does not support time-stamps, so it should always return -1.
* Obtains the time in microseconds that has elapsed since this MIDI Device was opened.
*
* @return the time in microseconds that has elapsed since this MIDI Device was opened.
*
* @see javax.sound.midi.MidiDevice#getMicrosecondPosition()
*
* @return Always -1 as this device does not support timestamps.
*
*/

@Override
public long getMicrosecondPosition() {

// Not supported
return -1;
// Return the elapsed time in Microseconds
return this.getMicroSecondTime() - startTime;

}

Expand Down Expand Up @@ -220,4 +223,28 @@ public List<Transmitter> getTransmitters() {

}

//////////////////////////////
///// JNI Interfaces
//////////////////////////////

/**
* Static method for loading the native library
*
*/

static {

System.loadLibrary("CoreMIDI4J");

}

/**
* Obtains the current system time in microseconds.
*
* @return The current system time in microseconds.
*
*/

private native long getMicroSecondTime();

}
Loading

0 comments on commit d813e69

Please sign in to comment.