diff options
Diffstat (limited to '3rdparty/portmidi/pm_mac')
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 Binary files differdeleted file mode 100644 index c7e5600f98a..00000000000 --- a/3rdparty/portmidi/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings +++ /dev/null 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 ***************/ |