Skip to content

Commit

Permalink
I discovered that CMake supports building jar files, so I replaced th…
Browse files Browse the repository at this point in the history
…e custom project code with UseJava and add_jar(), but work is needed for Windows and testing for Linux.
  • Loading branch information
rbdannenberg committed Dec 20, 2021
1 parent 64314cc commit b7267da
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 55 deletions.
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/CMakeCache.txt
/CMakeFiles/
/CMakeScripts/
/Debug/
/Release/
/cmake_install.cmake
/pm_common/cmake_install.cmake
/pm_common/portmidi.build/
/pm_java/CMakeFiles/
/pm_java/CMakeScripts/
/pm_java/cmake_install.cmake
/pm_java/pmdefaults.xcodeproj/
/pm_java/pmdefaults/pmdefaults.jar
/pm_java/portmidi.build/
/pm_test/cmake_install.cmake
/pm_test/portmidi.build/
/portmidi.build/
/portmidi.xcodeproj/

2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# 20 Sep 2009

cmake_minimum_required(VERSION 2.8.12)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6 CACHE STRING
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9 CACHE STRING
"make for this OS version or higher")

if(UNIX)
Expand Down
10 changes: 4 additions & 6 deletions Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ PROJECT_BRIEF = "Cross-platform MIDI IO library"
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.

PROJECT_LOGO = /Users/rbd/portmedia/portmidi/portmusic_logo.png
PROJECT_LOGO = portmusic_logo.png

# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.

OUTPUT_DIRECTORY = doc
OUTPUT_DIRECTORY = ../github-portmidi-portmidi_docs

# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
Expand Down Expand Up @@ -871,9 +871,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.

#INPUT =/Users/rbd/portmedia/portmidi/pm_common /Users/rbd/portmedia/portmidi/porttime /Users/rbd/portmedia/portmidi/pm_linux

INPUT =pm_common/portmidi.h porttime/porttime.h pm_common/pmutil.h
INPUT =pm_common porttime/porttime.h pm_common/pmutil.h

# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
Expand Down Expand Up @@ -1233,7 +1231,7 @@ GENERATE_HTML = YES
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.

HTML_OUTPUT = html
HTML_OUTPUT = docs

# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).
Expand Down
4 changes: 2 additions & 2 deletions pm_common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ else(APPLE OR WIN32)
endif(APPLE OR WIN32)

if(APPLE)
set(PM_OSX_VERSION "10.7" CACHE STRING
"selects PM_OSX_SDK and macosx-version-min C flag")
# set(PM_OSX_VERSION "10.7" CACHE STRING
# "selects PM_OSX_SDK and macosx-version-min C flag")
set(PM_OSX_SDK "/Developer/SDKs/MacOSX${PM_OSX_VERSION}.sdk")
set(CMAKE_OSX_SYSROOT ${PM_OSC_SDK} CACHE
PATH "-isysroot parameter for compiler")
Expand Down
69 changes: 33 additions & 36 deletions pm_java/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# pm_java

