summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/portmidi/pm_mac
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/portmidi/pm_mac')
-rw-r--r--3rdparty/portmidi/pm_mac/Makefile.osx8
-rw-r--r--3rdparty/portmidi/pm_mac/README_MAC.txt231
-rw-r--r--3rdparty/portmidi/pm_mac/finddefault.c4
-rw-r--r--3rdparty/portmidi/pm_mac/osxsupport.h18
-rw-r--r--3rdparty/portmidi/pm_mac/osxsupport.m37
-rw-r--r--3rdparty/portmidi/pm_mac/pm_mac.xcodeproj/project.pbxproj594
-rw-r--r--3rdparty/portmidi/pm_mac/pmdefaults/make/build.xml87
-rw-r--r--3rdparty/portmidi/pm_mac/pmdefaults/make/find-classrefs.sh31
-rw-r--r--3rdparty/portmidi/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf14
-rw-r--r--3rdparty/portmidi/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.stringsbin220 -> 0 bytes
-rw-r--r--3rdparty/portmidi/pm_mac/pmdefaults/resources/Info.plist40
-rw-r--r--3rdparty/portmidi/pm_mac/pmdefaults/resources/Manifest1
-rw-r--r--3rdparty/portmidi/pm_mac/pmmac.c11
-rw-r--r--3rdparty/portmidi/pm_mac/pmmac.h2
-rw-r--r--3rdparty/portmidi/pm_mac/pmmacosxcm.c1310
-rw-r--r--3rdparty/portmidi/pm_mac/pmmacosxcm.h2
-rw-r--r--3rdparty/portmidi/pm_mac/readbinaryplist.c161
-rw-r--r--3rdparty/portmidi/pm_mac/readbinaryplist.h10
18 files changed, 964 insertions, 1597 deletions
diff --git a/3rdparty/portmidi/pm_mac/Makefile.osx b/3rdparty/portmidi/pm_mac/Makefile.osx
index 8c6862e28f0..e34e33a92ff 100644
--- a/3rdparty/portmidi/pm_mac/Makefile.osx
+++ b/3rdparty/portmidi/pm_mac/Makefile.osx
@@ -4,7 +4,7 @@
# Sep 2009
# NOTE: you can use
-# make -f pm_osx/Makefile.osx configuration=Release
+# make -f pm_mac/Makefile.osx configuration=Release
# to override the default Debug configuration
configuration=Release
@@ -23,12 +23,12 @@ all: $(CONFIG)/CMakeCache.txt
cd $(CONFIG); make
$(CONFIG)/CMakeCache.txt:
- rm -f CMakeCache.txt
+ rm -f $(CONFIG)/CMakeCache.txt
mkdir -p $(CONFIG)
cd $(CONFIG); cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=$(CONFIG)
-**** For instructions: make -f pm_mac\Makefile.osx help ****\n'
+**** For instructions: make -f pm_mac/Makefile.osx help ****\n'
help:
echo $$'\n\n\
@@ -63,6 +63,8 @@ cleaner: clean
rm -f pm_java/pmjni/Release/*.jnilib
cleanest: cleaner
+ rm -f Debug/CMakeCache.txt Release/CMakeCache.txt
+ rm -f CMakeCache.txt
rm -f Debug/libportmidi_s.a Release/libportmidi_s.a
rm -f pm_test/Debug/test pm_test/Debug/sysex pm_test/Debug/midithread
rm -f pm_test/Debug/latency pm_test/Debug/midithru
diff --git a/3rdparty/portmidi/pm_mac/README_MAC.txt b/3rdparty/portmidi/pm_mac/README_MAC.txt
index 1650dccecce..12cc40bbc17 100644
--- a/3rdparty/portmidi/pm_mac/README_MAC.txt
+++ b/3rdparty/portmidi/pm_mac/README_MAC.txt
@@ -1,163 +1,76 @@
README_MAC.txt for PortMidi
Roger Dannenberg
20 nov 2009
-revised 20 Sep 2010 for Xcode 3.2.4 and CMake 8.2-2
+revised 20 Sep 2010 for Xcode 4.3.2 and CMake 2.8.8
+revised Jan 2022 for the PortMidi/portmidi repo on github.com
+
+This documents how I build PortMidi for macOS. It's not the only way,
+and command-line/scripting enthusiasts will say it's not even a good
+way. Feel free to contribute your approach if you are willing to
+describe it carefully and test it.
+
+Install Xcode and the CMake application, CMake.app. I use the GUI
+version of CMake which makes it easy to see/edit variables and
+options.
+
+==== USING CMAKE ====
+
+Run CMake.app and select your portmidi repo working directory as the
+location for source and build. (Yes, I use so called "in-tree"
+builds -- it doesn't hurt, but I don't think it is necessary.)
+
+Default settings should all be fine, but select options under BUILD if
+you wish:
+
+BUILD_NATIVE_JAVA_INTERFACE and BUILD_PMDEFAULTS to build a Java-based
+GUI for setting default MIDI devices. (Otherwise, calls to
+Pm_DefaultInputDevice() and Pm_DefaultOutputDevice() will not be
+useful, but maybe you are not going to use these anyway -- up to you.)
+
+BUILD_PORTMIDI_TESTS to create some test programs. Of particular
+interest are test/mm, a handy command-line MIDI Input Monitor, and
+test/testio, a simple command-line program to send or receive some
+MIDI notes in case you need a quick test: What devices do I have? Does
+this input work? Does this output work?
+
+I disable BUILD_SHARED_LIBS and always link statically: Static linking only
+adds about 40KB to any application and then you don't have to worry
+about versions, instally, copying or finding the dynamic link library,
+etc.
+
+To make sure you link statically, I rename the library to
+libportmidi_static.a. To do this, set PM_STATIC_LIB_NAME (in CMake,
+under the "PM" group) to "portmidi_static", and of course your
+application will have to specify portmidi_static as the library to
+link to.
+
+If you are building simple command-line applications, you might want
+to enable PM_CHECK_ERRORS. If you do, then calls into the PortMidi
+library will print error messages and exit in the event of an error
+(such as trying to open a device that does not exist). This saves you
+from having to check for errors everytime you call a library function
+or getting confused when errors are detected but not reported. For
+high-quality applications, do NOT enable PM_CHECK_ERRORS -- any
+failure could immediately abort your whole application, which is not
+very friendly to users.
+
+Click on Configure (maybe a couple of times).
+
+Click on Generate and make an Xcode project.
+
+Open portmidi/portmidi.xcodeproj with Xcode and build what you
+need. The simplest thing is to build the ALL_BUILD target. Be careful
+to specify a Debug or Release depending on what you want. "ALL_BUILD"
+is a misnomer -- it only builds the version you select.
+
+PmDefaults is minimally supported and may be removed in 2023 unless we
+hear from users. To run it,
+(1) make sure java runs from the command line.
+(2) run the following command in an open Terminal:
+ cd portmidi/pm_java/pmdefaults
+ ./pmdefaults
+
+Feel free to write a short script that cd's to your pmdefaults
+directory and runs pmdefaults, and put that script somewhere on your
+path so you can type it anywhere.
-To build PortMidi for Mac OS X, you must install Xcode and
-CMake.
-
-CMake can build either command-line Makefiles or Xcode projects.
-These approaches are described in separate sections below.
-
-==== CLEANING UP ====
-(Skip this for now, but later you might want start from a clean
-slate.)
-
-Start in the portmedia/portmidi directory.
-
-make -f pm_mac/Makefile.osx clean
-
-will remove .o, CMakeFiles, and other intermediate files.
-
-Using "cleaner" instead of "clean" will also remove jni-related
-intermediate files.
-
-Using "cleanest" instead of "clean" or "cleaner" will also remove
-application binaries and the portmidi libraries. (It will not
-uninstall anything, however.)
-
-==== USING CMAKE (AND COMMAND LINE TOOLS) ====
-
-Start in the portmedia/portmidi directory.
-
-make -f pm_mac/Makefile.osx
-
-(Begin note: make will invoke cmake to build a Makefile and then make to
-build portmidi. This extra level allows you to correctly build
-both Release and Debug versions. Release is the default, so to get
-the Debug version, use:
-
-make -f pm_mac/Makefile.osx configuration=Debug
-)
-
-Release version executables and libraries are now in
- portmedia/portmidi/Release
-
-Debug version executables and libraries are created in
- portmedia/portmidi/Debug
-The Debug versions are compiled with PM_CHECK_ERRORS which
-prints an error message and aborts when an error code is returned
-by PortMidi functions. This is useful for small command line
-applications. Otherwise, you should check and handle error returns
-in your program.
-
-You can install portmidi as follows:
-
-cd Release; sudo make install
-
-This will install /usr/local/include/{portmidi.h, porttime.h}
-and /usr/local/lib/{libportmidi.dylib, libportmidi_s.a, libpmjni.dylib}
-
-You should now make the pmdefaults.app:
-
-make -f pm_mac/Makefile.osx pmdefaults
-
-NOTE: pmdefaults.app will be in pm_mac/Release/.
-
-Please copy pmdefaults.app to your Applications folder or wherever
-you would normally expect to find it.
-
-==== USING CMAKE TO BUILD Xcode PROJECT ====
-
-Before you can use Xcode, you need a portmidi.xcodeproj file.
-CMake builds a location-dependent Xcode project, so unfortunately
-it is not easy to provide an Xcode project that is ready to use.
-Therefore, you should make your own. Once you have it, you can
-use it almost like any other Xcode project, and you will not have
-to go back to CMake.
-
-(1) Install CMake if you do not have it already.
-
-(2) Open portmedia/portmidi/CMakeLists.txt with CMake
-
-(3) Use Configure and Generate buttons
-
-(4) This creates portmedia/portmidi/portmidi.xcodeproj.
-
-Note: You will also use pm_mac/pm_mac.xcodeproj, which
-is not generated by CMake.
-
-(5) Open portmidi/portmidi.xcodeproj with Xcode and
-build what you need. The simplest thing is to build the
-ALL_BUILD target. The default will be to build the Debug
-version, but you may want to change this to Release.
-
-NOTE: ALL_BUILD may report errors. Try simply building again
-or rebuilding specific targets that fail until they build
-without errors. There appears to be a race condition or
-missing dependencies in the build system.
-
-The Debug version is compiled with PM_CHECK_ERRORS, and the
-Release version is not. PM_CHECK_ERRORS will print an error
-message and exit your program if any error is returned from
-a call into PortMidi.
-
-CMake (currently) also creates MinSizRel and RelWithDebInfo
-versions, but only because I cannot figure out how to disable
-them.
-
-You will probably want the application PmDefaults, which sets
-default MIDI In and Out devices for PortMidi. You may also
-want to build a Java application using PortMidi. Since I have
-not figured out how to use CMake to make an OS X Java application,
-use pm_mac/pm_mac.xcodeproj as follows:
-
-(6) open pm_mac/pm_mac.xcodeproj
-
-(7) pm_java/pmjni/portmidi_JportmidiApi.h is needed
-by libpmjni.jnilib, the Java native interface library. Since
-portmidi_JportmidiApi.h is included with PortMidi, you can skip
-to step 8, but if you really want to rebuild everything from
-scratch, build the JPortMidiHeaders project first, and continue
-with step 8:
-
-(8) If you did not build libpmjni.dylib using portmidi.xcodeproj,
-do it now. (It depends on portmidi_JportmidiApi.h, and the
-PmDefaults project depends on libpmjni.dylib.)
-
-(9) Returning to pm_mac.xcodeproj, build the PmDefaults program.
-
-(10) If you wish, copy pm_mac/build/Deployment/PmDefaults.app to
-your applications folder.
-
-(11) If you want to install libportmidi.dylib, first make it with
-Xcode, then
- sudo make -f pm_mac/Makefile.osx install
-This command will install /usr/local/include/{porttime.h, portmidi.h}
-and /usr/local/lib/libportmidi.dylib
-Note that the "install" function of xcode creates portmidi/Release
-and does not install the library to /usr/local/lib, so please use
-the command line installer.
-
-
-CHANGELOG
-
-20-Sep-2010 Roger B. Dannenberg
- Adapted to Xcode 3.2.4
-20-Nov-2009 Roger B. Dannenberg
- Added some install instructions
-26-Sep-2009 Roger B. Dannenberg
- More changes for using CMake, Makefiles, XCode
-20-Sep-2009 Roger B. Dannenberg
- Modifications for using CMake
-14-Sep-2009 Roger B. Dannenberg
- Modifications for using CMake
-17-Jan-2007 Roger B. Dannenberg
- Explicit instructions for Xcode
-15-Jan-2007 Roger B. Dannenberg
- Changed instructions because of changes to Makefile.osx
-07-Oct-2006 Roger B. Dannenberg
- Added directions for xcodebuild
-29-aug-2006 Roger B. Dannenberg
- Updated this documentation.
-
diff --git a/3rdparty/portmidi/pm_mac/finddefault.c b/3rdparty/portmidi/pm_mac/finddefault.c
index bc95a4001a6..b4556e98d91 100644
--- a/3rdparty/portmidi/pm_mac/finddefault.c
+++ b/3rdparty/portmidi/pm_mac/finddefault.c
@@ -17,14 +17,14 @@
plist files (user and system) open at once (due to a simple
memory management scheme).
*/
-PmDeviceID find_default_device(char *path, int input, PmDeviceID id)
+PmDeviceID find_default_device(const char *path, int input, PmDeviceID id)
/* path -- the name of the preference we are searching for
input -- true iff this is an input device
id -- current default device id
returns matching device id if found, otherwise id
*/
{
- static char *pref_file = (char *)"com.apple.java.util.prefs.plist";
+ static char const *const pref_file = "com.apple.java.util.prefs.plist";
char *pref_str = NULL;
// read device preferences
value_ptr prefs = bplist_read_user_pref(pref_file);
diff --git a/3rdparty/portmidi/pm_mac/osxsupport.h b/3rdparty/portmidi/pm_mac/osxsupport.h
deleted file mode 100644
index 7771868d12a..00000000000
--- a/3rdparty/portmidi/pm_mac/osxsupport.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- osxsupport.h - Cocoa glue to emulated deprecated old Carbon path finder functions
-*/
-
-#ifndef _OSXSUPPORT_H_
-#define _OSXSUPPORT_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-char *FindPrefsDir(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/3rdparty/portmidi/pm_mac/osxsupport.m b/3rdparty/portmidi/pm_mac/osxsupport.m
deleted file mode 100644
index 1cf457f6bdb..00000000000
--- a/3rdparty/portmidi/pm_mac/osxsupport.m
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- osxsupport.m - Cocoa glue to emulated deprecated old Carbon path finder functions
-*/
-
-#import <Cocoa/Cocoa.h>
-#import <AvailabilityMacros.h>
-#include "osxsupport.h"
-
-// convert an NSString to a C string
-#ifndef OSX_PPC
-static char *StringToChar(NSString *str)
-{
- const char *charstr = [str UTF8String];
- char *resstr = (char *)malloc(strlen(charstr)+1);
-
- strcpy(resstr, charstr);
- return resstr;
-}
-
-char *FindPrefsDir(void)
-{
- char *resstr = NULL;
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSPreferencePanesDirectory, NSUserDomainMask, YES);
-
- if ([paths count] > 0)
- {
- resstr = StringToChar([paths objectAtIndex:0]) ;
- }
-
- [pool release];
-
- return resstr;
-}
-#endif
-
diff --git a/3rdparty/portmidi/pm_mac/pm_mac.xcodeproj/project.pbxproj b/3rdparty/portmidi/pm_mac/pm_mac.xcodeproj/project.pbxproj
deleted file mode 100644
index 0d06e565eae..00000000000
--- a/3rdparty/portmidi/pm_mac/pm_mac.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,594 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 44;
- objects = {
-
-/* Begin PBXAggregateTarget section */
- 3D634CAB1247805C0020F829 /* JPortMidiHeaders */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = 3D634CAE1247807A0020F829 /* Build configuration list for PBXAggregateTarget "JPortMidiHeaders" */;
- buildPhases = (
- 3D634CAA1247805C0020F829 /* ShellScript */,
- );
- dependencies = (
- 3D634CB0124781580020F829 /* PBXTargetDependency */,
- );
- name = JPortMidiHeaders;
- productName = JPortMidiHeaders;
- };
- 3DE2142D124662AA0033C839 /* CopyJavaSources */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = 3DE21434124662FF0033C839 /* Build configuration list for PBXAggregateTarget "CopyJavaSources" */;
- buildPhases = (
- 3DE2142C124662AA0033C839 /* CopyFiles */,
- );
- comments = "The reason for copying files here is that the Compile Java target looks in a particular place for sources. It would be much better to simply have Compile Java look in the original location for all sources, but I don't know how to do that. -RBD\n";
- dependencies = (
- );
- name = CopyJavaSources;
- productName = CopyJavaSources;
- };
- 89D0F1C90F3B704E007831A7 /* PmDefaults */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = 89D0F1D20F3B7080007831A7 /* Build configuration list for PBXAggregateTarget "PmDefaults" */;
- buildPhases = (
- );
- dependencies = (
- 89D0F1D10F3B7062007831A7 /* PBXTargetDependency */,
- 89D0F1CD0F3B7062007831A7 /* PBXTargetDependency */,
- 3DE21431124662C50033C839 /* PBXTargetDependency */,
- );
- name = PmDefaults;
- productName = pmdefaults;
- };
-/* End PBXAggregateTarget section */
-
-/* Begin PBXBuildFile section */
- 3DE2137F124653FB0033C839 /* portmusic_logo.png in Resources */ = {isa = PBXBuildFile; fileRef = 3DE2137E124653FB0033C839 /* portmusic_logo.png */; };
- 3DE21435124663860033C839 /* PmDefaultsFrame.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE2137D124653CB0033C839 /* PmDefaultsFrame.java */; };
- 3DE214361246638A0033C839 /* PmDefaults.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE2137B1246538B0033C839 /* PmDefaults.java */; };
- 3DE214371246638F0033C839 /* JPortMidiException.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE21382124654DE0033C839 /* JPortMidiException.java */; };
- 3DE214381246638F0033C839 /* JPortMidiApi.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE21381124654CF0033C839 /* JPortMidiApi.java */; };
- 3DE214391246638F0033C839 /* JPortMidi.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE21380124654BC0033C839 /* JPortMidi.java */; };
- 3DE216131246AC0E0033C839 /* libpmjni.dylib in Copy Java Resources */ = {isa = PBXBuildFile; fileRef = 3DE216101246ABE30033C839 /* libpmjni.dylib */; };
- 3DE216951246D57A0033C839 /* pmdefaults.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3DE216901246C6410033C839 /* pmdefaults.icns */; };
- 89C3F2920F5250A300B0048E /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 89C3F2900F5250A300B0048E /* Credits.rtf */; };
- 89D0F0240F392F20007831A7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 89D0F0210F392F20007831A7 /* InfoPlist.strings */; };
- 89D0F0410F39306C007831A7 /* JavaApplicationStub in Copy Executable */ = {isa = PBXBuildFile; fileRef = 89D0F03E0F39304A007831A7 /* JavaApplicationStub */; };
- 89D0F16A0F3A124E007831A7 /* pmdefaults.jar in Copy Java Resources */ = {isa = PBXBuildFile; fileRef = 89D0F15D0F3A0FF7007831A7 /* pmdefaults.jar */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXContainerItemProxy section */
- 3D634CAF124781580020F829 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 89D0F1C90F3B704E007831A7;
- remoteInfo = PmDefaults;
- };
- 3DE21430124662C50033C839 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 3DE2142D124662AA0033C839;
- remoteInfo = CopyJavaSources;
- };
- 3DE2145D124666900033C839 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 3DE2142D124662AA0033C839;
- remoteInfo = CopyJavaSources;
- };
- 89D0F1CC0F3B7062007831A7 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 8D1107260486CEB800E47090;
- remoteInfo = "Assemble Application";
- };
- 89D0F1D00F3B7062007831A7 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 89D0F0480F393A6F007831A7;
- remoteInfo = "Compile Java";
- };
-/* End PBXContainerItemProxy section */
-
-/* Begin PBXCopyFilesBuildPhase section */
- 3DE2142C124662AA0033C839 /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "${PROJECT_DIR}/pmdefaults/src/java";
- dstSubfolderSpec = 0;
- files = (
- 3DE21435124663860033C839 /* PmDefaultsFrame.java in CopyFiles */,
- 3DE214361246638A0033C839 /* PmDefaults.java in CopyFiles */,
- 3DE214371246638F0033C839 /* JPortMidiException.java in CopyFiles */,
- 3DE214381246638F0033C839 /* JPortMidiApi.java in CopyFiles */,
- 3DE214391246638F0033C839 /* JPortMidi.java in CopyFiles */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 89D0F0440F393070007831A7 /* Copy Executable */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "";
- dstSubfolderSpec = 6;
- files = (
- 89D0F0410F39306C007831A7 /* JavaApplicationStub in Copy Executable */,
- );
- name = "Copy Executable";
- runOnlyForDeploymentPostprocessing = 0;
- };
- 89D0F11F0F394189007831A7 /* Copy Java Resources */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "";
- dstSubfolderSpec = 15;
- files = (
- 89D0F16A0F3A124E007831A7 /* pmdefaults.jar in Copy Java Resources */,
- 3DE216131246AC0E0033C839 /* libpmjni.dylib in Copy Java Resources */,
- );
- name = "Copy Java Resources";
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXCopyFilesBuildPhase section */
-
-/* Begin PBXFileReference section */
- 3DE2137B1246538B0033C839 /* PmDefaults.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = PmDefaults.java; path = ../pm_java/pmdefaults/PmDefaults.java; sourceTree = SOURCE_ROOT; };
- 3DE2137D124653CB0033C839 /* PmDefaultsFrame.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = PmDefaultsFrame.java; path = ../pm_java/pmdefaults/PmDefaultsFrame.java; sourceTree = SOURCE_ROOT; };
- 3DE2137E124653FB0033C839 /* portmusic_logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = portmusic_logo.png; path = ../pm_java/pmdefaults/portmusic_logo.png; sourceTree = SOURCE_ROOT; };
- 3DE21380124654BC0033C839 /* JPortMidi.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = JPortMidi.java; path = ../pm_java/jportmidi/JPortMidi.java; sourceTree = SOURCE_ROOT; };
- 3DE21381124654CF0033C839 /* JPortMidiApi.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = JPortMidiApi.java; path = ../pm_java/jportmidi/JPortMidiApi.java; sourceTree = SOURCE_ROOT; };
- 3DE21382124654DE0033C839 /* JPortMidiException.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = JPortMidiException.java; path = ../pm_java/jportmidi/JPortMidiException.java; sourceTree = SOURCE_ROOT; };
- 3DE213841246555A0033C839 /* CoreMIDI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = /System/Library/Frameworks/CoreMIDI.framework; sourceTree = "<absolute>"; };
- 3DE21390124655760033C839 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
- 3DE213BE1246557F0033C839 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = "<absolute>"; };
- 3DE216101246ABE30033C839 /* libpmjni.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpmjni.dylib; path = ../Release/libpmjni.dylib; sourceTree = SOURCE_ROOT; };
- 3DE216901246C6410033C839 /* pmdefaults.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = pmdefaults.icns; path = ../pm_java/pmdefaults/pmdefaults.icns; sourceTree = SOURCE_ROOT; };
- 89C3F2910F5250A300B0048E /* English */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = English; path = English.lproj/Credits.rtf; sourceTree = "<group>"; };
- 89D0F0220F392F20007831A7 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
- 89D0F0230F392F20007831A7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
- 89D0F03E0F39304A007831A7 /* JavaApplicationStub */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = JavaApplicationStub; path = /System/Library/Frameworks/JavaVM.framework/Versions/A/Resources/MacOS/JavaApplicationStub; sourceTree = "<absolute>"; };
- 89D0F0840F394066007831A7 /* JavaNativeFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaNativeFoundation.framework; path = /System/Library/Frameworks/JavaVM.framework/Versions/A/Frameworks/JavaNativeFoundation.framework; sourceTree = "<absolute>"; };
- 89D0F1390F3948A9007831A7 /* pmdefaults/make */ = {isa = PBXFileReference; lastKnownFileType = folder; path = pmdefaults/make; sourceTree = "<group>"; };
- 89D0F15D0F3A0FF7007831A7 /* pmdefaults.jar */ = {isa = PBXFileReference; lastKnownFileType = archive.jar; name = pmdefaults.jar; path = build/Release/pmdefaults.jar; sourceTree = SOURCE_ROOT; };
- 89D0F1860F3A2442007831A7 /* JavaVM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaVM.framework; path = /System/Library/Frameworks/JavaVM.framework; sourceTree = "<absolute>"; };
- 8D1107320486CEB800E47090 /* PmDefaults.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PmDefaults.app; sourceTree = BUILT_PRODUCTS_DIR; };
-/* End PBXFileReference section */
-
-/* Begin PBXGroup section */
- 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
- isa = PBXGroup;
- children = (
- 3DE213841246555A0033C839 /* CoreMIDI.framework */,
- 3DE21390124655760033C839 /* CoreFoundation.framework */,
- 3DE213BE1246557F0033C839 /* CoreAudio.framework */,
- 89D0F1860F3A2442007831A7 /* JavaVM.framework */,
- 89D0F0840F394066007831A7 /* JavaNativeFoundation.framework */,
- );
- name = "Linked Frameworks";
- sourceTree = "<group>";
- };
- 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
- isa = PBXGroup;
- children = (
- );
- name = "Other Frameworks";
- sourceTree = "<group>";
- };
- 19C28FACFE9D520D11CA2CBB /* Products */ = {
- isa = PBXGroup;
- children = (
- 89D0F15D0F3A0FF7007831A7 /* pmdefaults.jar */,
- 8D1107320486CEB800E47090 /* PmDefaults.app */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 29B97314FDCFA39411CA2CEA /* pmdefaults */ = {
- isa = PBXGroup;
- children = (
- 3DE216101246ABE30033C839 /* libpmjni.dylib */,
- 89D0F0260F392F48007831A7 /* Source */,
- 89D0F0200F392F20007831A7 /* Resources */,
- 89D0F1390F3948A9007831A7 /* pmdefaults/make */,
- 29B97323FDCFA39411CA2CEA /* Frameworks */,
- 19C28FACFE9D520D11CA2CBB /* Products */,
- );
- name = pmdefaults;
- sourceTree = "<group>";
- };
- 29B97323FDCFA39411CA2CEA /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
- 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
- );
- name = Frameworks;
- sourceTree = "<group>";
- };
- 3DE2136A124652E20033C839 /* pm_java */ = {
- isa = PBXGroup;
- children = (
- 3DE21379124653150033C839 /* pmdefaults */,
- 3DE2137A1246531D0033C839 /* jportmidi */,
- );
- name = pm_java;
- path = ..;
- sourceTree = "<group>";
- };
- 3DE21379124653150033C839 /* pmdefaults */ = {
- isa = PBXGroup;
- children = (
- 3DE2137D124653CB0033C839 /* PmDefaultsFrame.java */,
- 3DE2137B1246538B0033C839 /* PmDefaults.java */,
- );
- name = pmdefaults;
- sourceTree = "<group>";
- };
- 3DE2137A1246531D0033C839 /* jportmidi */ = {
- isa = PBXGroup;
- children = (
- 3DE21382124654DE0033C839 /* JPortMidiException.java */,
- 3DE21381124654CF0033C839 /* JPortMidiApi.java */,
- 3DE21380124654BC0033C839 /* JPortMidi.java */,
- );
- name = jportmidi;
- sourceTree = "<group>";
- };
- 89D0F0200F392F20007831A7 /* Resources */ = {
- isa = PBXGroup;
- children = (
- 3DE216901246C6410033C839 /* pmdefaults.icns */,
- 3DE2137E124653FB0033C839 /* portmusic_logo.png */,
- 89C3F2900F5250A300B0048E /* Credits.rtf */,
- 89D0F0230F392F20007831A7 /* Info.plist */,
- 89D0F0210F392F20007831A7 /* InfoPlist.strings */,
- 89D0F03E0F39304A007831A7 /* JavaApplicationStub */,
- );
- name = Resources;
- path = pmdefaults/resources;
- sourceTree = "<group>";
- };
- 89D0F0260F392F48007831A7 /* Source */ = {
- isa = PBXGroup;
- children = (
- 3DE2136A124652E20033C839 /* pm_java */,
- );
- name = Source;
- path = pmdefaults/src;
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXLegacyTarget section */
- 89D0F0480F393A6F007831A7 /* Compile Java */ = {
- isa = PBXLegacyTarget;
- buildArgumentsString = "-e -f \"${SRCROOT}/make/build.xml\" -debug \"$ACTION\"";
- buildConfigurationList = 89D0F04B0F393AB7007831A7 /* Build configuration list for PBXLegacyTarget "Compile Java" */;
- buildPhases = (
- );
- buildToolPath = /usr/bin/ant;
- buildWorkingDirectory = "";
- dependencies = (
- 3DE2145E124666900033C839 /* PBXTargetDependency */,
- );
- name = "Compile Java";
- passBuildSettingsInEnvironment = 1;
- productName = "Compile Java";
- };
-/* End PBXLegacyTarget section */
-
-/* Begin PBXNativeTarget section */
- 8D1107260486CEB800E47090 /* Assemble Application */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Assemble Application" */;
- buildPhases = (
- 89D0F0440F393070007831A7 /* Copy Executable */,
- 89D0F11F0F394189007831A7 /* Copy Java Resources */,
- 8D1107290486CEB800E47090 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "Assemble Application";
- productInstallPath = "$(HOME)/Applications";
- productName = pmdefaults;
- productReference = 8D1107320486CEB800E47090 /* PmDefaults.app */;
- productType = "com.apple.product-type.application";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 29B97313FDCFA39411CA2CEA /* Project object */ = {
- isa = PBXProject;
- buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "pm_mac" */;
- compatibilityVersion = "Xcode 3.0";
- developmentRegion = English;
- hasScannedForEncodings = 1;
- knownRegions = (
- English,
- Japanese,
- French,
- German,
- );
- mainGroup = 29B97314FDCFA39411CA2CEA /* pmdefaults */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 3D634CAB1247805C0020F829 /* JPortMidiHeaders */,
- 89D0F1C90F3B704E007831A7 /* PmDefaults */,
- 3DE2142D124662AA0033C839 /* CopyJavaSources */,
- 89D0F0480F393A6F007831A7 /* Compile Java */,
- 8D1107260486CEB800E47090 /* Assemble Application */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- 8D1107290486CEB800E47090 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 3DE216951246D57A0033C839 /* pmdefaults.icns in Resources */,
- 89D0F0240F392F20007831A7 /* InfoPlist.strings in Resources */,
- 89C3F2920F5250A300B0048E /* Credits.rtf in Resources */,
- 3DE2137F124653FB0033C839 /* portmusic_logo.png in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXShellScriptBuildPhase section */
- 3D634CAA1247805C0020F829 /* ShellScript */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputPaths = (
- );
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "echo BUILT_PRODUCTS_DIR is ${BUILT_PRODUCTS_DIR}\njavah -classpath \"${BUILT_PRODUCTS_DIR}/pmdefaults.jar\" -force -o \"${BUILT_PRODUCTS_DIR}/jportmidi_JportMidiApi.h\" \"jportmidi.JPortMidiApi\"\nmv \"${BUILT_PRODUCTS_DIR}/jportmidi_JportMidiApi.h\" ../pm_java/pmjni/\necho \"Created ../pm_java/pmjni/jportmidi_JportMidiApi.h\"\n";
- };
-/* End PBXShellScriptBuildPhase section */
-
-/* Begin PBXTargetDependency section */
- 3D634CB0124781580020F829 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 89D0F1C90F3B704E007831A7 /* PmDefaults */;
- targetProxy = 3D634CAF124781580020F829 /* PBXContainerItemProxy */;
- };
- 3DE21431124662C50033C839 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 3DE2142D124662AA0033C839 /* CopyJavaSources */;
- targetProxy = 3DE21430124662C50033C839 /* PBXContainerItemProxy */;
- };
- 3DE2145E124666900033C839 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 3DE2142D124662AA0033C839 /* CopyJavaSources */;
- targetProxy = 3DE2145D124666900033C839 /* PBXContainerItemProxy */;
- };
- 89D0F1CD0F3B7062007831A7 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 8D1107260486CEB800E47090 /* Assemble Application */;
- targetProxy = 89D0F1CC0F3B7062007831A7 /* PBXContainerItemProxy */;
- };
- 89D0F1D10F3B7062007831A7 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 89D0F0480F393A6F007831A7 /* Compile Java */;
- targetProxy = 89D0F1D00F3B7062007831A7 /* PBXContainerItemProxy */;
- };
-/* End PBXTargetDependency section */
-
-/* Begin PBXVariantGroup section */
- 89C3F2900F5250A300B0048E /* Credits.rtf */ = {
- isa = PBXVariantGroup;
- children = (
- 89C3F2910F5250A300B0048E /* English */,
- );
- name = Credits.rtf;
- sourceTree = "<group>";
- };
- 89D0F0210F392F20007831A7 /* InfoPlist.strings */ = {
- isa = PBXVariantGroup;
- children = (
- 89D0F0220F392F20007831A7 /* English */,
- );
- name = InfoPlist.strings;
- sourceTree = "<group>";
- };
-/* End PBXVariantGroup section */
-
-/* Begin XCBuildConfiguration section */
- 3D634CAC1247805C0020F829 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_OPTIMIZATION_LEVEL = 0;
- PRODUCT_NAME = JPortMidiHeaders;
- };
- name = Debug;
- };
- 3D634CAD1247805C0020F829 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = YES;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- GCC_ENABLE_FIX_AND_CONTINUE = NO;
- PRODUCT_NAME = JPortMidiHeaders;
- ZERO_LINK = NO;
- };
- name = Release;
- };
- 3DE2142E124662AB0033C839 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_OPTIMIZATION_LEVEL = 0;
- PRODUCT_NAME = CopyJavaSources;
- };
- name = Debug;
- };
- 3DE2142F124662AB0033C839 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = YES;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- GCC_ENABLE_FIX_AND_CONTINUE = NO;
- PRODUCT_NAME = CopyJavaSources;
- ZERO_LINK = NO;
- };
- name = Release;
- };
- 89D0F0490F393A6F007831A7 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = pmdefaults;
- SRCROOT = ./pmdefaults;
- };
- name = Debug;
- };
- 89D0F04A0F393A6F007831A7 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = pmdefaults;
- SRCROOT = ./pmdefaults;
- };
- name = Release;
- };
- 89D0F1CA0F3B704F007831A7 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = pmdefaults;
- };
- name = Debug;
- };
- 89D0F1CB0F3B704F007831A7 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = pmdefaults;
- };
- name = Release;
- };
- C01FCF4B08A954540054247B /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)";
- COPY_PHASE_STRIP = NO;
- INFOPLIST_FILE = pmdefaults/resources/Info.plist;
- INSTALL_PATH = "$(HOME)/Applications";
- PRODUCT_NAME = pmdefaults;
- WRAPPER_EXTENSION = app;
- };
- name = Debug;
- };
- C01FCF4C08A954540054247B /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)";
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- INFOPLIST_FILE = pmdefaults/resources/Info.plist;
- INSTALL_PATH = "$(HOME)/Applications";
- PRODUCT_NAME = PmDefaults;
- WRAPPER_EXTENSION = app;
- };
- name = Release;
- };
- C01FCF4F08A954540054247B /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)";
- ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc";
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- PREBINDING = NO;
- };
- name = Debug;
- };
- C01FCF5008A954540054247B /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)";
- ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc";
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- PREBINDING = NO;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 3D634CAE1247807A0020F829 /* Build configuration list for PBXAggregateTarget "JPortMidiHeaders" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 3D634CAC1247805C0020F829 /* Debug */,
- 3D634CAD1247805C0020F829 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 3DE21434124662FF0033C839 /* Build configuration list for PBXAggregateTarget "CopyJavaSources" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 3DE2142E124662AB0033C839 /* Debug */,
- 3DE2142F124662AB0033C839 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 89D0F04B0F393AB7007831A7 /* Build configuration list for PBXLegacyTarget "Compile Java" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 89D0F0490F393A6F007831A7 /* Debug */,
- 89D0F04A0F393A6F007831A7 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 89D0F1D20F3B7080007831A7 /* Build configuration list for PBXAggregateTarget "PmDefaults" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 89D0F1CA0F3B704F007831A7 /* Debug */,
- 89D0F1CB0F3B704F007831A7 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Assemble Application" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- C01FCF4B08A954540054247B /* Debug */,
- C01FCF4C08A954540054247B /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- C01FCF4E08A954540054247B /* Build configuration list for PBXProject "pm_mac" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- C01FCF4F08A954540054247B /* Debug */,
- C01FCF5008A954540054247B /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
-}
diff --git a/3rdparty/portmidi/pm_mac/pmdefaults/make/build.xml b/3rdparty/portmidi/pm_mac/pmdefaults/make/build.xml
deleted file mode 100644
index bd08c682082..00000000000
--- a/3rdparty/portmidi/pm_mac/pmdefaults/make/build.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="pmdefaults" default="jar" basedir="..">
-
- <!-- Global Properties -->
- <property environment="env"/>
-
-
- <!-- building in Xcode -->
- <condition property="product" value="${env.PRODUCT_NAME}">
- <isset property="env.PRODUCT_NAME"/>
- </condition>
-
- <condition property="src" value="${env.SRCROOT}/src">
- <isset property="env.SRCROOT"/>
- </condition>
-
- <condition property="obj" value="${env.OBJECT_FILE_DIR}">
- <isset property="env.OBJECT_FILE_DIR"/>
- </condition>
-
- <condition property="dst" value="${env.BUILT_PRODUCTS_DIR}">
- <isset property="env.BUILT_PRODUCTS_DIR"/>
- </condition>
-
-
- <!-- building from the command line -->
- <condition property="src" value="src">
- <not>
- <isset property="src"/>
- </not>
- </condition>
-
- <condition property="obj" value="build/obj">
- <not>
- <isset property="obj"/>
- </not>
- </condition>
-
- <condition property="dst" value="build">
- <not>
- <isset property="dst"/>
- </not>
- </condition>
-
- <condition property="product" value="pmdefaults">
- <not>
- <isset property="product"/>
- </not>
- </condition>
-
-
- <!-- Targets -->
- <target name="init" description="Create build directories">
- <mkdir dir="${obj}/${product}"/>
- <mkdir dir="${dst}"/>
- </target>
-
- <target name="compile" depends="init" description="Compile">
- <javac destdir="${obj}/${product}" deprecation="on" source="1.5" target="1.5" fork="true" debug="true" debuglevel="lines,source">
- <src path="${src}/java"/>
- <classpath path="${src}/../lib/eawt-stubs.jar"/>
- </javac>
- </target>
-
- <target name="copy" depends="init" description="Copy resources">
-
- </target>
-
- <target name="jar" depends="compile, copy" description="Assemble Jar file">
- <jar jarfile="${dst}/${product}.jar" basedir="${obj}/${product}" manifest="resources/Manifest" index="true"/>
- </target>
-
- <target name="install" depends="jar" description="Alias for 'jar'">
- <!-- sent by Xcode -->
- </target>
-
- <target name="clean" description="Removes build directories">
- <!-- sent by Xcode -->
- <delete dir="${obj}/${product}"/>
- <delete file="${dst}/${product}.jar"/>
- </target>
-
- <target name="installhdrs" description="">
- <!-- sent by Xcode -->
- <echo>"Nothing to do for install-headers phase"</echo>
- </target>
-</project>
diff --git a/3rdparty/portmidi/pm_mac/pmdefaults/make/find-classrefs.sh b/3rdparty/portmidi/pm_mac/pmdefaults/make/find-classrefs.sh
deleted file mode 100644
index 2217580d0d3..00000000000
--- a/3rdparty/portmidi/pm_mac/pmdefaults/make/find-classrefs.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-
-# Prints all class references made by all classes in a Jar file
-# Depends on the output formatting of javap
-
-# create a temporary working directory
-dir=`mktemp -d $TMPDIR/classrefs.XXXXXX`
-
-asm_dump="$dir/asm_dump"
-all_classes="$dir/all_classes"
-
-# for each class in a Jar file, dump the full assembly
-javap -c -classpath "$1" `/usr/bin/jar tf "$1" | grep "\.class" | sort | xargs | sed -e 's/\.class//g'` > $asm_dump
-
-# dump the initial list of all classes in the Jar file
-/usr/bin/jar tf $1 | grep "\.class" | sed -e 's/\.class//g' >> $all_classes
-
-# dump all static class references
-cat $asm_dump | grep //class | awk -F"//class " '{print $2}' | sort | uniq >> $all_classes
-
-# dump all references to classes made in methods
-cat $asm_dump | grep //Method | awk -F"//Method " '{print $2}' | sort | uniq | grep "\." | awk -F"." '{print $1}' | sort | uniq >> $all_classes
-
-# dump all references to classes by direct field access
-cat $asm_dump | grep //Field | awk -F"//Field " '{print $2}' | sort | uniq | grep "\:L" | awk -F"\:L" '{print $2}' | sort | uniq | awk -F"\;" '{print $1}' >> $all_classes
-
-# sort and reformat
-sort $all_classes | uniq | grep -v "\"" | sed -e 's/\//\./g'
-
-# cleanup
-rm -rf $dir
diff --git a/3rdparty/portmidi/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf b/3rdparty/portmidi/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf
deleted file mode 100644
index 18f83781e7b..00000000000
--- a/3rdparty/portmidi/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf
+++ /dev/null
@@ -1,14 +0,0 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf320
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
-
-\f0\b\fs24 \cf0 Author:
-\b0 \
- Roger B. Dannenberg\
-\
-
-\b With special thanks to:
-\b0 \
- National Science Foundation\
-} \ No newline at end of file
diff --git a/3rdparty/portmidi/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings b/3rdparty/portmidi/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings
deleted file mode 100644
index c7e5600f98a..00000000000
--- a/3rdparty/portmidi/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings
+++ /dev/null
Binary files differ
diff --git a/3rdparty/portmidi/pm_mac/pmdefaults/resources/Info.plist b/3rdparty/portmidi/pm_mac/pmdefaults/resources/Info.plist
deleted file mode 100644
index 58bedb45013..00000000000
--- a/3rdparty/portmidi/pm_mac/pmdefaults/resources/Info.plist
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>English</string>
- <key>CFBundleExecutable</key>
- <string>JavaApplicationStub</string>
- <key>CFBundleIconFile</key>
- <string>pmdefaults.icns</string>
- <key>CFBundleIdentifier</key>
- <string></string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>PmDefaults</string>
- <key>CFBundlePackageType</key>
- <string>APPL</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>1.0</string>
- <key>CFBundleShortVersionString</key>
- <string>1.0</string>
- <key>Java</key>
- <dict>
- <key>ClassPath</key>
- <string>$JAVAROOT/pmdefaults.jar</string>
- <key>JVMVersion</key>
- <string>1.5+</string>
- <key>MainClass</key>
- <string>pmdefaults.PmDefaults</string>
- <key>Properties</key>
- <dict>
- <key>apple.laf.useScreenMenuBar</key>
- <string>true</string>
- </dict>
- </dict>
-</dict>
-</plist>
diff --git a/3rdparty/portmidi/pm_mac/pmdefaults/resources/Manifest b/3rdparty/portmidi/pm_mac/pmdefaults/resources/Manifest
deleted file mode 100644
index 5dee9b0dc13..00000000000
--- a/3rdparty/portmidi/pm_mac/pmdefaults/resources/Manifest
+++ /dev/null
@@ -1 +0,0 @@
-Main-Class: pmdefaults/PmDefaults
diff --git a/3rdparty/portmidi/pm_mac/pmmac.c b/3rdparty/portmidi/pm_mac/pmmac.c
index 8160fa02bb1..6c310022465 100644
--- a/3rdparty/portmidi/pm_mac/pmmac.c
+++ b/3rdparty/portmidi/pm_mac/pmmac.c
@@ -18,7 +18,7 @@ non-CoreMIDI devices.
PmDeviceID pm_default_input_device_id = -1;
PmDeviceID pm_default_output_device_id = -1;
-void pm_init()
+void pm_init(void)
{
PmError err = pm_macosxcm_init();
// this is set when we return to Pm_Initialize, but we need it
@@ -26,10 +26,10 @@ void pm_init()
pm_initialized = TRUE;
if (!err) {
pm_default_input_device_id = find_default_device(
- (char *)"/PortMidi/PM_RECOMMENDED_INPUT_DEVICE", TRUE,
+ "/PortMidi/PM_RECOMMENDED_INPUT_DEVICE", TRUE,
pm_default_input_device_id);
pm_default_output_device_id = find_default_device(
- (char *)"/PortMidi/PM_RECOMMENDED_OUTPUT_DEVICE", FALSE,
+ "/PortMidi/PM_RECOMMENDED_OUTPUT_DEVICE", FALSE,
pm_default_output_device_id);
}
}
@@ -41,13 +41,14 @@ void pm_term(void)
}
-PmDeviceID Pm_GetDefaultInputDeviceID()
+PmDeviceID Pm_GetDefaultInputDeviceID(void)
{
Pm_Initialize();
return pm_default_input_device_id;
}
-PmDeviceID Pm_GetDefaultOutputDeviceID() {
+PmDeviceID Pm_GetDefaultOutputDeviceID(void)
+{
Pm_Initialize();
return pm_default_output_device_id;
}
diff --git a/3rdparty/portmidi/pm_mac/pmmac.h b/3rdparty/portmidi/pm_mac/pmmac.h
index 6cc0392c3f4..6b64fff2a95 100644
--- a/3rdparty/portmidi/pm_mac/pmmac.h
+++ b/3rdparty/portmidi/pm_mac/pmmac.h
@@ -1,4 +1,4 @@
/* pmmac.h */
extern PmDeviceID pm_default_input_device_id;
-extern PmDeviceID pm_default_output_device_id; \ No newline at end of file
+extern PmDeviceID pm_default_output_device_id;
diff --git a/3rdparty/portmidi/pm_mac/pmmacosxcm.c b/3rdparty/portmidi/pm_mac/pmmacosxcm.c
index 71177dded11..81c531e033b 100644
--- a/3rdparty/portmidi/pm_mac/pmmacosxcm.c
+++ b/3rdparty/portmidi/pm_mac/pmmacosxcm.c
@@ -9,21 +9,67 @@
*/
/* Notes:
- since the input and output streams are represented by MIDIEndpointRef
- values and almost no other state, we store the MIDIEndpointRef on
- descriptors[midi->device_id].descriptor. The only other state we need
- is for errors: we need to know if there is an error and if so, what is
- the error text. We use a structure with two kinds of
- host error: "error" and "callback_error". That way, asynchronous callbacks
- do not interfere with other error information.
+
+ Since the input and output streams are represented by
+ MIDIEndpointRef values and almost no other state, we store the
+ MIDIEndpointRef on pm_descriptors[midi->device_id].descriptor.
- OS X does not seem to have an error-code-to-text function, so we will
- just use text messages instead of error codes.
+ OS X does not seem to have an error-code-to-text function, so we
+ will just use text messages instead of error codes.
+
+ Virtual device input synchronization: Once we create a virtual
+ device, it is always "on" and receiving messages, but it must drop
+ messages unless the device has been opened with Pm_OpenInput. To
+ open, the main thread should create all the data structures, then
+ call OSMemoryBarrier so that writes are observed, then set
+ is_opened = TRUE. To close without locks, we need to get the
+ callback to set is_opened to FALSE before we free data structures;
+ otherwise, there's a race condition where closing could delete
+ structures in use by the virtual_read_callback function. We send
+ 8 MIDI resets (FF) in a single packet to our own port to signal
+ the virtual_read_callback to close it. Then, we wait for the
+ callback to recognize the "close" packet and reset is_opened.
+
+ Device scanning is done when you first open an application.
+ PortMIDI does not actively update the devices. Instead, you must
+ Pm_Terminate() and Pm_Initialize(), basically starting over. But
+ CoreMIDI does not have a way to shut down(!), and even
+ MIDIClientDispose() somehow retains state (and docs say do not
+ call it even if it worked). The solution, apparently, is to
+ call CFRunLoopRunInMode(), which somehow updates CoreMIDI
+ state.
+
+ But when do we call CFRunLoopRunInMode()? I tried calling it
+ in midi_in_poll() which is called when you call Pm_Read() since
+ that is called often. I observed that this caused the program
+ to block for as long as 50ms and fairly often for 2 or 3ms.
+ What was Apple thinking? Is it really OK to design systems that
+ can only function with a tricky multi-threaded, non-blocking
+ priority-based solution, and then not provide a proof of concept
+ or documentation? Or is Apple's design really flawed? If anyone
+ at Apple reads this, please let me know -- I'm curious.
+
+ But I digress... Here's the PortMidi approach: Since
+ CFRunLoopRunInMode() is potentially a non-realtime operation,
+ we only call it in Pm_Initialize(), where other calls to look
+ up devices and device names are quite slow to begin with. Again,
+ PortMidi does not actively scan for new or deleted devices, so
+ if devices change, you won't see it until the next Pm_Terminate
+ and Pm_Initialize.
+
+ Calling CFRunLoopRunInMode() once is probably not enough. There
+ might be better way, but it seems to work to just call it 100
+ times and insert 20 1ms delays (in case some inter-process
+ communication or synchronization is going on).
+ This adds 20ms to the wall time of Pm_Initialize(), but it
+ typically runs 30ms to much more (~4s), so this has little impact.
*/
#include <stdlib.h>
-//#define CM_DEBUG 1
+/* turn on lots of debugging print statements */
+#define CM_DEBUG if (0)
+/* #define CM_DEBUG if (1) */
#include "portmidi.h"
#include "pmutil.h"
@@ -39,39 +85,101 @@
#include <CoreMIDI/MIDIServices.h>
#include <CoreAudio/HostTime.h>
#include <unistd.h>
+#include <libkern/OSAtomic.h>
#define PACKET_BUFFER_SIZE 1024
-/* maximum overall data rate (OS X limit is 15000 bytes/second) */
-#define MAX_BYTES_PER_S 14000
-
-/* Apple reports that packets are dropped when the MIDI bytes/sec
- exceeds 15000. This is computed by "tracking the number of MIDI
- bytes scheduled into 1-second buckets over the last six seconds
- and averaging these counts."
-
- This is apparently based on timestamps, not on real time, so
- we have to avoid constructing packets that schedule high speed
- output even if the actual writes are delayed (which was my first
- solution).
-
- The LIMIT_RATE symbol, if defined, enables code to modify
- timestamps as follows:
- After each packet is formed, the next allowable timestamp is
- computed as this_packet_time + this_packet_len * delay_per_byte
+/* maximum overall data rate (OS X limits MIDI rate in case there
+ * is a cycle among IAC ports.
+ */
- This is the minimum timestamp allowed in the next packet.
+#define MAX_BYTES_PER_S 5400
- Note that this distorts accurate timestamps somewhat.
+/* Apple reports that packets are dropped when the MIDI bytes/sec
+ exceeds 15000. This is computed by "tracking the number of MIDI
+ bytes scheduled into 1-second buckets over the last six seconds and
+ averaging these counts." This was confirmed in measurements
+ (2021) with pm_test/fast.c and pm_test/fastrcv.c Now, in 2022, with
+ macOS 12, pm_test/fast{rcv}.c show problems begin at 6000 bytes/sec.
+ Previously, we set MAX_BYTES_PER_S to 14000. This is reduced to
+ 5400 based on testing (which shows 5700 is too high) to fix the
+ packet loss problem that showed up with macOS 12.
+
+ Experiments show this restriction applies to IAC bus MIDI, but not
+ to hardware interfaces. (I measured 0.5 Mbps each way over USB to a
+ Teensy 3.2 microcontroller implementing a USB MIDI loopback. Maybe
+ it would get 1 Mbps one-way, which would make the CoreMIDI
+ restriction 18x slower than USB. Maybe other USB MIDI
+ implementations are faster -- USB top speed for other protocols is
+ certainly higher than 1 Mbps!)
+
+ This is apparently based on timestamps, not on real time, so we
+ have to avoid constructing packets that schedule high speed output
+ regardless of when writes occur. The solution is to alter
+ timestamps to limit data rates. This adds a slight time
+ distortion, e.g. an 11 note chord with all notes on the same
+ timestamp will be altered so that the last message is delayed by
+ 11 messages x 3 bytes/message / 5400 bytes/second = 6.1 ms.
+ Note that this is about 2x MIDI speed, but at least 18x slower
+ than USB MIDI.
+
+ Altering timestamps creates another problem, which is that a sender
+ that exceeds the maximum rate can queue up an unbounded number of
+ messages. With non-USB MIDI devices, you could be writing 5x faster
+ to CoreMIDI than the hardware interface can send, causing an
+ unbounded backlog, not to mention that the output stream will be a
+ steady byte stream (e.g., one 3-byte MIDI message every 0.55 ms),
+ losing any original timing or rhythm. PortMidi does not guarantee
+ delivery if, over the long run, you write faster than the hardware
+ can send.
+
+ The LIMIT_RATE symbol, if defined (which is the default), enables
+ code to modify timestamps for output to an IAC device as follows:
+
+ Before a packet is formed, the message timestamp is set to the
+ maximum of the PortMidi timestamp (converted to CoreMIDI time)
+ and min_next_time. After each send, min_next_time is updated to
+ the packet time + packet length * delay_per_byte, which limits
+ the scheduled bytes-per-second. Also, after each packet list
+ flush, min_next_time is updated to the maximum of min_next_time
+ and the real time, which prevents many bytes to be scheduled in
+ the past. (We could more directly just say packets are never
+ scheduled in the past, but we prefer to get the current time -- a
+ system call -- only when we perform the more expensive operation
+ of flushing packets, so that's when we update min_next_time to
+ the current real time. If we are sending a lot, we have to flush
+ a lot, so the time will be updated frequently when it matters.)
+
+ This possible adjustment to timestamps can distort accurate
+ timestamps by up to 0.556 us per 3-byte MIDI message.
+
+ Nothing blocks the sender from queueing up an arbitrary number of
+ messages. Timestamps should be used for accurate timing by sending
+ timestamped messages a little ahead of real time, not for
+ scheduling an entire MIDI sequence at once!
*/
#define LIMIT_RATE 1
#define SYSEX_BUFFER_SIZE 128
+/* What is the maximum PortMidi device number for an IAC device? A
+ * cleaner design would be to not use the endpoint as our device
+ * representation. Instead, we could have a private extensible struct
+ * to keep all device information, including whether the device is
+ * implemented with the AppleMIDIIACDriver, which we need because we
+ * have to limit the data rate to this particular driver to avoid
+ * dropping messages. Rather than rewrite a lot of code, I am just
+ * allocating 64 bytes to flag which devices are IAC ones. If an IAC
+ * device number is greater than 63, PortMidi will fail to limit
+ * writes to it, but will not complain and will not access memory
+ * outside the 64-element array of char.
+ */
+#define MAX_IAC_NUM 63
#define VERBOSE_ON 1
#define VERBOSE if (VERBOSE_ON)
-#define MIDI_SYSEX 0xf0
-#define MIDI_EOX 0xf7
+#define MIDI_SYSEX 0xf0
+#define MIDI_EOX 0xf7
+#define MIDI_CLOCK 0xf8
#define MIDI_STATUS_MASK 0x80
// "Ref"s are pointers on 32-bit machines and ints on 64 bit machines
@@ -82,18 +190,17 @@
#define NULL_REF NULL
#endif
-static MIDIClientRef client = NULL_REF; /* Client handle to the MIDI server */
-static MIDIPortRef portIn = NULL_REF; /* Input port handle */
-static MIDIPortRef portOut = NULL_REF; /* Output port handle */
+static MIDIClientRef client = NULL_REF; /* Client handle to the MIDI server */
+static MIDIPortRef portIn = NULL_REF; /* Input port handle */
+static MIDIPortRef portOut = NULL_REF; /* Output port handle */
+static char isIAC[MAX_IAC_NUM + 1]; /* is device an IAC device */
extern pm_fns_node pm_macosx_in_dictionary;
extern pm_fns_node pm_macosx_out_dictionary;
-typedef struct midi_macosxcm_struct {
- PmTimestamp sync_time; /* when did we last determine delta? */
+typedef struct coremidi_info_struct {
+ int is_virtual; /* virtual device (TRUE) or actual device (FALSE)? */
UInt64 delta; /* difference between stream time and real time in ns */
- UInt64 last_time; /* last output time in host units*/
- int first_message; /* tells midi_write to sychronize timestamps */
int sysex_mode; /* middle of sending sysex */
uint32_t sysex_word; /* accumulate data when receiving sysex */
uint32_t sysex_byte_count; /* count how many received */
@@ -103,26 +210,34 @@ typedef struct midi_macosxcm_struct {
MIDIPacketList *packetList; /* a pointer to packetBuffer */
MIDIPacket *packet;
Byte sysex_buffer[SYSEX_BUFFER_SIZE]; /* temp storage for sysex data */
- MIDITimeStamp sysex_timestamp; /* timestamp to use with sysex data */
+ MIDITimeStamp sysex_timestamp; /* host timestamp to use with sysex data */
/* allow for running status (is running status possible here? -rbd): -cpr */
unsigned char last_command;
int32_t last_msg_length;
- /* limit midi data rate (a CoreMidi requirement): */
- UInt64 min_next_time; /* when can the next send take place? */
- int byte_count; /* how many bytes in the next packet list? */
+ UInt64 min_next_time; /* when can the next send take place? (host time) */
+ int isIACdevice;
Float64 us_per_host_tick; /* host clock frequency, units of min_next_time */
UInt64 host_ticks_per_byte; /* host clock units per byte at maximum rate */
-} midi_macosxcm_node, *midi_macosxcm_type;
+} coremidi_info_node, *coremidi_info_type;
/* private function declarations */
-MIDITimeStamp timestamp_pm_to_cm(PmTimestamp timestamp);
-PmTimestamp timestamp_cm_to_pm(MIDITimeStamp timestamp);
+MIDITimeStamp timestamp_pm_to_cm(PmTimestamp timestamp); // returns host time
+PmTimestamp timestamp_cm_to_pm(MIDITimeStamp timestamp); // returns ms
-char* cm_get_full_endpoint_name(MIDIEndpointRef endpoint);
+char* cm_get_full_endpoint_name(MIDIEndpointRef endpoint, int *isIAC);
+
+static PmError check_hosterror(OSStatus err, const char *msg)
+{
+ if (err != noErr) {
+ sprintf(pm_hosterror_text, "Host error %ld: %s", (long) err, msg);
+ pm_hosterror = TRUE;
+ return pmHostError;
+ }
+ return pmNoError;
+}
-static int
-midi_length(int32_t msg)
+static int midi_length(int32_t msg)
{
int status, high, low;
static int high_lengths[] = {
@@ -143,31 +258,31 @@ midi_length(int32_t msg)
static PmTimestamp midi_synchronize(PmInternal *midi)
{
- midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
- UInt64 pm_stream_time_2 =
+ coremidi_info_type info = (coremidi_info_type) midi->api_info;
+ UInt64 pm_stream_time_2 = // current time in ns
AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
- PmTimestamp real_time;
- UInt64 pm_stream_time;
+ PmTimestamp real_time; // in ms
+ UInt64 pm_stream_time; // in ns
/* if latency is zero and this is an output, there is no
time reference and midi_synchronize should never be called */
assert(midi->time_proc);
- assert(!(midi->write_flag && midi->latency == 0));
+ assert(midi->is_input || midi->latency != 0);
do {
/* read real_time between two reads of stream time */
pm_stream_time = pm_stream_time_2;
real_time = (*midi->time_proc)(midi->time_info);
- pm_stream_time_2 = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
+ pm_stream_time_2 = AudioConvertHostTimeToNanos(
+ AudioGetCurrentHostTime());
/* repeat if more than 0.5 ms has elapsed */
} while (pm_stream_time_2 > pm_stream_time + 500000);
- m->delta = pm_stream_time - ((UInt64) real_time * (UInt64) 1000000);
- m->sync_time = real_time;
+ info->delta = pm_stream_time - ((UInt64) real_time * (UInt64) 1000000);
+ midi->sync_time = real_time;
return real_time;
}
-static void
-process_packet(MIDIPacket *packet, PmEvent *event,
- PmInternal *midi, midi_macosxcm_type m)
+static void process_packet(MIDIPacket *packet, PmEvent *event,
+ PmInternal *midi, coremidi_info_type info)
{
/* handle a packet of MIDI messages from CoreMIDI */
/* there may be multiple short messages in one packet (!) */
@@ -176,9 +291,9 @@ process_packet(MIDIPacket *packet, PmEvent *event,
while (remaining_length > 0) {
if (cur_packet_data[0] == MIDI_SYSEX ||
/* are we in the middle of a sysex message? */
- (m->last_command == 0 &&
+ (info->last_command == 0 &&
!(cur_packet_data[0] & MIDI_STATUS_MASK))) {
- m->last_command = 0; /* no running status */
+ info->last_command = 0; /* no running status */
unsigned int amt = pm_read_bytes(midi, cur_packet_data,
remaining_length,
event->timestamp);
@@ -188,7 +303,7 @@ process_packet(MIDIPacket *packet, PmEvent *event,
/* this should never happen, because pm_read_bytes should
* get and read all EOX bytes*/
midi->sysex_in_progress = FALSE;
- m->last_command = 0;
+ info->last_command = 0;
} else if (cur_packet_data[0] & MIDI_STATUS_MASK) {
/* compute the length of the next (short) msg in packet */
unsigned int cur_message_length = midi_length(cur_packet_data[0]);
@@ -199,8 +314,15 @@ process_packet(MIDIPacket *packet, PmEvent *event,
/* since there's no more data, we're done */
return;
}
- m->last_msg_length = cur_message_length;
- m->last_command = cur_packet_data[0];
+ if (cur_packet_data[0] < MIDI_SYSEX) {
+ /* channel messages set running status */
+ info->last_command = cur_packet_data[0];
+ info->last_msg_length = cur_message_length;
+ } else if (cur_packet_data[0] < MIDI_CLOCK) {
+ /* system messages clear running status */
+ info->last_command = 0;
+ info->last_msg_length = 0;
+ }
switch (cur_message_length) {
case 1:
event->message = Pm_Message(cur_packet_data[0], 0, 0);
@@ -220,9 +342,9 @@ process_packet(MIDIPacket *packet, PmEvent *event,
return; /* give up on packet if continued after assert */
}
pm_read_short(midi, event);
- remaining_length -= m->last_msg_length;
- cur_packet_data += m->last_msg_length;
- } else if (m->last_msg_length > remaining_length + 1) {
+ remaining_length -= cur_message_length;
+ cur_packet_data += cur_message_length;
+ } else if (info->last_msg_length > remaining_length + 1) {
/* we have running status, but not enough data */
#ifdef DEBUG
printf("PortMidi debug msg: not enough data in CoreMIDI packet");
@@ -230,427 +352,588 @@ process_packet(MIDIPacket *packet, PmEvent *event,
/* since there's no more data, we're done */
return;
} else { /* output message using running status */
- switch (m->last_msg_length) {
+ switch (info->last_msg_length) {
case 1:
- event->message = Pm_Message(m->last_command, 0, 0);
+ event->message = Pm_Message(info->last_command, 0, 0);
break;
case 2:
- event->message = Pm_Message(m->last_command,
+ event->message = Pm_Message(info->last_command,
cur_packet_data[0], 0);
break;
case 3:
- event->message = Pm_Message(m->last_command,
+ event->message = Pm_Message(info->last_command,
cur_packet_data[0],
cur_packet_data[1]);
break;
default:
/* last_msg_length is invalid -- internal PortMIDI error */
- assert(m->last_msg_length == 1);
+ assert(info->last_msg_length == 1);
}
pm_read_short(midi, event);
- remaining_length -= (m->last_msg_length - 1);
- cur_packet_data += (m->last_msg_length - 1);
+ remaining_length -= (info->last_msg_length - 1);
+ cur_packet_data += (info->last_msg_length - 1);
}
}
}
-
/* called when MIDI packets are received */
-static void
-readProc(const MIDIPacketList *newPackets, void *refCon, void *connRefCon)
+static void read_callback(const MIDIPacketList *newPackets, PmInternal *midi)
{
- PmInternal *midi;
- midi_macosxcm_type m;
PmEvent event;
MIDIPacket *packet;
unsigned int packetIndex;
uint32_t now;
unsigned int status;
-
-#ifdef CM_DEBUG
- printf("readProc: numPackets %d: ", newPackets->numPackets);
-#endif
-
/* Retrieve the context for this connection */
- midi = (PmInternal *) connRefCon;
- m = (midi_macosxcm_type) midi->descriptor;
- assert(m);
+ coremidi_info_type info = (coremidi_info_type) midi->api_info;
+ assert(info);
+
+ CM_DEBUG printf("read_callback: numPackets %d: ", newPackets->numPackets);
/* synchronize time references every 100ms */
now = (*midi->time_proc)(midi->time_info);
- if (m->first_message || m->sync_time + 100 /*ms*/ < now) {
+ if (midi->first_message || midi->sync_time + 100 /*ms*/ < now) {
/* time to resync */
now = midi_synchronize(midi);
- m->first_message = FALSE;
+ midi->first_message = FALSE;
}
packet = (MIDIPacket *) &newPackets->packet[0];
- /* printf("readproc packet status %x length %d\n", packet->data[0],
- packet->length); */
+ /* hardware devices get untimed messages and apply timestamps. We
+ * want to preserve them because they should be more accurate than
+ * applying the current time here. virtual devices just pass on the
+ * packet->timeStamp, which could be anything. PortMidi says the
+ * PortMidi timestamp is the time the message is received. We do not
+ * know if we are receiving from a device driver or a virtual device.
+ * PortMidi sends to virtual devices get a current timestamp, so we
+ * can treat them as the receive time. If the timestamp is zero,
+ * suggested by CoreMIDI as the value to use for immediate delivery,
+ * then we plug in `now` which is obtained above. If another
+ * application sends bogus non-zero timestamps, we will convert them
+ * to this port's reference time and pass them as event.timestamp.
+ * Receiver beware.
+ */
+ CM_DEBUG printf("read_callback packet @ %lld ns (host %lld) "
+ "status %x length %d\n",
+ AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()),
+ AudioGetCurrentHostTime(),
+ packet->data[0], packet->length);
for (packetIndex = 0; packetIndex < newPackets->numPackets; packetIndex++) {
/* Set the timestamp and dispatch this message */
- event.timestamp = (PmTimestamp) /* explicit conversion */ (
- (AudioConvertHostTimeToNanos(packet->timeStamp) - m->delta) /
+ CM_DEBUG printf(" packet->timeStamp %lld ns %lld host\n",
+ packet->timeStamp,
+ AudioConvertHostTimeToNanos(packet->timeStamp));
+ if (packet->timeStamp == 0) {
+ event.timestamp = now;
+ } else {
+ event.timestamp = (PmTimestamp) /* explicit conversion */ (
+ (AudioConvertHostTimeToNanos(packet->timeStamp) - info->delta) /
(UInt64) 1000000);
+ }
status = packet->data[0];
/* process packet as sysex data if it begins with MIDI_SYSEX, or
MIDI_EOX or non-status byte with no running status */
-#ifdef CM_DEBUG
- printf(" %d", packet->length);
-#endif
+ CM_DEBUG printf(" len %d stat %x\n", packet->length, status);
if (status == MIDI_SYSEX || status == MIDI_EOX ||
- ((!(status & MIDI_STATUS_MASK)) && !m->last_command)) {
- /* previously was: !(status & MIDI_STATUS_MASK)) {
+ ((!(status & MIDI_STATUS_MASK)) && !info->last_command)) {
+ /* previously was: !(status & MIDI_STATUS_MASK)) {
* but this could mistake running status for sysex data
*/
/* reset running status data -cpr */
- m->last_command = 0;
- m->last_msg_length = 0;
+ info->last_command = 0;
+ info->last_msg_length = 0;
/* printf("sysex packet length: %d\n", packet->length); */
pm_read_bytes(midi, packet->data, packet->length, event.timestamp);
} else {
- process_packet(packet, &event, midi, m);
+ process_packet(packet, &event, midi, info);
}
packet = MIDIPacketNext(packet);
}
-#ifdef CM_DEBUG
- printf("\n");
-#endif
}
-static PmError
-midi_in_open(PmInternal *midi, void *driverInfo)
+/* callback for real devices - redirects to read_callback */
+static void device_read_callback(const MIDIPacketList *newPackets,
+ void *refCon, void *connRefCon)
+{
+ read_callback(newPackets, (PmInternal *) connRefCon);
+}
+
+
+/* callback for virtual devices - redirects to read_callback */
+static void virtual_read_callback(const MIDIPacketList *newPackets,
+ void *refCon, void *connRefCon)
+{
+ /* this refCon is the device ID -- if there is a valid ID and
+ the pm_descriptors table has a non-null pointer to a PmInternal,
+ then then device is open and should receive this data */
+ PmDeviceID id = (PmDeviceID) (size_t) refCon;
+ if (id >= 0 && id < pm_descriptor_len) {
+ if (pm_descriptors[id].pub.opened) {
+ /* check for close request (7 reset status bytes): */
+ if (newPackets->numPackets == 1 &&
+ newPackets->packet[0].length == 8 &&
+ /* CoreMIDI declares packets with 4-byte alignment, so we
+ * should be safe to test for 8 0xFF's as 2 32-bit values: */
+ *(SInt32 *) &newPackets->packet[0].data[0] == -1 &&
+ *(SInt32 *) &newPackets->packet[0].data[4] == -1) {
+ CM_DEBUG printf("got close request packet\n");
+ pm_descriptors[id].pub.opened = FALSE;
+ return;
+ } else {
+ read_callback(newPackets, pm_descriptors[id].pm_internal);
+ }
+ }
+ }
+}
+
+
+/* allocate and initialize our internal coremidi connection info */
+static coremidi_info_type create_macosxcm_info(int is_virtual, int is_input)
+{
+ coremidi_info_type info = (coremidi_info_type)
+ pm_alloc(sizeof(coremidi_info_node));
+ if (!info) {
+ return NULL;
+ }
+ info->is_virtual = is_virtual;
+ info->delta = 0;
+ info->sysex_mode = FALSE;
+ info->sysex_word = 0;
+ info->sysex_byte_count = 0;
+ info->packet = NULL;
+ info->last_command = 0;
+ info->last_msg_length = 0;
+ info->min_next_time = 0;
+ info->isIACdevice = FALSE;
+ info->us_per_host_tick = 1000000.0 / AudioGetHostClockFrequency();
+ info->host_ticks_per_byte =
+ (UInt64) (1000000.0 / (info->us_per_host_tick * MAX_BYTES_PER_S));
+ info->packetList = (is_input ? NULL :
+ (MIDIPacketList *) info->packetBuffer);
+ return info;
+}
+
+
+static PmError midi_in_open(PmInternal *midi, void *driverInfo)
{
MIDIEndpointRef endpoint;
- midi_macosxcm_type m;
+ coremidi_info_type info;
OSStatus macHostError;
+ int is_virtual = pm_descriptors[midi->device_id].pub.is_virtual;
- /* insure that we have a time_proc for timing */
- if (midi->time_proc == NULL) {
- if (!Pt_Started())
- Pt_Start(1, 0, 0);
- /* time_get does not take a parameter, so coerce */
- midi->time_proc = (PmTimeProcPtr) Pt_Time;
- }
- endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
- if (endpoint == NULL_REF) {
- return pmInvalidDeviceId;
+ /* if this is an external device, descriptor is a MIDIEndpointRef.
+ * if this is a virtual device for this application, descriptor is NULL.
+ */
+ if (!is_virtual) {
+ endpoint = (MIDIEndpointRef) (intptr_t)
+ pm_descriptors[midi->device_id].descriptor;
+ if (endpoint == NULL_REF) {
+ return pmInvalidDeviceId;
+ }
}
- m = (midi_macosxcm_type) pm_alloc(sizeof(midi_macosxcm_node)); /* create */
- midi->descriptor = m;
- if (!m) {
+ info = create_macosxcm_info(is_virtual, TRUE);
+ midi->api_info = info;
+ if (!info) {
return pmInsufficientMemory;
}
- m->error[0] = 0;
- m->callback_error[0] = 0;
- m->sync_time = 0;
- m->delta = 0;
- m->last_time = 0;
- m->first_message = TRUE;
- m->sysex_mode = FALSE;
- m->sysex_word = 0;
- m->sysex_byte_count = 0;
- m->packetList = NULL;
- m->packet = NULL;
- m->last_command = 0;
- m->last_msg_length = 0;
-
- macHostError = MIDIPortConnectSource(portIn, endpoint, midi);
- if (macHostError != noErr) {
- pm_hosterror = macHostError;
- sprintf(pm_hosterror_text,
- "Host error %ld: MIDIPortConnectSource() in midi_in_open()",
- (long) macHostError);
- midi->descriptor = NULL;
- pm_free(m);
- return pmHostError;
+ if (!is_virtual) {
+ macHostError = MIDIPortConnectSource(portIn, endpoint, midi);
+ if (macHostError != noErr) {
+ midi->api_info = NULL;
+ pm_free(info);
+ return check_hosterror(macHostError,
+ "MIDIPortConnectSource() in midi_in_open()");
+ }
}
-
return pmNoError;
}
-static PmError
-midi_in_close(PmInternal *midi)
+static PmError midi_in_close(PmInternal *midi)
{
MIDIEndpointRef endpoint;
OSStatus macHostError;
PmError err = pmNoError;
- midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
+ coremidi_info_type info = (coremidi_info_type) midi->api_info;
- if (!m) return pmBadPtr;
+ if (!info) return pmBadPtr;
- endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
+ endpoint = (MIDIEndpointRef) (intptr_t)
+ pm_descriptors[midi->device_id].descriptor;
if (endpoint == NULL_REF) {
- pm_hosterror = pmBadPtr;
+ return pmBadPtr;
}
- /* shut off the incoming messages before freeing data structures */
- macHostError = MIDIPortDisconnectSource(portIn, endpoint);
- if (macHostError != noErr) {
- pm_hosterror = macHostError;
- sprintf(pm_hosterror_text,
- "Host error %ld: MIDIPortDisconnectSource() in midi_in_close()",
- (long) macHostError);
- err = pmHostError;
+ if (!info->is_virtual) {
+ /* shut off the incoming messages before freeing data structures */
+ macHostError = MIDIPortDisconnectSource(portIn, endpoint);
+ /* If the source closes, you get paramErr == -50 here. It seems
+ * possible to monitor changes like sources closing by getting
+ * notifications ALL changes, but the CoreMIDI documentation is
+ * really terrible overall, and it seems easier to just ignore
+ * this host error.
+ */
+ if (macHostError != noErr && macHostError != -50) {
+ pm_hosterror = TRUE;
+ err = check_hosterror(macHostError,
+ "MIDIPortDisconnectSource() in midi_in_close()");
+ }
+ } else {
+ /* make "close virtual port" message */
+ SInt64 close_port_bytes = 0xFFFFFFFFFFFFFFFF;
+ /* memory requirements: packet count (4), timestamp (8), length (2),
+ * data (8). Total: 22, but we allocate plenty more:
+ */
+ Byte packetBuffer[64];
+ MIDIPacketList *plist = (MIDIPacketList *) packetBuffer;
+ MIDIPacket *packet = MIDIPacketListInit(plist);
+ MIDIPacketListAdd(plist, 64, packet, 0, 8,
+ (const Byte *) &close_port_bytes);
+ macHostError = MIDISend(portOut, endpoint, plist);
+ if (macHostError != noErr) {
+ err = check_hosterror(macHostError, "MIDISend() (PortMidi close "
+ "port packet) in midi_in_close()");
+ }
+ /* when packet is delivered, callback thread will clear opened;
+ * we must wait for that before removing the input queues etc.
+ * Maybe this could use signals of some kind, but if signals use
+ * locks, locks can cause priority inversion problems, so we will
+ * just sleep as needed. On the MIDI timescale, inserting a 0.5ms
+ * latency should be OK, as the application has no business
+ * opening/closing devices during time-critical moments.
+ *
+ * We expect the MIDI thread to close the device quickly (<0.5ms),
+ * but we wait up to 50ms in case something terrible happens like
+ * getting paged out in the middle of deliving packets to this
+ * virtual device. If there is still no response, we time out and
+ * force the close without the MIDI thread (even this will probably
+ * succeed - the problem would be: this thread proceeds to delete
+ * the input queues, and the freed memory is reallocated and
+ * overwritten so that queues are no longer usable. Meanwhile,
+ * the MIDI thread has already begun to deliver packets, so the
+ * check for opened == TRUE passed, but MIDI thread does not insert
+ * into queue until queue is freed, reallocated and overwritten.
+ */
+ for (int i = 0; i < 100; i++) { /* up to 50ms delay */
+ if (!pm_descriptors[midi->device_id].pub.opened) {
+ break;
+ }
+ usleep(500); /* 0.5ms */
+ }
+ pm_descriptors[midi->device_id].pub.opened = FALSE; /* force it */
}
-
- midi->descriptor = NULL;
- pm_free(midi->descriptor);
-
+ midi->api_info = NULL;
+ pm_free(info);
return err;
}
-static PmError
-midi_out_open(PmInternal *midi, void *driverInfo)
+static PmError midi_out_open(PmInternal *midi, void *driverInfo)
{
- midi_macosxcm_type m;
+ coremidi_info_type info;
+ int is_virtual = pm_descriptors[midi->device_id].pub.is_virtual;
- m = (midi_macosxcm_type) pm_alloc(sizeof(midi_macosxcm_node)); /* create */
- midi->descriptor = m;
- if (!m) {
+ info = create_macosxcm_info(is_virtual, FALSE);
+ if (midi->device_id <= MAX_IAC_NUM) {
+ info->isIACdevice = isIAC[midi->device_id];
+ CM_DEBUG printf("midi_out_open isIACdevice %d\n", info->isIACdevice);
+ }
+ midi->api_info = info;
+ if (!info) {
return pmInsufficientMemory;
}
- m->error[0] = 0;
- m->callback_error[0] = 0;
- m->sync_time = 0;
- m->delta = 0;
- m->last_time = 0;
- m->first_message = TRUE;
- m->sysex_mode = FALSE;
- m->sysex_word = 0;
- m->sysex_byte_count = 0;
- m->packetList = (MIDIPacketList *) m->packetBuffer;
- m->packet = NULL;
- m->last_command = 0;
- m->last_msg_length = 0;
- m->min_next_time = 0;
- m->byte_count = 0;
- m->us_per_host_tick = 1000000.0 / AudioGetHostClockFrequency();
- m->host_ticks_per_byte = (UInt64) (1000000.0 /
- (m->us_per_host_tick * MAX_BYTES_PER_S));
return pmNoError;
}
-static PmError
-midi_out_close(PmInternal *midi)
+static PmError midi_out_close(PmInternal *midi)
{
- midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
- if (!m) return pmBadPtr;
-
- midi->descriptor = NULL;
- pm_free(midi->descriptor);
-
+ coremidi_info_type info = (coremidi_info_type) midi->api_info;
+ if (!info) return pmBadPtr;
+ midi->api_info = NULL;
+ pm_free(info);
return pmNoError;
}
-static PmError
-midi_abort(PmInternal *midi)
+
+/* MIDIDestinationCreate apparently cannot create a virtual device
+ * without a callback and a "refCon" parameter, but when we create
+ * a virtual device, we do not want a PortMidi stream yet -- that
+ * should wait for the user to open the stream. So, for the refCon,
+ * use the PortMidi device ID. The callback will check if the
+ * device is opened within PortMidi, and if so, use the pm_descriptors
+ * table to locate the corresponding PmStream.
+ */
+static PmError midi_create_virtual(int is_input, const char *name,
+ void *device_info)
{
- PmError err = pmNoError;
OSStatus macHostError;
- MIDIEndpointRef endpoint =
- (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
- macHostError = MIDIFlushOutput(endpoint);
+ MIDIEndpointRef endpoint;
+ CFStringRef nameRef;
+ PmDeviceID id = pm_add_device("CoreMIDI", name, is_input, TRUE, NULL,
+ (is_input ? &pm_macosx_in_dictionary :
+ &pm_macosx_out_dictionary));
+ if (id < 0) { /* error -- out of memory or name conflict? */
+ return id;
+ }
+
+ nameRef = CFStringCreateWithCString(NULL, name, kCFStringEncodingASCII);
+ if (is_input) {
+ macHostError = MIDIDestinationCreate(client, nameRef,
+ virtual_read_callback, (void *) (intptr_t) id,
+ &endpoint);
+ } else {
+ macHostError = MIDISourceCreate(client, nameRef, &endpoint);
+ }
+ CFRelease(nameRef);
+
if (macHostError != noErr) {
- pm_hosterror = macHostError;
- sprintf(pm_hosterror_text,
- "Host error %ld: MIDIFlushOutput()", (long) macHostError);
- err = pmHostError;
+ /* undo the device we just allocated */
+ pm_undo_add_device(id);
+ return check_hosterror(macHostError, (is_input ?
+ "MIDIDestinationCreate() in midi_create_virtual()" :
+ "MIDISourceCreate() in midi_create_virtual()"));
}
- return err;
+ pm_descriptors[id].descriptor = (void *) (intptr_t) endpoint;
+ return id;
}
-static PmError
-midi_write_flush(PmInternal *midi, PmTimestamp timestamp)
+static PmError midi_delete_virtual(PmDeviceID id)
{
+ MIDIEndpointRef endpoint;
OSStatus macHostError;
- midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
- MIDIEndpointRef endpoint =
- (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
- assert(m);
+ PmError err = pmNoError;
+
+ endpoint = (MIDIEndpointRef) (long) pm_descriptors[id].descriptor;
+ if (endpoint == NULL_REF) {
+ return pmBadPtr;
+ }
+ macHostError = MIDIEndpointDispose(endpoint);
+ return check_hosterror(macHostError,
+ "MIDIEndpointDispose() in midi_in_close()");
+}
+
+
+static PmError midi_abort(PmInternal *midi)
+{
+ PmError err = pmNoError;
+ OSStatus macHostError;
+ MIDIEndpointRef endpoint = (MIDIEndpointRef) (intptr_t)
+ pm_descriptors[midi->device_id].descriptor;
+ macHostError = MIDIFlushOutput(endpoint);
+ return check_hosterror(macHostError,
+ "MIDIFlushOutput() in midi_abort()");
+}
+
+
+static PmError midi_write_flush(PmInternal *midi, PmTimestamp timestamp)
+{
+ OSStatus macHostError = noErr;
+ coremidi_info_type info = (coremidi_info_type) midi->api_info;
+ MIDIEndpointRef endpoint = (MIDIEndpointRef) (intptr_t)
+ pm_descriptors[midi->device_id].descriptor;
+ assert(info);
assert(endpoint);
- if (m->packet != NULL) {
+ if (info->packet != NULL) {
/* out of space, send the buffer and start refilling it */
- /* before we can send, maybe delay to limit data rate. OS X allows
- * 15KB/s. */
- UInt64 now = AudioGetCurrentHostTime();
- if (now < m->min_next_time) {
- usleep((useconds_t)
- ((m->min_next_time - now) * m->us_per_host_tick));
+ /* update min_next_time each flush to support rate limit */
+ UInt64 host_now = AudioGetCurrentHostTime();
+ if (host_now > info->min_next_time)
+ info->min_next_time = host_now;
+ if (info->is_virtual) {
+ macHostError = MIDIReceived(endpoint, info->packetList);
+ } else {
+ macHostError = MIDISend(portOut, endpoint, info->packetList);
}
- macHostError = MIDISend(portOut, endpoint, m->packetList);
- m->packet = NULL; /* indicate no data in packetList now */
- m->min_next_time = now + m->byte_count * m->host_ticks_per_byte;
- m->byte_count = 0;
- if (macHostError != noErr) goto send_packet_error;
+ info->packet = NULL; /* indicate no data in packetList now */
}
- return pmNoError;
-
-send_packet_error:
- pm_hosterror = macHostError;
- sprintf(pm_hosterror_text,
- "Host error %ld: MIDISend() in midi_write()",
- (long) macHostError);
- return pmHostError;
-
+ return check_hosterror(macHostError, (info->is_virtual ?
+ "MIDIReceived() in midi_write()" :
+ "MIDISend() in midi_write()"));
}
-static PmError
-send_packet(PmInternal *midi, Byte *message, unsigned int messageLength,
- MIDITimeStamp timestamp)
+static PmError send_packet(PmInternal *midi, Byte *message,
+ unsigned int messageLength, MIDITimeStamp timestamp)
{
PmError err;
- midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
- assert(m);
+ coremidi_info_type info = (coremidi_info_type) midi->api_info;
+ assert(info);
- /* printf("add %d to packet %p len %d\n", message[0], m->packet, messageLength); */
- m->packet = MIDIPacketListAdd(m->packetList, sizeof(m->packetBuffer),
- m->packet, timestamp, messageLength,
- message);
- m->byte_count += messageLength;
- if (m->packet == NULL) {
+ CM_DEBUG printf("add %d to packet %p len %d timestamp %lld @ %lld ns "
+ "(host %lld)\n",
+ message[0], info->packet, messageLength, timestamp,
+ AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()),
+ AudioGetCurrentHostTime());
+ info->packet = MIDIPacketListAdd(info->packetList,
+ sizeof(info->packetBuffer), info->packet,
+ timestamp, messageLength, message);
+#if defined(LIMIT_SEND_RATE) && (LIMIT_SEND_RATE != 0)
+ info->byte_count += messageLength;
+#endif
+ if (info->packet == NULL) {
/* out of space, send the buffer and start refilling it */
/* make midi->packet non-null to fool midi_write_flush into sending */
- m->packet = (MIDIPacket *) 4;
+ info->packet = (MIDIPacket *) 4;
/* timestamp is 0 because midi_write_flush ignores timestamp since
* timestamps are already in packets. The timestamp parameter is here
* because other API's need it. midi_write_flush can be called
* from system-independent code that must be cross-API.
*/
if ((err = midi_write_flush(midi, 0)) != pmNoError) return err;
- m->packet = MIDIPacketListInit(m->packetList);
- assert(m->packet); /* if this fails, it's a programming error */
- m->packet = MIDIPacketListAdd(m->packetList, sizeof(m->packetBuffer),
- m->packet, timestamp, messageLength,
- message);
- assert(m->packet); /* can't run out of space on first message */
+ info->packet = MIDIPacketListInit(info->packetList);
+ assert(info->packet); /* if this fails, it's a programming error */
+ info->packet = MIDIPacketListAdd(info->packetList,
+ sizeof(info->packetBuffer), info->packet,
+ timestamp, messageLength, message);
+ assert(info->packet); /* can't run out of space on first message */
}
return pmNoError;
}
-static PmError
-midi_write_short(PmInternal *midi, PmEvent *event)
+static PmError midi_write_short(PmInternal *midi, PmEvent *event)
{
PmTimestamp when = event->timestamp;
PmMessage what = event->message;
MIDITimeStamp timestamp;
- UInt64 when_ns;
- midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
+ coremidi_info_type info = (coremidi_info_type) midi->api_info;
Byte message[4];
unsigned int messageLength;
- if (m->packet == NULL) {
- m->packet = MIDIPacketListInit(m->packetList);
+ if (info->packet == NULL) {
+ info->packet = MIDIPacketListInit(info->packetList);
/* this can never fail, right? failure would indicate something
unrecoverable */
- assert(m->packet);
+ assert(info->packet);
}
- /* compute timestamp */
- if (when == 0) when = midi->now;
- /* if latency == 0, midi->now is not valid. We will just set it to zero */
- if (midi->latency == 0) when = 0;
- when_ns = ((UInt64) (when + midi->latency) * (UInt64) 1000000) + m->delta;
- timestamp = (MIDITimeStamp) AudioConvertNanosToHostTime(when_ns);
+ /* PortMidi specifies that incoming timestamps are the receive
+ * time. Devices attach their receive times, but virtual devices
+ * do not. Instead, they pass along whatever timestamp was sent to
+ * them. We do not know if we are connected to real or virtual
+ * device. To avoid wild timestamps on the receiving end, we
+ * consider 2 cases: PortMidi timestamp is zero or latency is
+ * zero. Both mean send immediately, so we attach the current time
+ * which will go out immediately and arrive with a sensible
+ * timestamp (not zero and not zero mapped to the client's local
+ * time). Otherwise, we assume the timestamp is reasonable. It
+ * might be slighly in the past, but we pass it along after
+ * translation to MIDITimeStamp units.
+ *
+ * Compute timestamp: use current time if timestamp is zero or
+ * latency is zero. Both mean no timing and send immediately.
+ */
+ if (when == 0 || midi->latency == 0) {
+ timestamp = AudioGetCurrentHostTime();
+ } else { /* translate PortMidi time + latency to CoreMIDI time */
+ timestamp = ((UInt64) (when + midi->latency) * (UInt64) 1000000) +
+ info->delta;
+ timestamp = AudioConvertNanosToHostTime(timestamp);
+ }
message[0] = Pm_MessageStatus(what);
message[1] = Pm_MessageData1(what);
message[2] = Pm_MessageData2(what);
messageLength = midi_length(what);
-
- /* make sure we go foreward in time */
- if (timestamp < m->min_next_time) timestamp = m->min_next_time;
-
- #ifdef LIMIT_RATE
- if (timestamp < m->last_time)
- timestamp = m->last_time;
- m->last_time = timestamp + messageLength * m->host_ticks_per_byte;
- #endif
+#ifdef LIMIT_RATE
+ /* Make sure we go forward in time. */
+ if (timestamp < info->min_next_time) {
+ timestamp = info->min_next_time;
+ }
+ /* Note that if application is way behind and slowly catching up, then
+ * timestamps could be increasing faster than real time, and since
+ * timestamps are used to estimate data rate, our estimate could be
+ * low, causing CoreMIDI to drop packets. This seems very unlikely.
+ */
+ if (info->isIACdevice || info->is_virtual) {
+ info->min_next_time = timestamp + messageLength *
+ info->host_ticks_per_byte;
+ }
+#endif
/* Add this message to the packet list */
return send_packet(midi, message, messageLength, timestamp);
}
-static PmError
-midi_begin_sysex(PmInternal *midi, PmTimestamp when)
+static PmError midi_begin_sysex(PmInternal *midi, PmTimestamp when)
{
UInt64 when_ns;
- midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
- assert(m);
- m->sysex_byte_count = 0;
+ coremidi_info_type info = (coremidi_info_type) midi->api_info;
+ assert(info);
+ info->sysex_byte_count = 0;
/* compute timestamp */
if (when == 0) when = midi->now;
/* if latency == 0, midi->now is not valid. We will just set it to zero */
if (midi->latency == 0) when = 0;
- when_ns = ((UInt64) (when + midi->latency) * (UInt64) 1000000) + m->delta;
- m->sysex_timestamp = (MIDITimeStamp) AudioConvertNanosToHostTime(when_ns);
+ when_ns = ((UInt64) (when + midi->latency) * (UInt64) 1000000) +
+ info->delta;
+ info->sysex_timestamp =
+ (MIDITimeStamp) AudioConvertNanosToHostTime(when_ns);
+ UInt64 now; /* only make system time call when writing a virtual port */
+ if (info->is_virtual && info->sysex_timestamp <
+ (now = AudioGetCurrentHostTime())) {
+ info->sysex_timestamp = now;
+ }
- if (m->packet == NULL) {
- m->packet = MIDIPacketListInit(m->packetList);
+ if (info->packet == NULL) {
+ info->packet = MIDIPacketListInit(info->packetList);
/* this can never fail, right? failure would indicate something
unrecoverable */
- assert(m->packet);
+ assert(info->packet);
}
return pmNoError;
}
-static PmError
-midi_end_sysex(PmInternal *midi, PmTimestamp when)
+static PmError midi_end_sysex(PmInternal *midi, PmTimestamp when)
{
PmError err;
- midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
- assert(m);
+ coremidi_info_type info = (coremidi_info_type) midi->api_info;
+ assert(info);
+#ifdef LIMIT_RATE
/* make sure we go foreward in time */
- if (m->sysex_timestamp < m->min_next_time)
- m->sysex_timestamp = m->min_next_time;
-
- #ifdef LIMIT_RATE
- if (m->sysex_timestamp < m->last_time)
- m->sysex_timestamp = m->last_time;
- m->last_time = m->sysex_timestamp + m->sysex_byte_count *
- m->host_ticks_per_byte;
- #endif
+ if (info->sysex_timestamp < info->min_next_time)
+ info->sysex_timestamp = info->min_next_time;
+
+ if (info->isIACdevice) {
+ info->min_next_time = info->sysex_timestamp + info->sysex_byte_count *
+ info->host_ticks_per_byte;
+ }
+#endif
/* now send what's in the buffer */
- err = send_packet(midi, m->sysex_buffer, m->sysex_byte_count,
- m->sysex_timestamp);
- m->sysex_byte_count = 0;
+ err = send_packet(midi, info->sysex_buffer, info->sysex_byte_count,
+ info->sysex_timestamp);
+ info->sysex_byte_count = 0;
if (err != pmNoError) {
- m->packet = NULL; /* flush everything in the packet list */
- return err;
+ info->packet = NULL; /* flush everything in the packet list */
}
- return pmNoError;
+ return err;
}
-static PmError
-midi_write_byte(PmInternal *midi, unsigned char byte, PmTimestamp timestamp)
+static PmError midi_write_byte(PmInternal *midi, unsigned char byte,
+ PmTimestamp timestamp)
{
- midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
- assert(m);
- if (m->sysex_byte_count >= SYSEX_BUFFER_SIZE) {
+ coremidi_info_type info = (coremidi_info_type) midi->api_info;
+ assert(info);
+ if (info->sysex_byte_count >= SYSEX_BUFFER_SIZE) {
PmError err = midi_end_sysex(midi, timestamp);
if (err != pmNoError) return err;
}
- m->sysex_buffer[m->sysex_byte_count++] = byte;
+ info->sysex_buffer[info->sysex_byte_count++] = byte;
return pmNoError;
}
-static PmError
-midi_write_realtime(PmInternal *midi, PmEvent *event)
+static PmError midi_write_realtime(PmInternal *midi, PmEvent *event)
{
/* to send a realtime message during a sysex message, first
flush all pending sysex bytes into packet list */
@@ -660,27 +943,10 @@ midi_write_realtime(PmInternal *midi, PmEvent *event)
return midi_write_short(midi, event);
}
-static unsigned int midi_has_host_error(PmInternal *midi)
-{
- midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
- return (m->callback_error[0] != 0) || (m->error[0] != 0);
-}
-
-static void midi_get_host_error(PmInternal *midi, char *msg, unsigned int len)
+static unsigned int midi_check_host_error(PmInternal *midi)
{
- midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
- msg[0] = 0; /* initialize to empty string */
- if (m) { /* make sure there is an open device to examine */
- if (m->error[0]) {
- strncpy(msg, m->error, len);
- m->error[0] = 0; /* clear the error */
- } else if (m->callback_error[0]) {
- strncpy(msg, m->callback_error, len);
- m->callback_error[0] = 0; /* clear the error */
- }
- msg[len - 1] = 0; /* make sure string is terminated */
- }
+ return FALSE;
}
@@ -695,6 +961,7 @@ MIDITimeStamp timestamp_pm_to_cm(PmTimestamp timestamp)
}
}
+
PmTimestamp timestamp_cm_to_pm(MIDITimeStamp timestamp)
{
UInt64 nanos;
@@ -708,179 +975,170 @@ PmTimestamp timestamp_cm_to_pm(MIDITimeStamp timestamp)
//////////////////////////////////////
// Obtain the name of an endpoint without regard for whether it has connections.
// The result should be released by the caller.
-CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal)
+CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal, int *isIAC)
{
- CFMutableStringRef result = CFStringCreateMutable(NULL, 0);
- CFStringRef str;
-
- // begin with the endpoint's name
- str = NULL;
- MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &str);
- if (str != NULL) {
- CFStringAppend(result, str);
- CFRelease(str);
- }
+ CFMutableStringRef result = CFStringCreateMutable(NULL, 0);
+ CFStringRef str;
+ *isIAC = FALSE;
- MIDIEntityRef entity = NULL_REF;
- MIDIEndpointGetEntity(endpoint, &entity);
- if (entity == NULL_REF)
- // probably virtual
- return result;
-
- if (CFStringGetLength(result) == 0) {
- // endpoint name has zero length -- try the entity
+ // begin with the endpoint's name
str = NULL;
- MIDIObjectGetStringProperty(entity, kMIDIPropertyName, &str);
+ MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &str);
if (str != NULL) {
- CFStringAppend(result, str);
- CFRelease(str);
- }
- }
- // now consider the device's name
- MIDIDeviceRef device = NULL_REF;
- MIDIEntityGetDevice(entity, &device);
- if (device == NULL_REF)
- return result;
-
- str = NULL;
- MIDIObjectGetStringProperty(device, kMIDIPropertyName, &str);
- if (CFStringGetLength(result) == 0) {
- CFRelease(result);
- return str;
- }
- if (str != NULL) {
- // if an external device has only one entity, throw away
- // the endpoint name and just use the device name
- if (isExternal && MIDIDeviceGetNumberOfEntities(device) < 2) {
- CFRelease(result);
- return str;
- } else {
- if (CFStringGetLength(str) == 0) {
+ CFStringAppend(result, str);
CFRelease(str);
+ }
+ MIDIEntityRef entity = NULL_REF;
+ MIDIEndpointGetEntity(endpoint, &entity);
+ if (entity == NULL_REF) {
+ // probably virtual
return result;
- }
- // does the entity name already start with the device name?
- // (some drivers do this though they shouldn't)
- // if so, do not prepend
- if (CFStringCompareWithOptions( result, /* endpoint name */
- str /* device name */,
- CFRangeMake(0, CFStringGetLength(str)), 0) != kCFCompareEqualTo) {
- // prepend the device name to the entity name
- if (CFStringGetLength(result) > 0)
- CFStringInsert(result, 0, CFSTR(" "));
- CFStringInsert(result, 0, str);
- }
- CFRelease(str);
- }
- }
- return result;
-}
-
+ }
+ if (!isExternal) { /* detect IAC devices */
+ //extern const CFStringRef kMIDIPropertyDriverOwner;
+ MIDIObjectGetStringProperty(entity, kMIDIPropertyDriverOwner, &str);
+ if (str != NULL) {
+ char s[32]; /* driver name may truncate, but that's OK */
+ CFStringGetCString(str, s, 31, kCFStringEncodingUTF8);
+ s[31] = 0; /* make sure it is terminated just to be safe */
+ CM_DEBUG printf("driver %s\n", s);
+ *isIAC = (strcmp(s, "com.apple.AppleMIDIIACDriver") == 0);
+ }
+ }
-// Obtain the name of an endpoint, following connections.
-// The result should be released by the caller.
-static CFStringRef ConnectedEndpointName(MIDIEndpointRef endpoint)
-{
- CFMutableStringRef result = CFStringCreateMutable(NULL, 0);
- CFStringRef str;
- OSStatus err;
- long i;
-
- // Does the endpoint have connections?
- CFDataRef connections = NULL;
- long nConnected = 0;
- bool anyStrings = false;
- err = MIDIObjectGetDataProperty(endpoint, kMIDIPropertyConnectionUniqueID, &connections);
- if (connections != NULL) {
- // It has connections, follow them
- // Concatenate the names of all connected devices
- nConnected = CFDataGetLength(connections) / (int32_t) sizeof(MIDIUniqueID);
- if (nConnected) {
- const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections));
- for (i = 0; i < nConnected; ++i, ++pid) {
- MIDIUniqueID id = EndianS32_BtoN(*pid);
- MIDIObjectRef connObject;
- MIDIObjectType connObjectType;
- err = MIDIObjectFindByUniqueID(id, &connObject, &connObjectType);
- if (err == noErr) {
- if (connObjectType == kMIDIObjectType_ExternalSource ||
- connObjectType == kMIDIObjectType_ExternalDestination) {
- // Connected to an external device's endpoint (10.3 and later).
- str = EndpointName((MIDIEndpointRef)(connObject), true);
- } else {
- // Connected to an external device (10.2) (or something else, catch-all)
- str = NULL;
- MIDIObjectGetStringProperty(connObject, kMIDIPropertyName, &str);
- }
- if (str != NULL) {
- if (anyStrings)
- CFStringAppend(result, CFSTR(", "));
- else anyStrings = true;
+ if (CFStringGetLength(result) == 0) {
+ // endpoint name has zero length -- try the entity
+ str = NULL;
+ MIDIObjectGetStringProperty(entity, kMIDIPropertyName, &str);
+ if (str != NULL) {
CFStringAppend(result, str);
CFRelease(str);
- }
}
- }
}
- CFRelease(connections);
- }
- if (anyStrings)
- return result;
+ // now consider the device's name
+ MIDIDeviceRef device = NULL_REF;
+ MIDIEntityGetDevice(entity, &device);
+ if (device == NULL_REF)
+ return result;
- // Here, either the endpoint had no connections, or we failed to obtain names for any of them.
- return EndpointName(endpoint, false);
+ str = NULL;
+ MIDIObjectGetStringProperty(device, kMIDIPropertyName, &str);
+ if (CFStringGetLength(result) == 0) {
+ CFRelease(result);
+ return str;
+ }
+ if (str != NULL) {
+ // if an external device has only one entity, throw away
+ // the endpoint name and just use the device name
+ if (isExternal && MIDIDeviceGetNumberOfEntities(device) < 2) {
+ CFRelease(result);
+ return str;
+ } else {
+ if (CFStringGetLength(str) == 0) {
+ CFRelease(str);
+ return result;
+ }
+ // does the entity name already start with the device name?
+ // (some drivers do this though they shouldn't)
+ // if so, do not prepend
+ if (CFStringCompareWithOptions(result, /* endpoint name */
+ str, /* device name */
+ CFRangeMake(0, CFStringGetLength(str)), 0) !=
+ kCFCompareEqualTo) {
+ // prepend the device name to the entity name
+ if (CFStringGetLength(result) > 0)
+ CFStringInsert(result, 0, CFSTR(" "));
+ CFStringInsert(result, 0, str);
+ }
+ CFRelease(str);
+ }
+ }
+ return result;
}
-char* cm_get_full_endpoint_name(MIDIEndpointRef endpoint)
+// Obtain the name of an endpoint, following connections.
+// The result should be released by the caller.
+static CFStringRef ConnectedEndpointName(MIDIEndpointRef endpoint, int *isIAC)
{
-#ifdef OLDCODE
- MIDIEntityRef entity;
- MIDIDeviceRef device;
+ CFMutableStringRef result = CFStringCreateMutable(NULL, 0);
+ CFStringRef str;
+ OSStatus err;
+ long i;
+
+ // Does the endpoint have connections?
+ CFDataRef connections = NULL;
+ long nConnected = 0;
+ bool anyStrings = false;
+ err = MIDIObjectGetDataProperty(endpoint, kMIDIPropertyConnectionUniqueID,
+ &connections);
+ if (connections != NULL) {
+ // It has connections, follow them
+ // Concatenate the names of all connected devices
+ nConnected = CFDataGetLength(connections) /
+ (int32_t) sizeof(MIDIUniqueID);
+ if (nConnected) {
+ const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections));
+ for (i = 0; i < nConnected; ++i, ++pid) {
+ MIDIUniqueID id = EndianS32_BtoN(*pid);
+ MIDIObjectRef connObject;
+ MIDIObjectType connObjectType;
+ err = MIDIObjectFindByUniqueID(id, &connObject,
+ &connObjectType);
+ if (err == noErr) {
+ if (connObjectType == kMIDIObjectType_ExternalSource ||
+ connObjectType == kMIDIObjectType_ExternalDestination) {
+ // Connected to an external device's endpoint (>=10.3)
+ str = EndpointName((MIDIEndpointRef)(connObject), true,
+ isIAC);
+ } else {
+ // Connected to an external device (10.2)
+ // (or something else, catch-all)
+ str = NULL;
+ MIDIObjectGetStringProperty(connObject,
+ kMIDIPropertyName, &str);
+ }
+ if (str != NULL) {
+ if (anyStrings)
+ CFStringAppend(result, CFSTR(", "));
+ else anyStrings = true;
+ CFStringAppend(result, str);
+ CFRelease(str);
+ }
+ }
+ }
+ }
+ CFRelease(connections);
+ }
+ if (anyStrings)
+ return result; // caller should release result
- CFStringRef endpointName = NULL;
- CFStringRef deviceName = NULL;
-#endif
- CFStringRef fullName = NULL;
- CFStringEncoding defaultEncoding;
- char* newName;
+ CFRelease(result);
- /* get the default string encoding */
- defaultEncoding = CFStringGetSystemEncoding();
+ // Here, either the endpoint had no connections, or we failed to
+ // obtain names for any of them.
+ return EndpointName(endpoint, false, isIAC);
+}
- fullName = ConnectedEndpointName(endpoint);
-
-#ifdef OLDCODE
- /* get the entity and device info */
- MIDIEndpointGetEntity(endpoint, &entity);
- MIDIEntityGetDevice(entity, &device);
- /* create the nicely formated name */
- MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &endpointName);
- MIDIObjectGetStringProperty(device, kMIDIPropertyName, &deviceName);
- if (deviceName != NULL) {
- fullName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@: %@"),
- deviceName, endpointName);
- } else {
- fullName = endpointName;
- }
-#endif
- /* copy the string into our buffer */
- newName = (char *) malloc(CFStringGetLength(fullName) + 1);
- CFStringGetCString(fullName, newName, CFStringGetLength(fullName) + 1,
- defaultEncoding);
+char *cm_get_full_endpoint_name(MIDIEndpointRef endpoint, int *isIAC)
+{
+ /* Thanks to Dan Wilcox for fixes for Unicode handling */
+ CFStringRef fullName = ConnectedEndpointName(endpoint, isIAC);
+ CFIndex utf16_len = CFStringGetLength(fullName) + 1;
+ CFIndex max_byte_len = CFStringGetMaximumSizeForEncoding(
+ utf16_len, kCFStringEncodingUTF8) + 1;
+ char* pmname = (char *) pm_alloc(CFStringGetLength(fullName) + 1);
+
+ /* copy the string into our buffer; note that there may be some wasted
+ space, but the total waste is not large */
+ CFStringGetCString(fullName, pmname, max_byte_len, kCFStringEncodingUTF8);
/* clean up */
-#ifdef OLDCODE
- if (endpointName) CFRelease(endpointName);
- if (deviceName) CFRelease(deviceName);
-#endif
if (fullName) CFRelease(fullName);
-
- return newName;
+ return pmname;
}
-
pm_fns_node pm_macosx_in_dictionary = {
none_write_short,
@@ -894,8 +1152,7 @@ pm_fns_node pm_macosx_in_dictionary = {
midi_abort,
midi_in_close,
success_poll,
- midi_has_host_error,
- midi_get_host_error,
+ midi_check_host_error
};
pm_fns_node pm_macosx_out_dictionary = {
@@ -910,23 +1167,50 @@ pm_fns_node pm_macosx_out_dictionary = {
midi_abort,
midi_out_close,
success_poll,
- midi_has_host_error,
- midi_get_host_error,
+ midi_check_host_error
};
+/* We do nothing with callbacks, but generating the callbacks also
+ * updates CoreMIDI state. Callback may not be essential, but calling
+ * the CFRunLoopRunInMode is necessary.
+ */
+void cm_notify(const MIDINotification *msg, void *refCon)
+{
+ /* for debugging, trace change notifications:
+ const char *descr[] = {
+ "undefined (0)",
+ "kMIDIMsgSetupChanged",
+ "kMIDIMsgObjectAdded",
+ "kMIDIMsgObjectRemoved",
+ "kMIDIMsgPropertyChanged",
+ "kMIDIMsgThruConnectionsChanged",
+ "kMIDIMsgSerialPortOwnerChanged",
+ "kMIDIMsgIOError"};
+
+ printf("MIDI Notify, messageID %d (%s)\n", (int) msg->messageID,
+ descr[(int) msg->messageID]);
+ */
+ return;
+}
+
+
PmError pm_macosxcm_init(void)
{
ItemCount numInputs, numOutputs, numDevices;
MIDIEndpointRef endpoint;
int i;
- OSStatus macHostError;
- char *error_text;
+ OSStatus macHostError = noErr;
+ const char *error_text;
+
+ memset(isIAC, 0, sizeof(isIAC)); /* initialize all FALSE */
+
+ /* Register interface CoreMIDI with create_virtual fn */
+ pm_add_interf("CoreMIDI", &midi_create_virtual, &midi_delete_virtual);
+ /* no check for error return because this always succeeds */
/* Determine the number of MIDI devices on the system */
numDevices = MIDIGetNumberOfDevices();
- numInputs = MIDIGetNumberOfSources();
- numOutputs = MIDIGetNumberOfDestinations();
/* Return prematurely if no devices exist on the system
Note that this is not an error. There may be no devices.
@@ -937,74 +1221,88 @@ PmError pm_macosxcm_init(void)
return pmNoError;
}
-
/* Initialize the client handle */
- macHostError = MIDIClientCreate(CFSTR("PortMidi"), NULL, NULL, &client);
+ if (client == NULL_REF) {
+ macHostError = MIDIClientCreate(CFSTR("PortMidi"), &cm_notify, NULL,
+ &client);
+ } else { /* see notes above on device scanning */
+ for (int i = 0; i < 100; i++) {
+ // look for any changes before scanning for devices
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
+ if (i % 5 == 0) Pt_Sleep(1); /* insert 20 delays */
+ }
+ }
if (macHostError != noErr) {
- error_text = (char *)"MIDIClientCreate() in pm_macosxcm_init()";
+ error_text = "MIDIClientCreate() in pm_macosxcm_init()";
goto error_return;
}
+ numInputs = MIDIGetNumberOfSources();
+ numOutputs = MIDIGetNumberOfDestinations();
/* Create the input port */
- macHostError = MIDIInputPortCreate(client, CFSTR("Input port"), readProc,
- NULL, &portIn);
+ macHostError = MIDIInputPortCreate(client, CFSTR("Input port"),
+ device_read_callback, NULL, &portIn);
if (macHostError != noErr) {
- error_text = (char *)"MIDIInputPortCreate() in pm_macosxcm_init()";
+ error_text = "MIDIInputPortCreate() in pm_macosxcm_init()";
goto error_return;
}
-
+
/* Create the output port */
macHostError = MIDIOutputPortCreate(client, CFSTR("Output port"), &portOut);
if (macHostError != noErr) {
- error_text = (char *)"MIDIOutputPortCreate() in pm_macosxcm_init()";
+ error_text = "MIDIOutputPortCreate() in pm_macosxcm_init()";
goto error_return;
}
/* Iterate over the MIDI input devices */
for (i = 0; i < numInputs; i++) {
+ int isIACflag;
endpoint = MIDIGetSource(i);
if (endpoint == NULL_REF) {
continue;
}
-
/* set the first input we see to the default */
if (pm_default_input_device_id == -1)
- pm_default_input_device_id = pm_descriptor_index;
+ pm_default_input_device_id = pm_descriptor_len;
/* Register this device with PortMidi */
- pm_add_device((char *)"CoreMIDI", cm_get_full_endpoint_name(endpoint),
- TRUE, (void *) (long) endpoint, &pm_macosx_in_dictionary);
+ pm_add_device("CoreMIDI",
+ cm_get_full_endpoint_name(endpoint, &isIACflag), TRUE, FALSE,
+ (void *) (intptr_t) endpoint, &pm_macosx_in_dictionary);
}
/* Iterate over the MIDI output devices */
for (i = 0; i < numOutputs; i++) {
+ int isIACflag;
+ PmDeviceID id;
endpoint = MIDIGetDestination(i);
if (endpoint == NULL_REF) {
continue;
}
-
/* set the first output we see to the default */
if (pm_default_output_device_id == -1)
- pm_default_output_device_id = pm_descriptor_index;
+ pm_default_output_device_id = pm_descriptor_len;
/* Register this device with PortMidi */
- pm_add_device((char *)"CoreMIDI", cm_get_full_endpoint_name(endpoint),
- FALSE, (void *) (long) endpoint,
- &pm_macosx_out_dictionary);
+ id = pm_add_device("CoreMIDI",
+ cm_get_full_endpoint_name(endpoint, &isIACflag), FALSE, FALSE,
+ (void *) (intptr_t) endpoint, &pm_macosx_out_dictionary);
+ /* if this is an IAC device, tuck that info away for write functions */
+ if (isIACflag && id <= MAX_IAC_NUM) {
+ isIAC[id] = TRUE;
+ }
}
return pmNoError;
error_return:
- pm_hosterror = macHostError;
- sprintf(pm_hosterror_text, "Host error %ld: %s\n", (long) macHostError,
- error_text);
pm_macosxcm_term(); /* clear out any opened ports */
- return pmHostError;
+ return check_hosterror(macHostError, error_text);
}
void pm_macosxcm_term(void)
{
- if (client != NULL_REF) MIDIClientDispose(client);
+ /* docs say do not explicitly dispose of client
+ if (client != NULL_REF) MIDIClientDispose(client); */
if (portIn != NULL_REF) MIDIPortDispose(portIn);
if (portOut != NULL_REF) MIDIPortDispose(portOut);
}
diff --git a/3rdparty/portmidi/pm_mac/pmmacosxcm.h b/3rdparty/portmidi/pm_mac/pmmacosxcm.h
index ea79902d40b..ab8b5edbcb7 100644
--- a/3rdparty/portmidi/pm_mac/pmmacosxcm.h
+++ b/3rdparty/portmidi/pm_mac/pmmacosxcm.h
@@ -3,4 +3,4 @@
PmError pm_macosxcm_init(void);
void pm_macosxcm_term(void);
-PmDeviceID find_default_device(char *path, int input, PmDeviceID id);
+PmDeviceID find_default_device(const char *path, int input, PmDeviceID id);
diff --git a/3rdparty/portmidi/pm_mac/readbinaryplist.c b/3rdparty/portmidi/pm_mac/readbinaryplist.c
index 858dd029ec7..9564e700d0b 100644
--- a/3rdparty/portmidi/pm_mac/readbinaryplist.c
+++ b/3rdparty/portmidi/pm_mac/readbinaryplist.c
@@ -3,26 +3,28 @@
readbinaryplist.c -- Roger B. Dannenberg, Jun 2008
Based on ReadBinaryPList.m by Jens Ayton, 2007
-Note that this code is intended to read preference files and has an upper
-bound on file size (currently 100MB) and assumes in some places that 32 bit
-offsets are sufficient.
+Note that this code is intended to read preference files and has an
+upper bound on file size (currently 100MB) and assumes in some places
+that 32 bit offsets are sufficient.
Here are his comments:
Reader for binary property list files (version 00).
-This has been found to work on all 566 binary plists in my ~/Library/Preferences/
-and /Library/Preferences/ directories. This probably does not provide full
-test coverage. It has also been found to provide different data to Apple's
-implementation when presented with a key-value archive. This is because Apple's
-implementation produces undocumented CFKeyArchiverUID objects. My implementation
-produces dictionaries instead, matching the in-file representation used in XML
-and OpenStep plists. See extract_uid().
-
-Full disclosure: in implementing this software, I read one comment and one
-struct defintion in CFLite, Apple's implementation, which is under the APSL
-license. I also deduced the information about CFKeyArchiverUID from that code.
-However, none of the implementation was copied.
+This has been found to work on all 566 binary plists in my
+~/Library/Preferences/ and /Library/Preferences/ directories. This
+probably does not provide full test coverage. It has also been found
+to provide different data to Apple's implementation when presented
+with a key-value archive. This is because Apple's implementation
+produces undocumented CFKeyArchiverUID objects. My implementation
+produces dictionaries instead, matching the in-file representation
+used in XML and OpenStep plists. See extract_uid().
+
+Full disclosure: in implementing this software, I read one comment and
+one struct defintion in CFLite, Apple's implementation, which is under
+the APSL license. I also deduced the information about
+CFKeyArchiverUID from that code. However, none of the implementation
+was copied.
Copyright (C) 2007 Jens Ayton
@@ -33,16 +35,16 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
@@ -72,21 +74,19 @@ memory requested or calls longjmp, so callers don't have to check.
*/
#include <sys/types.h>
-#include <sys/param.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <sys/stat.h>
#include "readbinaryplist.h"
-#include "osxsupport.h"
#include <Carbon/Carbon.h>
#define NO 0
#define YES 1
#define BOOL int
-//#define MAXPATHLEN 256
+#define MAX_PATH_LEN 256
/* there are 2 levels of error logging/printing:
* BPLIST_LOG and BPLIST_LOG_VERBOSE
@@ -99,22 +99,21 @@ memory requested or calls longjmp, so callers don't have to check.
* parameters like printf but might be a no-op.
*/
-#define BPLIST_LOG_VERBOSE 0
-#define BPLIST_LOG 0
+/* #define BPLIST_LOG_VERBOSE 1 */
-#if BPLIST_LOG_VERBOSE
+#if defined(BPLIST_LOG_VERBOSE) && (BPLIST_LOG_VERBOSE != 0)
#ifndef BPLIST_LOG
#define BPLIST_LOG 1
#endif
#endif
-#if BPLIST_LOG
+#if defined(BPLIST_LOG) && (BPLIST_LOG != 0)
#define bplist_log printf
#else
#define bplist_log(...)
#endif
-#if BPLIST_LOG_VERBOSE
+#if defined(BPLIST_LOG_VERBOSE) && (BPLIST_LOG_VERBOSE != 0)
#define bplist_log_verbose bplist_log
#else
#define bplist_log_verbose(...)
@@ -156,7 +155,7 @@ static void *allocate(size_t size)
return result;
}
-void bplist_free_data()
+void bplist_free_data(void)
{
while (block_list) {
void *next = *(void **)block_list;
@@ -207,10 +206,12 @@ typedef struct bplist_info
static value_ptr bplist_read_pldata(pldata_ptr data);
-static value_ptr bplist_read_pref(char *filename, OSType folder_type);
-static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset, uint8_t size);
+static value_ptr bplist_read_pref(const char *filename, OSType folder_type);
+static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset,
+ uint8_t size);
static uint64_t read_offset(bplist_info_ptr bplist, uint64_t index);
-static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset, uint64_t *outValue, size_t *outSize);
+static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset,
+ uint64_t *outValue, size_t *outSize);
static value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef);
static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset);
@@ -219,7 +220,8 @@ static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset);
static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset);
static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset);
static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset);
-static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_unicode_string(bplist_info_ptr bplist,
+ uint64_t offset);
static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset);
static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset);
static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset);
@@ -236,15 +238,18 @@ void value_set_integer(value_ptr v, int64_t i) {
v->tag = kTAG_INT; v->integer = i;
}
+
void value_set_real(value_ptr v, double d) {
v->tag = kTAG_REAL; v->real = d;
}
+
// d is seconds since 1 January 2001
void value_set_date(value_ptr v, double d) {
v->tag = kTAG_DATE; v->real = d;
}
+
void value_set_ascii_string(value_ptr v, const uint8_t *s, size_t len) {
v->tag = kTAG_ASCIISTRING;
v->string = (char *) allocate(len + 1);
@@ -252,6 +257,7 @@ void value_set_ascii_string(value_ptr v, const uint8_t *s, size_t len) {
v->string[len] = 0;
}
+
void value_set_unicode_string(value_ptr v, const uint8_t *s, size_t len) {
v->tag = kTAG_UNICODESTRING;
v->string = (char *) allocate(len + 1);
@@ -276,8 +282,10 @@ void value_set_data(value_ptr v, const uint8_t *data, size_t len) {
printf("value at %p gets data at %p\n", v, pldata);
}
+
// caller releases ownership of array to value_ptr v
-void value_set_array(value_ptr v, value_ptr *array, size_t length) {
+void value_set_array(value_ptr v, value_ptr *array, size_t length)
+{
array_ptr a = (array_ptr) allocate(sizeof(array_node));
a->array = array;
a->length = length;
@@ -285,8 +293,10 @@ void value_set_array(value_ptr v, value_ptr *array, size_t length) {
v->array = a;
}
+
// caller releases ownership of dict to value_ptr v
-void value_set_dict(value_ptr v, dict_ptr dict) {
+void value_set_dict(value_ptr v, dict_ptr dict)
+{
v->tag = kTAG_DICTIONARY;
v->dict = dict;
}
@@ -334,7 +344,7 @@ BOOL is_binary_plist(pldata_ptr data)
}
-value_ptr bplist_read_file(char *filename)
+value_ptr bplist_read_file(const char *filename)
{
struct stat stbuf;
pldata_node pldata;
@@ -343,7 +353,7 @@ value_ptr bplist_read_file(char *filename)
value_ptr value;
int rslt = stat(filename, &stbuf);
if (rslt) {
- #if BPLIST_LOG
+ #if defined(BPLIST_LOG) && (BPLIST_LOG != 0)
perror("in stat");
#endif
bplist_log("Could not stat %s, error %d\n", filename, rslt);
@@ -380,12 +390,11 @@ value_ptr bplist_read_file(char *filename)
return value;
}
-// use old Carbon method on PPC
-#ifdef OSX_PPC
-value_ptr bplist_read_pref(char *filename, OSType folder_type)
+
+value_ptr bplist_read_pref(const char *filename, OSType folder_type)
{
FSRef prefdir;
- char cstr[MAXPATHLEN];
+ char cstr[MAX_PATH_LEN];
OSErr err = FSFindFolder(kOnAppropriateDisk, folder_type,
FALSE, &prefdir);
@@ -393,57 +402,23 @@ value_ptr bplist_read_pref(char *filename, OSType folder_type)
bplist_log("Error finding preferences folder: %d\n", err);
return NULL;
}
- err = FSRefMakePath(&prefdir, (UInt8 *) cstr, (UInt32) (MAXPATHLEN - 1));
+ err = FSRefMakePath(&prefdir, (UInt8 *) cstr, (UInt32) (MAX_PATH_LEN - 1));
if (err) {
bplist_log("Error making path name for preferences folder: %d\n", err);
return NULL;
}
- strlcat(cstr, "/", MAXPATHLEN);
- strlcat(cstr, filename, MAXPATHLEN);
+ strlcat(cstr, "/", MAX_PATH_LEN);
+ strlcat(cstr, filename, MAX_PATH_LEN);
return bplist_read_file(cstr);
}
-#else
-value_ptr bplist_read_pref(char *filename, OSType folder_type)
-{
- char cstr[MAXPATHLEN];
- char *foundstr;
-
- memset(cstr, 0, MAXPATHLEN);
-
- // for later OS X, the user preferences folder (~/Library/Preferences) is not available directly from Cocoa,
- // Apple documentation suggests just using POSIX APIs like so.
- if (folder_type == kPreferencesFolderType)
- {
- strlcpy(cstr, getenv("HOME"), MAXPATHLEN);
- strlcat(cstr, "/Library/Preferences", MAXPATHLEN);
- }
- else // the system preferences folder (~/Library/PreferencePanes) is accessible from Cocoa however
- {
- foundstr = FindPrefsDir();
-
- if (!foundstr) {
- bplist_log("Error finding preferences folder\n");
- return NULL;
- }
-
- strlcat(cstr, foundstr, MAXPATHLEN);
- free(foundstr);
- foundstr = NULL;
- }
-
- strlcat(cstr, "/", MAXPATHLEN);
- strlcat(cstr, filename, MAXPATHLEN);
-
- return bplist_read_file(cstr);
-}
-#endif
-value_ptr bplist_read_system_pref(char *filename) {
+
+value_ptr bplist_read_system_pref(const char *filename) {
return bplist_read_pref(filename, kSystemPreferencesFolderType);
}
-value_ptr bplist_read_user_pref(char *filename) {
+value_ptr bplist_read_user_pref(const char *filename) {
return bplist_read_pref(filename, kPreferencesFolderType);
}
@@ -774,7 +749,7 @@ static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset)
uint64_t bplist_get_a_size(bplist_info_ptr bplist,
- uint64_t *offset_ptr, char *msg)
+ uint64_t *offset_ptr, const char *msg)
{
uint64_t size = bplist->data_bytes[*offset_ptr] & 0x0F;
(*offset_ptr)++;
@@ -814,7 +789,7 @@ static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset)
assert(bplist->data_bytes != NULL && offset < bplist->length);
- if ((size = bplist_get_a_size(bplist, &offset, (char *)"data")) == UINT64_MAX)
+ if ((size = bplist_get_a_size(bplist, &offset, "data")) == UINT64_MAX)
return NULL;
value = value_create();
@@ -831,7 +806,7 @@ static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset)
assert(bplist->data_bytes != NULL && offset < bplist->length);
- if ((size = bplist_get_a_size(bplist, &offset, (char *)"ascii string")) ==
+ if ((size = bplist_get_a_size(bplist, &offset, "ascii string")) ==
UINT64_MAX)
return NULL;
@@ -850,7 +825,7 @@ static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset)
assert(bplist->data_bytes != NULL && offset < bplist->length);
- if ((size = bplist_get_a_size(bplist, &offset, (char *)"unicode string")) ==
+ if ((size = bplist_get_a_size(bplist, &offset, "unicode string")) ==
UINT64_MAX)
return NULL;
@@ -911,7 +886,7 @@ static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset)
assert(bplist->data_bytes != NULL && offset < bplist->length);
- if ((count = bplist_get_a_size(bplist, &offset, (char *)"array")) == UINT64_MAX)
+ if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX)
return NULL;
if (count > UINT64_MAX / bplist->object_ref_size - offset) {
@@ -973,7 +948,7 @@ static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset)
assert(bplist->data_bytes != NULL && offset < bplist->length);
- if ((count = bplist_get_a_size(bplist, &offset, (char *)"array")) == UINT64_MAX)
+ if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX)
return NULL;
if (count > UINT64_MAX / (bplist->object_ref_size * 2) - offset) {
@@ -1037,7 +1012,7 @@ char *value_get_asciistring(value_ptr v)
}
-value_ptr value_dict_lookup_using_string(value_ptr v, char *key)
+value_ptr value_dict_lookup_using_string(value_ptr v, const char *key)
{
dict_ptr dict;
if (v->tag != kTAG_DICTIONARY) return NULL; // not a dictionary
@@ -1053,7 +1028,7 @@ value_ptr value_dict_lookup_using_string(value_ptr v, char *key)
return NULL; /* not found */
}
-value_ptr value_dict_lookup_using_path(value_ptr v, char *path)
+value_ptr value_dict_lookup_using_path(value_ptr v, const char *path)
{
char key[MAX_KEY_SIZE];
while (*path) { /* more to the path */
diff --git a/3rdparty/portmidi/pm_mac/readbinaryplist.h b/3rdparty/portmidi/pm_mac/readbinaryplist.h
index e82056a0b79..8b096d08e2e 100644
--- a/3rdparty/portmidi/pm_mac/readbinaryplist.h
+++ b/3rdparty/portmidi/pm_mac/readbinaryplist.h
@@ -71,16 +71,16 @@ typedef struct value_struct {
} value_node, *value_ptr;
-value_ptr bplist_read_file(char *filename);
-value_ptr bplist_read_user_pref(char *filename);
-value_ptr bplist_read_system_pref(char *filename);
+value_ptr bplist_read_file(const char *filename);
+value_ptr bplist_read_user_pref(const char *filename);
+value_ptr bplist_read_system_pref(const char *filename);
void bplist_free_data(void);
/*************** functions for accessing values ****************/
char *value_get_asciistring(value_ptr v);
-value_ptr value_dict_lookup_using_string(value_ptr v, char *key);
-value_ptr value_dict_lookup_using_path(value_ptr v, char *path);
+value_ptr value_dict_lookup_using_string(value_ptr v, const char *key);
+value_ptr value_dict_lookup_using_path(value_ptr v, const char *path);
/*************** functions for debugging ***************/