find_package(Java)
message(STATUS "Java_JAVA_EXECUTABLE is " ${Java_JAVA_EXECUTABLE})
if(BUILD_PMDEFAULTS)
set(JPORTMIDICLASS JPortMidi.class JPortMidiException.class
JPortMidiApi.class)
Expand Down Expand Up @@ -34,41 +36,37 @@ if(BUILD_PMDEFAULTS)
MAIN_DEPENDENCY pmdefaults/PmDefaults.java
DEPENDS pmdefaults/PmDefaultsFrame.java
WORKING_DIRECTORY .)
add_custom_target(pmdefaults ALL
DEPENDS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/pmdefaults.jar)
# add_custom_target(pmdefaults ALL
# DEPENDS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/pmdefaults.jar)
if(UNIX)
add_custom_command(OUTPUT ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/pmdefaults.jar
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/pmdefaults
COMMAND cp pmdefaults/portmusic_logo.png .
COMMAND jar cmf pmdefaults/manifest.txt pmdefaults.jar
pmdefaults/*.class portmusic_logo.png jportmidi/*.class
COMMAND mv pmdefaults.jar ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
COMMAND rm portmusic_logo.png
# create a command to run pmdefaults:
COMMAND cp pmdefaults/pmdefaults ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
COMMAND chmod +x ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/pmdefaults
MAIN_DEPENDENCY pmdefaults/PmDefaults.class
DEPENDS ${PMDEFAULTS_ALL}
WORKING_DIRECTORY .)
project(pmdefaults NONE)
include(UseJava)
add_jar(pmdefaults
SOURCES pmdefaults/PmDefaults.java pmdefaults/PmDefaultsFrame.java
jportmidi/JPortMidi.java jportmidi/JPortMidiApi.java
jportmidi/JPortMidiException.java
RESOURCES NAMESPACE "." pmdefaults/portmusic_logo.png
MANIFEST pmdefaults/manifest.txt
OUTPUT_DIR pmdefaults)
if(BUILD_JAVA_NATIVE_INTERFACE)
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
# 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)
# 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")
set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH}/linux)
# libjvm.so is found relative to JAVA_INCLUDE_PATH:
set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../jre/lib/i386/client/libjvm.so)
endif(BUILD_JAVA_NATIVE_INTERFACE)
CACHE STRING "where to find Java SDK include directory")
set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH}/linux)
# libjvm.so is found relative to JAVA_INCLUDE_PATH:
set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../jre/lib/i386/client/libjvm.so)
endif(BUILD_JAVA_NATIVE_INTERFACE)
if(APPLE)
else(APPLE)
# install the libraries (Linux only)
Expand All @@ -92,7 +90,7 @@ if(BUILD_PMDEFAULTS)
# /MD is multithread DLL, /MT is multithread

if(BUILD_JAVA_NATIVE_INTERFACE)
include(FindJNI)
include(FindJNI)
# note: should use JAVA_JVM_LIB_PATH, but it is not set properly
set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../lib/jvm.lib)

Expand All @@ -109,10 +107,8 @@ endif(BUILD_PMDEFAULTS)
# define the jni library
include_directories(${JAVA_INCLUDE_PATHS})

set(JNISRC ${PROJECT_SOURCE_DIR}/pm_java/pmjni/pmjni.c)
set(JNISRC ${PROJECT_SOURCE_DIR}/pmjni/pmjni.c)

# THIS DID NOT WORK - REMOVE WHEN pmjni on Windows works again:
#
# note: PM_LIBSRC is all source for PortMidi, which becomes part of pmjni.
# This means there is no dependency on a separate PortMidi library, and
# pmjni can access internal PortMidi implementation variables and not
Expand All @@ -123,8 +119,9 @@ target_link_libraries(pmjni ${PM_NEEDED_LIBS})


set_target_properties(pmjni PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set_target_properties(pmjni PROPERTIES EXECUTABLE_EXTENSION "jnilib"
MACOSX_RPATH ON)
MACOSX_RPATH ON)
set(PMJNI_LIBRARY pmjni)

add_dependencies(pmdefaults pmjni)
4 changes: 3 additions & 1 deletion pm_java/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ In Windows:
[java must be executable from the command line]
cd portmidi\pm_java -- change to this directory
pmdefaults -- runs pmdefaults.bat
In macOS:
In macOS and Linux:
cd portmidi\pm_java\pmdefaults -- change to this directory
./pmdefaults -- shell script to invoke java
[java must be executable from the command line]


Expand Down
2 changes: 1 addition & 1 deletion pm_java/pmdefaults/pmdefaults
Original file line number Diff line number Diff line change
@@ -1 +1 @@
java -Djava.library.path=. -jar pmdefaults.jar > /dev/null
java -Djava.library.path=../../Release:../../Debug -jar pmdefaults.jar > /dev/null
83 changes: 75 additions & 8 deletions porttime/ptmacosx_mach.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@
#ifndef NSEC_PER_MSEC
#define NSEC_PER_MSEC 1000000
#endif
#define THREAD_IMPORTANCE 30
#define THREAD_IMPORTANCE 63

// do we ever NOT have Cocoa?
#ifndef HAVE_COCOA
#define HAVE_COCOA 1
#endif

static int time_started_flag = FALSE;
static UInt64 start_time;
Expand Down Expand Up @@ -58,19 +63,62 @@ static void *Pt_CallbackProc(void *p)
mach_error("Couldn't set thread precedence policy", error);
}

// Most important, set real-time constraints.

// Define the guaranteed and max fraction of time for the audio thread.
// These "duty cycle" values can range from 0 to 1. A value of 0.5
// means the scheduler would give half the time to the thread.
// These values have empirically been found to yield good behavior.
// Good means that audio performance is high and other threads won't starve.
const double kGuaranteedAudioDutyCycle = 0.75;
const double kMaxAudioDutyCycle = 0.85;

// Define constants determining how much time the audio thread can
// use in a given time quantum. All times are in milliseconds.

// About 128 frames @44.1KHz
const double kTimeQuantum = 2.9;

// Time guaranteed each quantum.
const double kAudioTimeNeeded = kGuaranteedAudioDutyCycle * kTimeQuantum;

// Maximum time each quantum.
const double kMaxTimeAllowed = kMaxAudioDutyCycle * kTimeQuantum;

// Get the conversion factor from milliseconds to absolute time
// which is what the time-constraints call needs.
mach_timebase_info_data_t tb_info;
mach_timebase_info(&tb_info);
double ms_to_abs_time =
((double)tb_info.denom / (double)tb_info.numer) * 1000000;

thread_time_constraint_policy_data_t time_constraints;
time_constraints.period = (uint32_t)(kTimeQuantum * ms_to_abs_time);
time_constraints.computation = (uint32_t)(kAudioTimeNeeded * ms_to_abs_time);
time_constraints.constraint = (uint32_t)(kMaxTimeAllowed * ms_to_abs_time);
time_constraints.preemptible = 0;

error = thread_policy_set(mach_thread_self(),
THREAD_TIME_CONSTRAINT_POLICY,
(thread_policy_t)&time_constraints,
THREAD_TIME_CONSTRAINT_POLICY_COUNT);
if (error != KERN_SUCCESS) {
mach_error("Couldn't set thread precedence policy", error);
}

/* to kill a process, just increment the pt_callback_proc_id */
/* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id, parameters->id); */
/* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id,
parameters->id); */
while (pt_callback_proc_id == parameters->id) {
/* wait for a multiple of resolution ms */
UInt64 wait_time;
int delay = mytime++ * parameters->resolution - Pt_Time();
PtTimestamp timestamp;
PtTimestamp timestamp;
if (delay < 0) delay = 0;
wait_time = AudioConvertNanosToHostTime((UInt64)delay * NSEC_PER_MSEC);
wait_time += AudioGetCurrentHostTime();
error = mach_wait_until(wait_time);
timestamp = Pt_Time();
mach_wait_until(wait_time);
timestamp = Pt_Time();
(*(parameters->callback))(timestamp, parameters->userData);
}
free(parameters);
Expand All @@ -93,7 +141,26 @@ PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
parms->resolution = resolution;
parms->callback = callback;
parms->userData = userData;

#ifdef HAVE_COCOA
pthread_attr_t qosAttribute;
pthread_attr_init(&qosAttribute);
pthread_attr_set_qos_class_np(&qosAttribute,
QOS_CLASS_USER_INTERACTIVE, 0);

res = pthread_create(&pt_thread_pid, &qosAttribute, Pt_CallbackProc,
parms);
#else
res = pthread_create(&pt_thread_pid, NULL, Pt_CallbackProc, parms);
#endif

struct sched_param sp;
memset(&sp, 0, sizeof(struct sched_param));
sp.sched_priority = sched_get_priority_max(SCHED_RR);
if (pthread_setschedparam(pthread_self(), SCHED_RR, &sp) == -1) {
return ptHostError;
}

if (res != 0) return ptHostError;
}

Expand All @@ -102,7 +169,7 @@ PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
}


PtError Pt_Stop()
PtError Pt_Stop(void)
{
/* printf("Pt_Stop called\n"); */
pt_callback_proc_id++;
Expand All @@ -112,13 +179,13 @@ PtError Pt_Stop()
}


int Pt_Started()
int Pt_Started(void)
{
return time_started_flag;
}


PtTimestamp Pt_Time()
PtTimestamp Pt_Time(void)
{
UInt64 clock_time, nsec_time;
clock_time = AudioGetCurrentHostTime() - start_time;
Expand Down

0 comments on commit b7267da

Please sign in to comment.