diff --git a/pd/portmidi/ALL_BUILD.vcproj b/pd/portmidi/ALL_BUILD.vcproj
new file mode 100644
index 0000000000000000000000000000000000000000..a04c3d528553d4a3c590c335aed8e69359db3a0e
--- /dev/null
+++ b/pd/portmidi/ALL_BUILD.vcproj
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="ALL_BUILD"
+	ProjectGUID="{E1C2664B-91BB-4D4F-868C-433164F81101}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="ALL_BUILD.dir\Debug"
+			ConfigurationType="10"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories=".\pm_common;.\porttime;"
+				ExceptionHandling="0"
+				PreprocessorDefinitions="CMAKE_INTDIR=\&quot;Debug\&quot;"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories=".\pm_common;.\porttime;"
+				PreprocessorDefinitions="CMAKE_INTDIR=\&quot;Debug\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="CMAKE_INTDIR=\&quot;Debug\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="ALL_BUILD.dir\Release"
+			ConfigurationType="10"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories=".\pm_common;.\porttime;"
+				ExceptionHandling="0"
+				PreprocessorDefinitions="CMAKE_INTDIR=\&quot;Release\&quot;"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories=".\pm_common;.\porttime;"
+				PreprocessorDefinitions="CMAKE_INTDIR=\&quot;Release\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="CMAKE_INTDIR=\&quot;Release\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+			<File
+				RelativePath=".\CMakeFiles\ALL_BUILD">
+			</File>
+		<Filter
+			Name="CMake Rules"
+			Filter="">
+			<File
+				RelativePath=".\CMakeFiles\ALL_BUILD.rule">
+				<FileConfiguration
+					Name="Debug|Win32">
+					<Tool
+					Name="VCCustomBuildTool"
+					Description="Build all projects"
+					CommandLine=""
+					AdditionalDependencies=".\CMakeFiles\ALL_BUILD.rule"
+					Outputs=".\CMakeFiles\ALL_BUILD"/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32">
+					<Tool
+					Name="VCCustomBuildTool"
+					Description="Build all projects"
+					CommandLine=""
+					AdditionalDependencies=".\CMakeFiles\ALL_BUILD.rule"
+					Outputs=".\CMakeFiles\ALL_BUILD"/>
+				</FileConfiguration>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/CHANGELOG.txt b/pd/portmidi/CHANGELOG.txt
index fd118e814cfe6601a932dcb2bf8a8a07c0b7b1f4..c2a083a56857dc5c8b0e9e5c9fe8e6415dcd5024 100644
--- a/pd/portmidi/CHANGELOG.txt
+++ b/pd/portmidi/CHANGELOG.txt
@@ -1,4 +1,38 @@
 /* CHANGELOG FOR PORTMIDI
+ *
+ * 19Oct09 Roger Dannenberg
+ * - Changes dynamic library names from portmidi_d to portmidi to
+ *   be backward-compatible with programs expecting a library by
+ *   the old name.
+ *
+ * 04Oct09 Roger Dannenberg
+ * - Converted to using Cmake.
+ * - Renamed static and dynamic library files to portmidi_s and portmidi_d
+ * - Eliminated VC9 and VC8 files (went back to simply test.vcproj, etc.,
+ *   use Cmake to switch from the provided VC9 files to VC8 or other)
+ * - Many small changes to prepare for 64-bit architectures (but only 
+ *   tested on 32-bit machines)
+ *
+ * 16Jun09 Roger Dannenberg
+ * - Started using Microsoft Visual C++ Version 9 (Express). Converted
+ * all *-VC9.vcproj file to *.vcproj and renamed old project files to 
+ * *-VC8.proj. Previously, output from VC9 went to special VC9 files,
+ * that breaks any program or script looking for output in release or
+ * debug files, so now both compiler version output to the same folders.
+ * Now, debug version uses static linking with debug DLL runtime, and 
+ * release version uses static linking with statically linked runtime.
+ * Converted to Inno Setup and worked on scripts to make things build
+ * properly, especially pmdefaults.
+ *
+ * 02Jan09 Roger Dannenberg
+ * - Created Java interface and wrote PmDefaults application to set
+ *   values for Pm_GetDefaultInputDeviceID() and 
+ *   Pm_GetDefaultOutputDeviceID(). Other fixes.
+ *
+ * 19Jun08 Roger Dannenberg and Austin Sung
+ * - Removed USE_DLL_FOR_CLEANUP -- Windows 2000 through Vista seem to be
+ *   fixed now, and can recover if MIDI ports are left open
+ * - Various other minor patches
  *
  * 17Jan07 Roger Dannenberg
  * - Lots more help for Common Lisp user in pm_cl
diff --git a/pd/portmidi/CMakeLists.txt b/pd/portmidi/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4919b78df620b6818f45c479e5f226d38ac7259b
--- /dev/null
+++ b/pd/portmidi/CMakeLists.txt
@@ -0,0 +1,77 @@
+# portmidi
+# Roger B. Dannenberg
+# 20 Sep 2009
+
+cmake_minimum_required(VERSION 2.6)
+
+if(UNIX)
+  # allow user to set Release or Debug
+  set(CMAKE_BUILD_TYPE Release CACHE STRING 
+      "Semicolon-separate list of supported configuration types")
+  # set default directories but don't override cached values...
+  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CACHEFILE_DIR}/${CMAKE_BUILD_TYPE}
+      CACHE STRING "libraries go here")
+  set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CACHEFILE_DIR}/${CMAKE_BUILD_TYPE}
+      CACHE STRING "libraries go here")
+  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY 
+      ${CMAKE_CACHEFILE_DIR}/${CMAKE_BUILD_TYPE}
+      CACHE STRING "executables go here")
+
+else(UNIX)
+  # this does not seem to work for xcode:
+  set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING 
+      "Semicolon-separate list of supported configuration types")
+endif(UNIX)
+
+#set(CMAKE_RELATIVE_PATHS ON CACHE STRING "avoid absolute paths" FORCE)
+
+# Clear out the built-in C++ compiler and link flags for each of the 
+# unused configurations.
+set(CMAKE_CXX_FLAGS_MINSIZEREL "" CACHE INTERNAL "Unused")
+set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "" CACHE INTERNAL "Unused")
+set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "" CACHE INTERNAL "Unused")
+set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "" CACHE INTERNAL "Unused")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "Unused")
+set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "Unused")
+set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "Unused")
+set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "" CACHE INTERNAL "Unused")
+
+set(CMAKE_OSX_ARCHITECTURES i386 ppc x86_64 CACHE STRING "change to needed architecture for a smaller library" FORCE)
+
+PROJECT(portmidi)
+
+if(UNIX)
+  # Problem: if there was an old Debug build and you change
+  #  CMAKE_BUILD_TYPE to Release, then the OUTPUT_DIRECTORY's will
+  #  still be Debug. Try to fix this by checking if the DIRECTORY's
+  #  look wrong, and if so, force them to the defaults:
+  if(CMAKE_BUILD_TYPE MATCHES "Debug")
+    set(BAD_DIR "Release")
+  else(CMAKE_BUILD_TYPE MATCHES "Debug")
+    set(BAD_DIR "Debug")
+  endif(CMAKE_BUILD_TYPE MATCHES "Debug")
+  # use library as reference -- if you give it a non-BAD_DIR location
+  # then every other path is left alone
+  if(CMAKE_LIBRARY_OUTPUT_DIRECTORY MATCHES ${BAD_DIR})
+    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY 
+        ${CMAKE_CACHEFILE_DIR}/${CMAKE_BUILD_TYPE}
+        CACHE STRING "executables go here" FORCE)
+    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY 
+        ${CMAKE_CACHEFILE_DIR}/${CMAKE_BUILD_TYPE}
+        CACHE STRING "libraries go here" FORCE)
+    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY 
+        ${CMAKE_CACHEFILE_DIR}/${CMAKE_BUILD_TYPE}
+        CACHE STRING "libraries go here" FORCE)
+  endif(CMAKE_LIBRARY_OUTPUT_DIRECTORY MATCHES ${BAD_DIR})
+endif(UNIX)
+
+include_directories(pm_common porttime)
+add_subdirectory(pm_common)
+
+add_subdirectory(pm_test)
+
+add_subdirectory(pm_dylib)
+
+# Cannot figure out how to make an xcode Java application with CMake
+add_subdirectory(pm_java)
+
diff --git a/pd/portmidi/Doxyfile b/pd/portmidi/Doxyfile
new file mode 100644
index 0000000000000000000000000000000000000000..0adb682932539cbcf7da1aff595dcc311a405424
--- /dev/null
+++ b/pd/portmidi/Doxyfile
@@ -0,0 +1,1472 @@
+# Doxyfile 1.5.5
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file 
+# that follow. The default is UTF-8 which is also the encoding used for all 
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
+# iconv built into libc) for the transcoding. See 
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = PortMidi
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 2.2.x
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, 
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), 
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, 
+# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, 
+# Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Java. For instance, namespaces will be presented as packages, qualified 
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
+# sources. Doxygen will then generate output that is tailored for 
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
+# to include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter 
+# and setter methods for a property. Setting this option to YES (the default) 
+# will make doxygen to replace the get and set methods by a property in the 
+# documentation. This will only work if the methods are indeed getting or 
+# setting a simple type. If this is not the case, or you want to show the 
+# methods anyway, you should set this option to NO.
+# 1.5.7
+#IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
+# is documented as struct, union, or enum with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code in case the coding convention dictates that all compound 
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is 
+# probably good enough. For larger projects a too small cache size can cause 
+# doxygen to be busy swapping symbols to and from disk most of the time 
+# causing a significant performance penality. 
+# If the system has enough physical memory increasing the cache will improve the 
+# performance by keeping more symbols in memory. Note that the value works on 
+# a logarithmic scale so increasing the size by one will rougly double the 
+# memory usage. The cache size is given by this formula: 
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# corresponding to a cache size of 2^16 = 65536 symbols
+# 1.5.7
+# SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be 
+# extracted and appear in the documentation as a namespace called 
+# 'anonymous_namespace{file}', where file will be replaced with the base 
+# name of the file that contains the anonymous namespace. By default 
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
+# hierarchy of group names into alphabetical order. If set to NO (the default) 
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the 
+# Folder Tree View (if specified). The default is YES.
+# 1.5.7
+# SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
+# Namespaces page.  This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+# 1.5.7
+# SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from 
+# the version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by 
+# doxygen. The layout file controls the global structure of the generated output files 
+# in an output format independent way. The create the layout file that represents 
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a 
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name 
+# of the layout file.
+# 1.5.7
+# LAYOUT_FILE            = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = \
+		         pm_common/portmidi.h \
+		         pm_common/portmidi.c \
+
+# This tag can be used to specify the character encoding of the source files 
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
+# also the default input encoding. Doxygen uses libiconv (or the iconv built 
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.h \
+                         *.c 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the 
+# output. The symbol name can be a fully qualified name, a word, or if the 
+# wildcard * is used, a substring. Examples: ANamespace, AClass, 
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = ./pm_test
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = *.cxx \
+                         *.h \
+                         *.H \
+                         *.fl
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.  Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = Pm_
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files 
+# will be generated that can be used as input for Apple's Xcode 3 
+# integrated development environment, introduced with OSX 10.5 (Leopard). 
+# To create a documentation set, doxygen will generate a Makefile in the 
+# HTML output directory. Running make will produce the docset in that 
+# directory and running "make install" will install the docset in 
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
+# it at startup. 
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = YES
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
+# feed. A documentation feed provides an umbrella under which multiple 
+# documentation sets from a single provider (such as a company or product suite) 
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
+# should uniquely identify the documentation set bundle. This should be a 
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+# 1.5.7
+# CHM_INDEX_ENCODING     = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER 
+# are set, an additional index file will be generated that can be used as input for 
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated 
+# HTML documentation.
+# 1.5.7
+# GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can 
+# be used to specify the file name of the resulting .qch file. 
+# The path specified is relative to the HTML output folder.
+# 1.5.7
+# QCH_FILE               = 
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# <a href="http://doc.trolltech.com/qthelpproject.html#namespace">Qt Help Project / Namespace</a>.
+# 1.5.7
+# QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# <a href="http://doc.trolltech.com/qthelpproject.html#virtual-folders">Qt Help Project / Virtual Folders</a>.
+# 1.5.7
+# QHP_VIRTUAL_FOLDER     = doc
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 
+# be used to specify the location of Qt's qhelpgenerator. 
+# If non-empty doxygen will try to run qhelpgenerator on the generated 
+# .qhp file .
+# 1.5.7
+# QHG_LOCATION           = 
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to FRAME, a side panel will be generated
+# containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature. Other possible values 
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list;
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
+# disables this behavior completely. For backwards compatibility with previous
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
+# respectively.
+
+GENERATE_TREEVIEW      = YES
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 200
+
+# Use this tag to change the font size of Latex formulas included 
+# as images in the HTML documentation. The default is 10. Note that 
+# when you change the font size after a successful doxygen run you need 
+# to manually remove any form_*.png images from the HTML output directory 
+# to force them to be regenerated.
+# 1.5.7
+# FORMULA_FONTSIZE       = 10
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = YES
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = FL_DOXYGEN \
+                         HAVE_CAIRO \
+                         HAVE_GL \
+                         HAVE_GL_OVERLAY \
+                         FL_EXPORT:=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see 
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
+# the mscgen tool resides. If left empty the tool is assumed to be found in the 
+# default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output 
+# directory and reference it in all dot files that doxygen generates. This 
+# font does not include all possible unicode characters however, so when you need 
+# these (or just want a differently looking font) you can specify the font name 
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font, 
+# which can be done by putting it in a standard location or by setting the 
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory 
+# containing the font.
+# 1.5.7
+# DOT_FONTNAME           = FreeSans
+
+# By default doxygen will tell dot to use the output directory to look for the 
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a 
+# different font using DOT_FONTNAME you can set the path where dot 
+# can find it using this tag.
+# 1.5.7
+# DOT_FONTPATH           = 
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
+# doxygen will generate a call dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable call graphs 
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
+# doxygen will generate a caller dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable caller 
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the 
+# number of direct children of the root node in a graph is already larger than 
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, because dot on Windows does not 
+# seem to support this out of the box. Warning: Depending on the platform used, 
+# enabling this option may lead to badly anti-aliased labels on the edges of 
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/pd/portmidi/README.txt b/pd/portmidi/README.txt
old mode 100644
new mode 100755
index 0ab950d034ea0fefd9caf75c4f0dee7fcefe9f24..32608231b54611b09e1d8ea7cad712db7baf6e3a
--- a/pd/portmidi/README.txt
+++ b/pd/portmidi/README.txt
@@ -1,7 +1,8 @@
 README for PortMidi
-Roger Dannenberg
 
-VERSION: this is the 17-Jan-07 version of PortMidi.
+Roger B. Dannenberg
+
+VERSION: please use "svn info" to get info.
 
 Documentation for PortMidi is found in pm_common/portmidi.h.
 
@@ -10,6 +11,10 @@ Additional documentation:
   - Linux: see pm_linux/README_LINUX.txt
   - Mac OSX: see pm_mac/README_MAC.txt
   - Common Lisp: see pm_cl/README_CL.txt
+  - Eclipse: see portmidi_cdt.zip (this was contributed as is; the dlls here
+        are now -- Sep 09 -- out of date. What is really needed is a script
+        to generate this release automatically so we can maintain it.)
+  - C-Sharp: see pm_csharp.zip (also contributed as is)
 
 ---------- some notes on the design of PortMidi ----------
 
@@ -27,7 +32,7 @@ ERROR HANDLING
 
 Error handling turned out to be much more complicated than expected.
 PortMidi functions return error codes that the caller can check.
-In addition, errors may occur asynchronously due to MIDI input. 
+In addition, errors may occur asynchronously due to MIDI input.
 However, for Windows, there are virtually no errors that can
 occur if the code is correct and not passing bogus values. One
 exception is an error that the system is out of memory, but my
@@ -39,8 +44,8 @@ Ordinarily, the caller checks for an error code. If the error is
 system-dependent, pmHostError is returned and the caller can
 call Pm_GetHostErrorText to get a text description of the error.
 
-Host error codes are system-specific and are recorded in the 
-system-specific data allocated for each open MIDI port. 
+Host error codes are system-specific and are recorded in the
+system-specific data allocated for each open MIDI port.
 However, if an error occurs on open or close,
 we cannot store the error with the device because there will be
 no device data (assuming PortMidi cleans up after devices that
@@ -56,7 +61,7 @@ overhead even if the user does not want to look at the error data.
 
 The system-specific Read, Write, Poll, etc. implementations should
 check for asynchronous errors and return immediately if one is
-found so that these get reported. This happens in the Mac OS X 
+found so that these get reported. This happens in the Mac OS X
 code, where lots of things are happening in callbacks, but again,
 in Windows, there are no error codes recorded in callbacks.
 
@@ -64,7 +69,7 @@ DEBUGGING
 
 If you are building a console application for research, we suggest
 compiling with the option PM_CHECK_ERRORS. This will insert a
-check for error return values at the end of each PortMidi 
+check for error return values at the end of each PortMidi
 function. If an error is encountered, a text message is printed
 using printf(), the user is asked to type ENTER, and then exit(-1)
 is called to clean up and terminate the program.
diff --git a/pd/portmidi/ZERO_CHECK.vcproj b/pd/portmidi/ZERO_CHECK.vcproj
new file mode 100644
index 0000000000000000000000000000000000000000..23d96278d6d1d315b17827981dd11c2b559f0f1d
--- /dev/null
+++ b/pd/portmidi/ZERO_CHECK.vcproj
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="ZERO_CHECK"
+	ProjectGUID="{28779535-7541-4FF5-AC12-FAFD66E894EC}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="ZERO_CHECK.dir\Debug"
+			ConfigurationType="10"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories=".\pm_common;.\porttime;"
+				ExceptionHandling="0"
+				PreprocessorDefinitions="CMAKE_INTDIR=\&quot;Debug\&quot;"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories=".\pm_common;.\porttime;"
+				PreprocessorDefinitions="CMAKE_INTDIR=\&quot;Debug\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="CMAKE_INTDIR=\&quot;Debug\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="ZERO_CHECK.dir\Release"
+			ConfigurationType="10"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories=".\pm_common;.\porttime;"
+				ExceptionHandling="0"
+				PreprocessorDefinitions="CMAKE_INTDIR=\&quot;Release\&quot;"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories=".\pm_common;.\porttime;"
+				PreprocessorDefinitions="CMAKE_INTDIR=\&quot;Release\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="CMAKE_INTDIR=\&quot;Release\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+			<File
+				RelativePath=".\CMakeFiles\ZERO_CHECK">
+			</File>
+		<Filter
+			Name="CMake Rules"
+			Filter="">
+			<File
+				RelativePath=".\CMakeFiles\ZERO_CHECK.rule">
+				<FileConfiguration
+					Name="Debug|Win32">
+					<Tool
+					Name="VCCustomBuildTool"
+					Description=""
+					CommandLine=""
+					AdditionalDependencies=".\CMakeFiles\ZERO_CHECK.rule"
+					Outputs=".\CMakeFiles\ZERO_CHECK"/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32">
+					<Tool
+					Name="VCCustomBuildTool"
+					Description=""
+					CommandLine=""
+					AdditionalDependencies=".\CMakeFiles\ZERO_CHECK.rule"
+					Outputs=".\CMakeFiles\ZERO_CHECK"/>
+				</FileConfiguration>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/license.txt b/pd/portmidi/license.txt
index b04523be49c041d116e0d76c1ea9874ed187527f..c757b37139a38cad6a7d94a6719ec49628f1fe1a 100644
--- a/pd/portmidi/license.txt
+++ b/pd/portmidi/license.txt
@@ -3,10 +3,10 @@
  *
  * license.txt -- a copy of the PortMidi copyright notice and license information
  *
- * Latest version available at: http://www.cs.cmu.edu/~music/portmidi/
+ * Latest version available at: http://sourceforge.net/projects/portmedia
  *
  * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
- * Copyright (c) 2001-2006 Roger B. Dannenberg
+ * Copyright (c) 2001-2009 Roger B. Dannenberg
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files
diff --git a/pd/portmidi/pm_cl/README_CL.txt b/pd/portmidi/pm_cl/README_CL.txt
new file mode 100644
index 0000000000000000000000000000000000000000..be4c63591f6e4f97e323216710d3cecf9248d5db
--- /dev/null
+++ b/pd/portmidi/pm_cl/README_CL.txt
@@ -0,0 +1,104 @@
+README_CL.txt for PortMidi
+Roger B. Dannenberg
+17 Jan 2007
+
+This is a Common Lisp interface to PortMidi.
+
+On Mac OSX, you need to build PortMidi as a dynamic link library
+before you can use PortMidi from Common Lisp.
+
+You can build PortMidi as a dynamic link library by running this:
+
+cd portmidi
+make -F pm_mac/Makefile.osx install-with-xcode
+
+This is just a shortcut for:
+
+cd portmidi/pm_mac
+sudo xcodebuild -project pm_mac.xcodeproj -configuration Deployment install DSTROOT=/
+
+You can check the file and the architecture for which it is built using:
+    file /usr/local/lib/libportmidi.dylib
+
+If you've done this install of portmidi, then you should also have 
+   /usr/local/include/portmidi.h
+This will be necessary to successfully build the cffi interface below.
+
+To test PortMidi with Common Lisp, I (RBD) am using SBCL, which I 
+downloaded from http://prdownloads.sourceforge.net/sbcl. Currently, I use 
+    sbcl-0.9.17-x86-darwin-binary.tar.bz2
+To install this, I unpacked it by just double-clicking in the finder. Then, 
+from a command window, I became root using "sudo sh", and then typed:
+# INSTALL_ROOT=/usr/local
+# sh install.sh
+# exit
+
+I also downloaded cffi-061012.tar.gz from 
+    http://common-lisp.net/project/cffi/tarballs/?M=D
+
+To compile cffi, use the following, where "/Lisp/cffi/" is replaced by 
+the actual directory of cffi, e.g. 
+    "/Users/rbd/sbcl-0.9.17-x86-darwin/cffi-061012":
+
+% sbcl
+* (require 'asdf)
+* (push "/Lisp/cffi/" asdf:*central-registry*)
+* (asdf:oos 'asdf:load-op :cffi)
+* (quit)
+
+Download Common Music's portmidi module from cvs and build the c side:
+(Replace "/Lisp" with your lisp directory, e.g. 
+"/Users/rbd/sbcl-0.9.17-x86-darwin". These cvs commands will create
+a new directory, portmidi.)
+
+% cd /Lisp
+% export CVSROOT=:pserver:anonymous@commonmusic.cvs.sourceforge.net:/cvsroot/commonmusic
+% cvs login   # press Return at password prompt
+% cvs checkout portmidi
+% cd portmidi
+% ./configure
+% make
+% cd ..
+
+Now compile/load the portmidi module just like cffi. Again, change
+"/Lisp/cffi/" and "/Lisp/portmidi" to correspond to your local file system.
+(Note that /Lisp becomes your lisp directory, and "cffi" becomes your
+cffi folder name, e.g. "cffi-061012".
+
+% sbcl
+* (require 'asdf)
+* (push "/Lisp/cffi/" asdf:*central-registry*)
+* (asdf:oos 'asdf:load-op :cffi)
+* (push "/Lisp/portmidi/" asdf:*central-registry*)
+* (asdf:oos 'asdf:load-op :portmidi)
+
+Look in the file /Lisp/portmidi/test.lisp for a test of the lisp interface to
+portmidi. For example, while still running sbcl:
+
+* (pm:portmidi)  ; initialize portmidi
+* (pt:start) ; start time
+* (pt:time) ; get time
+* (pprint (pm:GetDeviceInfo)) ; get list of devices
+((:ID 0 :NAME "IAC Driver Bus 1" :TYPE :INPUT :OPEN NIL)
+ (:ID 1 :NAME "IAC Driver Bus 1" :TYPE :OUTPUT :OPEN NIL))
+
+Notice that test.lisp assumes MIDI input devices are connected
+and uses some hard-wired device numbers, so it may not run
+as is without error.
+
+Since test.lisp uses some Common Music calls, I (RBD) wrote a
+simpler test, test-no-cm.lisp, which is in the same folder as
+this (README_CL.txt) file. To use it, first check that the 
+values for outid (4) and inid (1) actually match PortMidi device
+id's for output and input devices, and make sure the input
+device is a keyboard that can generate a middle-C -- otherwise
+the program will hang waiting for input. Run sbcl from this
+pm_cl folder, and type:
+
+(load "test-no-cm.lisp")
+
+The program pauses frequently by calling (READ), so you
+should type t or something, then <RETURN> to continue.
+
+
+(Thanks to Leigh Smith and Rick Taube)
diff --git a/pd/portmidi/pm_cl/cffi-portmidi.lisp b/pd/portmidi/pm_cl/cffi-portmidi.lisp
new file mode 100644
index 0000000000000000000000000000000000000000..4b3ad9c3e00ac534588f3124874e5c8aa0480565
--- /dev/null
+++ b/pd/portmidi/pm_cl/cffi-portmidi.lisp
@@ -0,0 +1,384 @@
+;;; **********************************************************************
+;;; Copyright (C) 2005 Heinrich Taube, <taube (at) uiuc (dot) edu>
+;;;
+;;; This program is free software; you can redistribute it and/or
+;;; modify it under the terms of the Lisp Lesser Gnu Public License.
+;;; See http://www.cliki.net/LLGPL for the text of this agreement.
+;;; **********************************************************************
+
+
+;;; A CFFI interface to Portmidi. Should run in most Common Lisp
+;;; implementations on Linux, OS X and Windows. For information about
+;;; CFFI see http://common-lisp.net/project/cffi/
+
+(in-package :cl-user)
+
+(defvar *libportmidi*
+  (let ((type #+(or darwin macos macosx) "dylib"
+              #+(or linux linux-target (and unix pc386) freebsd) "so"
+              #+(or win32 microsoft-32 cygwin) "dll")
+        (paths (list "/usr/lib/" "/usr/local/lib/" *load-pathname*)))
+    (loop for d in paths
+       for p = (make-pathname :name "libportmidi" :type type 
+                              :defaults d)
+       when (probe-file p) do (return p)
+       finally  
+         (error "Library \"portmidi.~A\" not found. Fix *libportmidi*."
+                type))))
+
+;;; linux: guess i need to load porttime.so first (?) osx doesnt seem
+;;; to need this lib at all...
+
+#+(or linux (and clisp unix (not macos)))
+(let ((lpt (merge-pathnames "libporttime" *libportmidi*)))
+  (if (probe-file lpt)
+      (cffi:load-foreign-library lpt)
+      (error "Porttime: ~a not found. Fix *libportmidi* path." lpt)))
+
+;;; load portmidi lib
+
+(cffi:load-foreign-library *libportmidi*)
+
+(defpackage :portmidi
+  (:use :common-lisp) 
+  (:nicknames :pm :pt)
+  (:shadow :initialize :terminate :time :start :stop :abort 
+           :close :read :write :poll)
+  (:export :Initialize :Terminate 
+           :HasHostError :GetErrorText :GetHostErrorText 
+           :CountDevices :GetDefaultInputDeviceID
+           :GetDefaultOutputDeviceID :GetDeviceInfo
+           :Message :Message.status :Message.data1 :Message.data2
+           :Event.message :Event.timestamp 
+           ;; event buffers added to api
+           :EventBufferNew :EventBufferFree :EventBufferElt
+           :EventBufferMap
+           :OpenInput :OpenOutput :SetFilter :SetChannelMask
+           :Abort :Close :Read :Write :Poll :WriteShort :WriteSysex
+           ;; filtering constants
+           :filt-active :filt-sysex :filt-clock :filt-play :filt-f9 
+           :filt-fd :filt-reset :filt-note :filt-channel-aftertouch
+           :filt-poly-aftertouch :filt-program :filt-control
+           :filt-pitchbend :filt-mtc :filt-song-position 
+           :filt-song-select :filt-tune :filt-tick :filt-undefined
+           :filt-realtime  :filt-aftertouch :filt-systemcommon
+           ;; porttime.
+           :Start :Stop :Started :Time
+           ;; initialization insurers added to api
+           :portmidi :*portmidi* ))
+
+(in-package :portmidi)
+
+(cffi:defcstruct pm-device-info 
+		 (struct-version :int) 
+		 (interf :pointer) 
+		 (name :pointer) 
+		 (input :int) 
+		 (output :int) 
+		 (opened :int))
+
+(cffi:define-foreign-type pm-message () ':long)
+(cffi:define-foreign-type pm-timestamp () ':long)
+(cffi:defcstruct pm-event 
+		 (message pm-message) 
+		 (timestamp pm-timestamp))
+(cffi:define-foreign-type pm-error () ':int)
+
+(cffi:define-foreign-type port-midi-stream () ':void)
+(cffi:define-foreign-type pm-device-id () ':int)
+(cffi:define-foreign-type pm-time-proc-ptr () ':pointer)
+(cffi:defcfun ("Pm_WriteSysEx" pm-write-sys-ex) pm-error (stream :pointer) (when pm-timestamp) (msg :pointer)) 
+(cffi:defcfun ("Pm_WriteShort" pm-write-short) pm-error (stream :pointer) (when pm-timestamp) (msg :long)) 
+(cffi:defcfun ("Pm_Write" pm-write) pm-error (stream :pointer) (buffer :pointer) (length :long)) 
+(cffi:defcfun ("Pm_Poll" pm-poll) pm-error (stream :pointer)) 
+(cffi:defcfun ("Pm_Read" pm-read) pm-error (stream :pointer) (buffer :pointer) (length :long)) 
+(cffi:defcfun ("Pm_Close" pm-close) pm-error (stream :pointer)) 
+(cffi:defcfun ("Pm_Abort" pm-abort) pm-error (stream :pointer)) 
+;(cffi:defcfun ("Pm_SetChannelMask" pm-set-channel-mask) pm-error (stream :pointer) (mask :int)) 
+(cffi:defcfun ("Pm_SetFilter" pm-set-filter) pm-error (stream :pointer) (filters :long)) 
+(cffi:defcfun ("Pm_OpenOutput" pm-open-output) pm-error (stream :pointer) (output-device pm-device-id) (output-driver-info :pointer) (buffer-size :long) (time-proc pm-time-proc-ptr) (time-info :pointer) (latency :long)) 
+(cffi:defcfun ("Pm_OpenInput" pm-open-input) pm-error (stream :pointer) (input-device pm-device-id) (input-driver-info :pointer) (buffer-size :long) (time-proc pm-time-proc-ptr) (time-info :pointer)) 
+(cffi:defcfun ("Pm_GetDeviceInfo" pm-get-device-info) :pointer (id pm-device-id)) 
+(cffi:defcfun ("Pm_GetDefaultOutputDeviceID" pm-get-default-output-device-id) pm-device-id) 
+(cffi:defcfun ("Pm_GetDefaultInputDeviceID" pm-get-default-input-device-id) pm-device-id) 
+(cffi:defcfun ("Pm_CountDevices" pm-count-devices) :int) 
+(cffi:defcfun ("Pm_GetHostErrorText" pm-get-host-error-text) :void (msg :pointer) (len :unsigned-int)) 
+(cffi:defcfun ("Pm_GetErrorText" pm-get-error-text) :pointer (errnum pm-error)) 
+(cffi:defcfun ("Pm_HasHostError" pm-has-host-error) :int (stream :pointer)) 
+(cffi:defcfun ("Pm_Terminate" pm-terminate) pm-error) 
+(cffi:defcfun ("Pm_Initialize" pm-initialize) pm-error)
+
+;;; porttime.h
+
+(cffi:define-foreign-type pt-error () ':int)
+(cffi:define-foreign-type pt-timestamp () ':long)
+(cffi:defcfun ("Pt_Start" pt-start) pt-error (a :int) (b :pointer) (c :pointer))
+(cffi:defcfun ("Pt_Stop" pt-stop) pt-error )
+(cffi:defcfun ("Pt_Started" pt-started) :int)
+(cffi:defcfun ("Pt_Time" pt-time) pt-timestamp)
+ 
+(defconstant true 1) 
+(defconstant false 0)
+(defconstant pmNoError 0)
+(defconstant pmHostError -10000)
+(defconstant pm-no-device -1)
+(defconstant pm-default-sysex-buffer-size 1024) 
+(defconstant filt-active 1) 
+(defconstant filt-sysex 2) 
+(defconstant filt-clock 4) 
+(defconstant filt-play 8) 
+(defconstant filt-f9 16) 
+(defconstant filt-fd 32) 
+(defconstant filt-reset 64) 
+(defconstant filt-note 128) 
+(defconstant filt-channel-aftertouch 256) 
+(defconstant filt-poly-aftertouch 512) 
+(defconstant filt-program 1024) 
+(defconstant filt-control 2048) 
+(defconstant filt-pitchbend 4096) 
+(defconstant filt-mtc 8192) 
+(defconstant filt-song-position 16384) 
+(defconstant filt-song-select 32768) 
+(defconstant filt-tune 65536) 
+(defconstant filt-tick filt-f9)
+(defconstant filt-undefined (logior filt-f9 filt-fd))
+(defconstant filt-realtime (logior filt-active filt-sysex
+                                      filt-clock filt-play
+                                      filt-undefined filt-reset))
+(defconstant filt-aftertouch (logior filt-channel-aftertouch
+                                        filt-poly-aftertouch ))
+(defconstant filt-systemcommon (logior filt-mtc filt-song-position
+                                          filt-song-select filt-tune))
+(defvar *portmidi* nil) ; t if loaded
+
+;;;
+;;; utils
+;;;
+
+(defvar host-error-text (make-string 256 :initial-element #\*))
+
+(defmacro with-pm-error (form)
+  (let ((v (gensym)))
+    `(let ((,v ,form))
+       (if (not (= ,v pmNoError))
+	   (if (= ,v pmHostError)
+	       (cffi:with-foreign-string (host-error host-error-text)
+		 (pm-get-host-error-text host-error
+					 (length host-error-text))
+		 (error "Host error is: ~a"
+			(cffi:foreign-string-to-lisp host-error)))
+	       (error (cffi:foreign-string-to-lisp
+		       (pm-get-error-text ,v))))
+           ,v))))
+
+(defun portmidi ()
+  ;; initializer, call before using lib
+  (or *portmidi*
+      (progn (pm-initialize)
+             (setq *portmidi* t))))
+
+(defun Message (status data1 data2)
+  ;; portmidi messages are just unsigneds
+  (logior (logand (ash data2 16) #xFF0000)
+          (logand (ash data1 08) #xFF00)
+          (logand status #xFF)))
+
+(defun Message.status (m)
+  (logand m #xFF))
+
+(defun Message.data1 (m)
+  (logand (ash m -08) #xFF))
+
+(defun Message.data2 (m)
+  (logand (ash m -16) #xFF))
+
+;;; accessors 
+
+(defun DeviceInfo.interf (ptr)
+  (cffi:foreign-string-to-lisp 
+   (cffi:foreign-slot-value ptr 'pm-device-info 'interf)))
+
+(defun DeviceInfo.name (ptr)
+  (cffi:foreign-string-to-lisp
+   (cffi:foreign-slot-value ptr 'pm-device-info 'name)))
+
+(defun DeviceInfo.input (ptr)
+  (if (= (cffi:foreign-slot-value ptr 'pm-device-info 'input) 0)
+      nil
+    t))
+
+(defun DeviceInfo.output (ptr)
+  (if (= (cffi:foreign-slot-value ptr 'pm-device-info 'output) 0)
+      nil
+    t))
+
+(defun DeviceInfo.opened (ptr)
+  (if (= (cffi:foreign-slot-value ptr 'pm-device-info 'opened) 0)
+      nil
+    t))
+
+(defun Event.message (e &optional (v nil vp))
+  (if vp
+      (progn 
+	(setf (cffi:foreign-slot-value e 'pm-event 'message) v)
+	v)
+    (cffi:foreign-slot-value e 'pm-event 'message)))
+    
+(defun Event.timestamp (e &optional (v nil vp))
+  (if vp
+      (progn 
+	(setf (cffi:foreign-slot-value e 'pm-event 'timestamp) v)
+	v)
+    (cffi:foreign-slot-value e 'pm-event 'timestamp)))
+
+;;; functions
+
+(defun Initialize ()
+  (with-pm-error (pm-initialize)))
+
+(defun terminate ()
+  (with-pm-error (pm-terminate)))
+
+
+(defun HasHostError (pms) 
+  (pm-has-host-error pms))
+
+(defun GetErrorText (err) 
+  (pm-get-error-text err))
+
+; how do i do this?
+;(progn
+;  (defalien "pm-GetHostErrorText" void (a c-string) (b unsigned-int))
+;  (defun GetHostErrorText () 
+;    (pm-GetHostErrorText 256)))
+
+(defun CountDevices ()
+  (portmidi)
+  (pm-count-devices ))
+
+(defun GetDefaultInputDeviceID ()
+  (let ((id (pm-get-default-input-device-id )))
+    (if (= id pm-no-device) nil id)))
+
+(defun GetDefaultOutputDeviceID ()
+  (let ((id (pm-get-default-output-device-id )))
+    (if (= id pm-no-device) nil id)))
+
+;replaced by lispy version end of file.
+;(defun GetDeviceInfo (id) (pm-get-device-info id))
+
+(defun OpenInput (device bufsiz)
+  ;; portmidi: timer must be running before opening
+  (unless (Started) (Start))
+  (cffi:with-foreign-object (p1 :pointer)
+    (let ((err (pm-open-input p1 device (cffi:null-pointer)
+                              bufsiz (cffi:null-pointer) (cffi:null-pointer))))
+        (if (= err pmNoError)
+            (cffi:mem-ref p1 :pointer)
+            (error (pm-get-error-text err))))))
+
+(defun OpenOutput (device bufsiz latency)
+  (unless (Started) (Start))
+  (cffi:with-foreign-object (p1 :pointer) ;(p (* PortMidi))
+    (let ((err (pm-open-output p1 device (cffi:null-pointer)
+                               bufsiz (cffi:null-pointer) (cffi:null-pointer)
+                               latency)))
+      (if (= err pmNoError)
+          (cffi:mem-ref p1 :pointer)
+          (error (pm-get-error-text err))))))
+
+(defun SetFilter (a filts) 
+  (with-pm-error
+    (pm-set-filter a filts)))
+
+;(defun SetChannelMask (pms mask)
+;  (with-pm-error (pm-set-channel-mask pms mask)))
+
+(defun Abort (pms)
+  (with-pm-error (pm-abort pms)))
+
+(defun Close (pms)
+  (with-pm-error (pm-close pms)))
+
+(defun EventBufferFree (buf)
+  (cffi:foreign-free buf))
+
+(defun EventBufferNew (len)
+  (cffi:foreign-alloc 'pm-event :count len))
+
+(defun EventBufferElt (buf i)
+  ;; buf is POINTER to buf
+  (cffi:mem-aref buf 'pm-event i))
+
+(defun EventBufferSet (buffer index timestamp message)
+  (setf (cffi:foreign-slot-value
+         (cffi:mem-aref buffer 'pm-event index) 'pm-event 'timestamp)
+        timestamp)
+  (setf (cffi:foreign-slot-value
+         (cffi:mem-aref buffer 'pm-event index) 'pm-event 'message)
+        message)
+  (values))
+
+(defun EventBufferMap (fn buf end)
+  (loop for i below end
+     for e = (EventBufferElt buf i)
+     do (funcall fn (Event.message e) (Event.timestamp e)))
+ (values))
+
+(defun Read (pms *evbuf len) 
+  (let ((res (pm-read pms *evbuf len)))
+    (if (< res 0)
+        (error (pm-get-error-text res))
+        res)))
+
+(defun Poll (pms)
+  (let ((res (pm-poll pms)))
+    (cond ((= res 0) nil)
+          ((= res 1) t)
+          (t (error (pm-get-error-text res))))))
+
+(defun Write (pms *evbuf len)
+  (with-pm-error (pm-write pms *evbuf len)))
+
+(defun WriteShort (pms when msg)
+  (with-pm-error (pm-write-short pms when msg)))
+
+(defun WriteSysex (pms when string)
+  (cffi:with-foreign-string (ptr string)
+    (with-pm-error (pm-write-sys-ex pms when ptr))))
+
+;;; porttime.h
+
+(defun Started ()
+  (let ((res (pt-started)))
+    (if (= res false) nil t)))
+
+(defun Start ()
+  ;; NB: This has to be called before opening output or input.
+  ;; it seems that if its called 2x we get an error.
+  (unless (Started)
+    (with-pm-error (pt-start 1 (cffi:null-pointer) (cffi:null-pointer))))
+  (values))
+
+(defun Stop ()
+  (when (Started)
+    (with-pm-error (pt-stop)))
+  (values))
+
+(defun Time ()
+  (pt-time))
+
+(defun GetDeviceInfo (&optional id)
+  (flet ((getone (id)
+           (let ((d (pm-get-device-info id)))
+             (list :id id
+                   :name  (DeviceInfo.name d)
+                   :type (if (DeviceInfo.input d) ':input ':output)
+                   :open (DeviceInfo.opened d)))))
+    ;; make sure lib is initialized before checking devices
+    (portmidi)
+    (if id (getone id)
+        (loop for i below (CountDevices)
+           collect (getone i)))))
+
+(pushnew ':portmidi *features*)
diff --git a/pd/portmidi/pm_cl/test-no-cm.lisp b/pd/portmidi/pm_cl/test-no-cm.lisp
new file mode 100644
index 0000000000000000000000000000000000000000..fd8527e6298887825550bd91807789c96d37b614
--- /dev/null
+++ b/pd/portmidi/pm_cl/test-no-cm.lisp
@@ -0,0 +1,112 @@
+;; this is a half-baked sequence of PortMidi calls to test the interface
+;; No calls to Common Music are made, hence test-no-cm.lisp
+
+; setup cffi if it has not been done already
+(if (not (boundp '*clpath*))
+    (load "setup-pm.lisp"))
+
+(defun println (s) (print s) (terpri))
+
+;; initialize portmidi lib
+(pm:portmidi)
+;; timer testing
+(pt:Start )
+(pt:Started)
+(format t "time is ~A, type something~%" (pt:Time))
+(read)
+(format t "time is ~A, type something~%" (pt:Time))
+(read)
+(pt:Time)
+(format t "time is ~A, type something~%" (pt:Time))
+
+;; device testing
+(pm:CountDevices)
+(pprint (pm:GetDeviceInfo ))
+(defparameter inid (pm:GetDefaultInputDeviceID ))
+(pm:GetDeviceInfo inid)
+(defparameter outid (pm:GetDefaultOutputDeviceID ))
+(pm:GetDeviceInfo outid)
+;; output testing
+(defparameter outid 4) ; 4 = my SimpleSynth
+(defparameter outdev (pm:OpenOutput outid 100 1000))
+(pm:getDeviceInfo outid) ; :OPEN should be T
+;; message tests
+(defun pm (m &optional (s t))
+  (format s "#<message :op ~2,'0x :ch ~2,'0d :data1 ~3,'0d :data2 ~3,'0d>"
+          (ash (logand (pm:Message.status m) #xf0) -4)
+          (logand (pm:Message.status m) #x0f)
+          (pm:Message.data1 m)
+          (pm:Message.data2 m)))
+(defparameter on (pm:message #b10010000 60 64))
+(terpri)
+(pm on)
+(pm:Message.status on)
+(logand (ash (pm:Message.status on) -4) #x0f)
+(pm:Message.data1 on)
+(pm:Message.data2 on)
+(pm:WriteShort outdev (+ (pm:time) 100) on)
+(defparameter off (pm:message #b10000000 60 64))
+(terpri)
+(pm off)
+(terpri)
+(println "type something for note off")
+(read)
+(pm:WriteShort outdev (+ (pm:time) 100) off)
+(println "type something to close output device")
+(read)
+(pm:Close outdev)
+;; event buffer testing
+(defparameter buff (pm:EventBufferNew 8))
+(loop for i below 8 for x = (pm:EventBufferElt buff i) 
+   ;; set buffer events
+   do
+     (pm:Event.message x (pm:message #b1001000 (+ 60 i) (+ 100 i)))
+     (pm:Event.timestamp x (* 1000 i)))
+(loop for i below 8 for x = (pm:EventBufferElt buff i) 
+   ;; check buffer contents
+   collect (list (pm:Event.timestamp x)
+                 (pm:Message.data1 (pm:Event.message x))
+                 (pm:Message.data2 (pm:Event.message x))))
+(pm:EventBufferFree buff)
+;; input testing -- requires external midi keyboard
+(println (pm:GetDeviceInfo ))
+(defparameter inid 1) ; 1 = my external keyboard
+(defparameter indev (pm:OpenInput inid 256)) 
+(pm:GetDeviceInfo inid) ; :OPEN should be T
+(pm:SetFilter indev pm:filt-realtime) ; ignore active sensing etc.
+(println "poll says:")
+(println (pm:Poll indev))
+(println "play midi keyboard and type something")
+(read)
+;;
+;; ...play midi keyboard, then ...
+;;
+(println "poll says")
+(println (pm:Poll indev))
+(defparameter buff (pm:EventBufferNew 32))
+(defparameter num (pm:Read indev buff 32))
+(println "pm:Read gets")
+(println num)
+(println "input messages:")
+(pm:EventBufferMap (lambda (a b) b (terpri) (pm a))
+                   buff num)
+(pm:Poll indev)
+
+(println "play keyboard, to stop, play middle-C")
+
+;;; recv testing
+
+(defparameter pitch 0)
+(loop while (/= pitch 60) do
+  (let ((n (pm:Read indev buff 1)))
+    (cond ((= n 1)
+           (pm:EventBufferMap
+                (lambda (a b) 
+                   b (pm a) (terpri)
+                   (setf pitch (pm:Message.data1 a)))
+                buff n)))))
+
+(pm:EventBufferFree buff)
+(pm:Close indev)
+
+
diff --git a/pd/portmidi/pm_common/CMakeLists.txt b/pd/portmidi/pm_common/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e1710474ae39af4953dda6c04ffc313a9f0d2328
--- /dev/null
+++ b/pd/portmidi/pm_common/CMakeLists.txt
@@ -0,0 +1,128 @@
+# pm_common
+
+# set the build directory for libportmidi.a to be in portmidi, not in 
+#    portmidi/pm_common
+if(APPLE OR WIN32)
+  set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+  # set the build directory for .dylib libraries
+  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+
+  # the first time CMake configures, save off CMake's built-in flags
+  if(NOT DEFAULT_DEBUG_FLAGS)
+    set(DEFAULT_DEBUG_FLAGS ${CMAKE_C_FLAGS_DEBUG} CACHE 
+        STRING "CMake's default debug flags" FORCE)
+    set(DEFAULT_RELEASE_FLAGS ${CMAKE_C_FLAGS_RELEASE} CACHE 
+        STRING "CMake's default release flags" FORCE)
+  else(NOT DEFAULT_DEBUG_FLAGS)
+    message(STATUS "DEFAULT_DEBUG_FLAGS not nil: " ${DEFAULT_DEBUG_FLAGS})
+  endif(NOT DEFAULT_DEBUG_FLAGS)
+else(APPLE OR WIN32)
+  set(LINUX_FLAGS "-DPMALSA")
+endif(APPLE OR WIN32)
+
+if(APPLE)
+  set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk CACHE 
+      PATH "-isysroot parameter for compiler" FORCE)
+  set(CMAKE_C_FLAGS "-mmacosx-version-min=10.5" CACHE 
+      STRING "needed in conjunction with CMAKE_OSX_SYSROOT" FORCE)
+endif(APPLE)
+
+macro(prepend_path RESULT PATH)
+  set(${RESULT})
+  foreach(FILE ${ARGN})
+    list(APPEND ${RESULT} "${PATH}${FILE}")
+  endforeach(FILE)
+endmacro(prepend_path)
+
+set(CMAKE_C_FLAGS_DEBUG 
+    "${DEFAULT_DEBUG_FLAGS} -DPM_CHECK_ERRORS=1 -DDEBUG ${LINUX_FLAGS}"
+    CACHE STRING "enable extra checks for debugging" FORCE)
+
+set(CMAKE_C_FLAGS_RELEASE "${DEFAULT_RELEASE_FLAGS} ${LINUX_FLAGS}"
+    CACHE STRING "flags for release version" FORCE)
+
+# first include the appropriate system-dependent file:
+if(UNIX)
+  # add the -g switch for Linux and Mac OS X (not used in Win32)
+  set (CMAKE_C_FLAGS_DEBUG "-g ${CMAKE_C_FLAGS_DEBUG}" 
+       CACHE STRING "enable extra checks for debugging" FORCE)
+  if(APPLE)
+    set(MACSRC pmmacosxcm pmmac readbinaryplist finddefault)
+    prepend_path(LIBSRC ../pm_mac/ ${MACSRC})
+    list(APPEND LIBSRC ../porttime/ptmacosx_mach)
+
+    include_directories(${CMAKE_OSX_SYSROOT}/Developer/Headers/FlatCarbon)
+    set(FRAMEWORK_PATH ${CMAKE_OSX_SYSROOT}/System/Library/Frameworks)
+    set(COREAUDIO_LIB "${FRAMEWORK_PATH}/CoreAudio.framework")
+    set(COREFOUNDATION_LIB "${FRAMEWORK_PATH}/CoreFoundation.framework")
+    set(COREMIDI_LIB "${FRAMEWORK_PATH}/CoreMIDI.framework")
+    set(CORESERVICES_LIB "${FRAMEWORK_PATH}/CoreServices.framework")
+    set(PM_NEEDED_LIBS ${COREAUDIO_LIB} ${COREFOUNDATION_LIB}
+                             ${COREMIDI_LIB} ${CORESERVICES_LIB}
+        CACHE INTERNAL "")
+
+    set(JAVAVM_LIB "${FRAMEWORK_PATH}/JavaVM.framework")
+    set(JAVA_INCLUDE_PATHS ${JAVAVM_LIB}/Headers)
+    message(STATUS "SYSROOT: " ${CMAKE_OSX_SYSROOT})
+  else(APPLE)
+    # LINUX settings...
+    include(FindJNI)
+    message(STATUS "JAVA_JVM_LIB_PATH is " ${JAVA_JVM_LIB_PATH})
+    message(STATUS "JAVA_INCLUDE_PATH is " ${JAVA_INCLUDE_PATH})
+    message(STATUS "JAVA_INCLUDE_PATH2 is " ${JAVA_INCLUDE_PATH2})
+    message(STATUS "JAVA_JVM_LIBRARY is " ${JAVA_JVM_LIBRARY})
+    set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})
+    # libjvm.so is found relative to JAVA_INCLUDE_PATH:
+    set(JAVAVM_LIB ${JAVA_JVM_LIBRARY}/libjvm.so)
+
+    set(LINUXSRC pmlinuxalsa pmlinux finddefault)
+    prepend_path(LIBSRC ../pm_linux/ ${LINUXSRC})
+    list(APPEND LIBSRC ../porttime/ptlinux)
+
+    set(PM_NEEDED_LIBS pthread asound)
+  endif(APPLE)
+else(UNIX)
+  if(WIN32)
+    # /MDd is multithread debug DLL, /MTd is multithread debug
+    # /MD is multithread DLL, /MT is multithread. Change to static:
+    include(../pm_win/static.cmake)
+    
+    include(FindJNI)
+
+    set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})
+    # message(STATUS "JAVA_INCLUDE_PATHS: " ${JAVA_INCLUDE_PATHS})
+
+    set(WINSRC pmwin pmwinmm)
+    prepend_path(LIBSRC ../pm_win/ ${WINSRC})
+    list(APPEND LIBSRC ../porttime/ptwinmm)
+    set(PM_NEEDED_LIBS winmm.lib)
+  endif(WIN32)
+endif(UNIX)
+set(JNI_EXTRA_LIBS ${PM_NEEDED_LIBS} ${JAVA_JVM_LIBRARY})
+
+# this completes the list of library sources by adding shared code
+list(APPEND LIBSRC pmutil portmidi)
+
+# now add the shared files to make the complete list of library sources
+add_library(portmidi-static ${LIBSRC})
+set_target_properties(portmidi-static PROPERTIES OUTPUT_NAME "portmidi_s")
+target_link_libraries(portmidi-static ${PM_NEEDED_LIBS})
+
+# define the jni library
+include_directories(${JAVA_INCLUDE_PATHS})
+
+set(JNISRC ${LIBSRC} ../pm_java/pmjni/pmjni.c)
+add_library(pmjni SHARED ${JNISRC})
+target_link_libraries(pmjni ${JNI_EXTRA_LIBS})
+set_target_properties(pmjni PROPERTIES EXECUTABLE_EXTENSION "jnilib")
+
+# install the libraries (Linux and Mac OS X command line)
+if(UNIX)
+  INSTALL(TARGETS portmidi-static pmjni
+    LIBRARY DESTINATION /usr/local/lib
+    ARCHIVE DESTINATION /usr/local/lib)
+# .h files installed by pm_dylib/CMakeLists.txt, so don't need them here
+#  INSTALL(FILES portmidi.h ../porttime/porttime.h
+#    DESTINATION /usr/local/include)
+endif(UNIX)
diff --git a/pd/portmidi/pm_common/pminternal.h b/pd/portmidi/pm_common/pminternal.h
old mode 100644
new mode 100755
index b8c0323257546e62b65ee6a0b54be2509db2f06f..f7c62705b70b6c64582c51af3d0df407323a573d
--- a/pd/portmidi/pm_common/pminternal.h
+++ b/pd/portmidi/pm_common/pminternal.h
@@ -21,6 +21,8 @@
 extern "C" {
 #endif
 
+extern int pm_initialized; /* see note in portmidi.c */
+
 /* these are defined in system-specific file */
 void *pm_alloc(size_t s);
 void pm_free(void *ptr);
@@ -93,7 +95,7 @@ extern int pm_descriptor_max;
 extern descriptor_type descriptors;
 extern int pm_descriptor_index;
 
-typedef unsigned long (*time_get_proc_type)(void *time_info);
+typedef uint32_t (*time_get_proc_type)(void *time_info);
 
 typedef struct pm_internal_struct {
     int device_id; /* which device is open (index to descriptors) */
@@ -101,18 +103,10 @@ typedef struct pm_internal_struct {
     
     PmTimeProcPtr time_proc; /* where to get the time */
     void *time_info; /* pass this to get_time() */
-    long buffer_len; /* how big is the buffer or queue? */
-#ifdef NEWBUFFER
+    int32_t buffer_len; /* how big is the buffer or queue? */
     PmQueue *queue;
-#else
-    PmEvent *buffer; /* storage for: 
-                        - midi input 
-                        - midi output w/latency != 0 */
-    long head;
-    long tail;
-    int overflow; /* set to non-zero if input is dropped */
-#endif
-    long latency; /* time delay in ms between timestamps and actual output */
+
+    int32_t latency; /* time delay in ms between timestamps and actual output */
                   /* set to zero to get immediate, simple blocking output */
                   /* if latency is zero, timestamps will be ignored; */
                   /* if midi input device, this field ignored */
@@ -128,8 +122,8 @@ typedef struct pm_internal_struct {
     PmMessage sysex_message; /* buffer for 4 bytes of sysex data */
     int sysex_message_count; /* how many bytes in sysex_message so far */
 
-    long filters; /* flags that filter incoming message classes */
-    int channel_mask; /* flter incoming messages based on channel */
+    int32_t filters; /* flags that filter incoming message classes */
+    int32_t channel_mask; /* filter incoming messages based on channel */
     PmTimestamp last_msg_time; /* timestamp of last message */
     PmTimestamp sync_time; /* time of last synchronization */
     PmTimestamp now; /* set by PmWrite to current time */
@@ -143,8 +137,8 @@ typedef struct pm_internal_struct {
      * important
      */
     unsigned char *fill_base; /* addr of ptr to sysex data */
-    int *fill_offset_ptr; /* offset of next sysex byte */
-    int fill_length; /* how many sysex bytes to write */
+    uint32_t *fill_offset_ptr; /* offset of next sysex byte */
+    int32_t fill_length; /* how many sysex bytes to write */
 } PmInternal;
 
 
@@ -163,7 +157,7 @@ PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp);
 PmError pm_success_fn(PmInternal *midi);
 PmError pm_add_device(char *interf, char *name, int input, void *descriptor,
                       pm_fns_type dictionary);
-unsigned int pm_read_bytes(PmInternal *midi, unsigned char *data, int len,
+uint32_t pm_read_bytes(PmInternal *midi, const unsigned char *data, int len,
                            PmTimestamp timestamp);
 void pm_read_short(PmInternal *midi, PmEvent *event);
 
@@ -176,6 +170,8 @@ void pm_read_short(PmInternal *midi, PmEvent *event);
 #define is_real_time(msg) \
     ((Pm_MessageStatus(msg) & MIDI_REALTIME_MASK) == MIDI_REALTIME_MASK)
 
+int pm_find_default_device(char *pattern, int is_input);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/pd/portmidi/pm_common/pmjni.vcproj b/pd/portmidi/pm_common/pmjni.vcproj
new file mode 100644
index 0000000000000000000000000000000000000000..5f3c663a7b334dc0bbc77b36f487efd837ebed1f
--- /dev/null
+++ b/pd/portmidi/pm_common/pmjni.vcproj
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="pmjni"
+	ProjectGUID="{87B548BD-F5CE-4D1F-9181-390966AC5855}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="pmjni.dir\Debug"
+			ConfigurationType="2"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;&quot;C:\Program Files\Java\jdk1.6.0_16\include&quot;;&quot;C:\Program Files\Java\jdk1.6.0_16\include\win32&quot;;"
+				BasicRuntimeChecks="3"
+				CompileAs="1"
+				DebugInformationFormat="3"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="0"
+				Optimization="0"
+				RuntimeLibrary="1"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;,pmjni_EXPORTS"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../Debug/pmjni.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;&quot;C:\Program Files\Java\jdk1.6.0_16\include&quot;;&quot;C:\Program Files\Java\jdk1.6.0_16\include\win32&quot;;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;,pmjni_EXPORTS"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;,pmjni_EXPORTS"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  winmm.lib &quot;C:\Program Files\Java\jdk1.6.0_16\include\..\lib\jvm.lib&quot; "
+				OutputFile="..\Debug\pmjni.dll"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="..\Debug\pmjni.pdb"
+				GenerateDebugInformation="TRUE"
+				ImportLibrary="..\Debug\pmjni.lib"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="pmjni.dir\Release"
+			ConfigurationType="2"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;&quot;C:\Program Files\Java\jdk1.6.0_16\include&quot;;&quot;C:\Program Files\Java\jdk1.6.0_16\include\win32&quot;;"
+				CompileAs="1"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="2"
+				Optimization="2"
+				RuntimeLibrary="0"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;,pmjni_EXPORTS"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../Release/pmjni.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;&quot;C:\Program Files\Java\jdk1.6.0_16\include&quot;;&quot;C:\Program Files\Java\jdk1.6.0_16\include\win32&quot;;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;,pmjni_EXPORTS"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;,pmjni_EXPORTS"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  winmm.lib &quot;C:\Program Files\Java\jdk1.6.0_16\include\..\lib\jvm.lib&quot; "
+				OutputFile="..\Release\pmjni.dll"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="..\Release\pmjni.pdb"
+				ImportLibrary="..\Release\pmjni.lib"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="">
+			<File
+				RelativePath="..\pm_win\pmwin.c">
+			</File>
+			<File
+				RelativePath="..\pm_win\pmwinmm.c">
+			</File>
+			<File
+				RelativePath="..\porttime\ptwinmm.c">
+			</File>
+			<File
+				RelativePath="..\pm_common\pmutil.c">
+			</File>
+			<File
+				RelativePath="..\pm_common\portmidi.c">
+			</File>
+			<File
+				RelativePath="..\pm_java\pmjni\pmjni.c">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_common/pmutil.c b/pd/portmidi/pm_common/pmutil.c
old mode 100644
new mode 100755
index 42f386c1df8d5d371ca3d8559b64f21f5ae5df87..a70fe2fa1f817bc7891b8729bcc01a9ef43d30f5
--- a/pd/portmidi/pm_common/pmutil.c
+++ b/pd/portmidi/pm_common/pmutil.c
@@ -1,311 +1,284 @@
-/* pmutil.c -- some helpful utilities for building midi
-               applications that use PortMidi
- */
-#include "stdlib.h"
-#include "assert.h"
-#include "memory.h"
-#include "portmidi.h"
-#include "pmutil.h"
-#include "pminternal.h"
-
-#ifdef WIN32
-#define bzero(addr, siz) memset(addr, 0, siz)
-#endif
-
-// #define QUEUE_DEBUG 1
-#ifdef QUEUE_DEBUG
-#include "stdio.h"
-#endif
-
-/* code is based on 4-byte words -- it should work on a 64-bit machine
-   as long as a "long" has 4 bytes. This code could be generalized to
-   be independent of the size of "long" */
-
-typedef long int32;
-
-typedef struct {
-    long head;
-    long tail;
-    long len;
-    long msg_size; /* number of int32 in a message including extra word */
-    long overflow;
-    long peek_overflow;
-    int32 *buffer;
-    int32 *peek;
-    int peek_flag;
-} PmQueueRep;
-
-
-PmQueue *Pm_QueueCreate(long num_msgs, long bytes_per_msg)
-{
-    PmQueueRep *queue = (PmQueueRep *) pm_alloc(sizeof(PmQueueRep));
-    int int32s_per_msg = ((bytes_per_msg + sizeof(int32) - 1) &
-                          ~(sizeof(int32) - 1)) / sizeof(int32);
-    /* arg checking */
-    if (!queue) 
-        return NULL;
-
-    /* need extra word per message for non-zero encoding */
-    queue->len = num_msgs * (int32s_per_msg + 1);
-    queue->buffer = (int32 *) pm_alloc(queue->len * sizeof(int32));
-    bzero(queue->buffer, queue->len * sizeof(int32));
-    if (!queue->buffer) {
-        pm_free(queue);
-        return NULL;
-    } else { /* allocate the "peek" buffer */
-        queue->peek = (int32 *) pm_alloc(int32s_per_msg * sizeof(int32));
-        if (!queue->peek) {
-            /* free everything allocated so far and return */
-            pm_free(queue->buffer);
-            pm_free(queue);
-            return NULL;
-        }
-    }
-    bzero(queue->buffer, queue->len * sizeof(int32));
-    queue->head = 0;
-    queue->tail = 0;
-    /* msg_size is in words */
-    queue->msg_size = int32s_per_msg + 1; /* note extra word is counted */
-    queue->overflow = FALSE;
-    queue->peek_overflow = FALSE;
-    queue->peek_flag = FALSE;
-    return queue;
-}
-
-
-PmError Pm_QueueDestroy(PmQueue *q)
-{
-    PmQueueRep *queue = (PmQueueRep *) q;
-        
-        /* arg checking */
-    if (!queue || !queue->buffer || !queue->peek) 
-                return pmBadPtr;
-    
-    pm_free(queue->peek);
-    pm_free(queue->buffer);
-    pm_free(queue);
-    return pmNoError;
-}
-
-
-PmError Pm_Dequeue(PmQueue *q, void *msg)
-{
-    long head;
-    PmQueueRep *queue = (PmQueueRep *) q;
-    int i;
-    int32 *msg_as_int32 = (int32 *) msg;
-
-    /* arg checking */
-    if (!queue)
-        return pmBadPtr;
-    /* a previous peek operation encountered an overflow, but the overflow
-     * has not yet been reported to client, so do it now. No message is
-     * returned, but on the next call, we will return the peek buffer.
-     */
-    if (queue->peek_overflow) {
-        queue->peek_overflow = FALSE;
-        return pmBufferOverflow;
-    }
-    if (queue->peek_flag) {
-#ifdef QUEUE_DEBUG
-        printf("Pm_Dequeue returns peek msg:");
-        for (i = 0; i < queue->msg_size - 1; i++) {
-            printf(" %d", queue->peek[i]);
-        }
-        printf("\n");
-#endif
-        memcpy(msg, queue->peek, (queue->msg_size - 1) * sizeof(int32));
-        queue->peek_flag = FALSE;
-        return 1;
-    }
-
-    head = queue->head;
-    /* if writer overflows, it writes queue->overflow = tail+1 so that
-     * when the reader gets to that position in the buffer, it can 
-     * return the overflow condition to the reader. The problem is that
-     * at overflow, things have wrapped around, so tail == head, and the
-     * reader will detect overflow immediately instead of waiting until
-     * it reads everything in the buffer, wrapping around again to the
-     * point where tail == head. So the condition also checks that
-     * queue->buffer[head] is zero -- if so, then the buffer is now
-     * empty, and we're at the point in the msg stream where overflow
-     * occurred. It's time to signal overflow to the reader. If 
-     * queue->buffer[head] is non-zero, there's a message there and we
-     * should read all the way around the buffer before signalling overflow.
-     * There is a write-order dependency here, but to fail, the overflow
-     * field would have to be written while an entire buffer full of 
-     * writes are still pending. I'm assuming out-of-order writes are
-     * possible, but not that many.
-     */
-    if (queue->overflow == head + 1 && !queue->buffer[head]) {
-        queue->overflow = 0; /* non-overflow condition */
-        return pmBufferOverflow;
-    }
-
-    /* test to see if there is data in the queue -- test from back
-     * to front so if writer is simultaneously writing, we don't
-     * waste time discovering the write is not finished 
-     */
-    for (i = queue->msg_size - 1; i >= 0; i--) {
-        if (!queue->buffer[head + i]) {
-            return 0;
-        }
-    }
-#ifdef QUEUE_DEBUG
-    printf("Pm_Dequeue:");
-    for (i = 0; i < queue->msg_size; i++) {
-        printf(" %d", queue->buffer[head + i]);
-    }
-    printf("\n");
-#endif
-    memcpy(msg, (char *) &queue->buffer[head + 1], 
-           sizeof(int32) * (queue->msg_size - 1));
-    /* fix up zeros */
-    i = queue->buffer[head];
-    while (i < queue->msg_size) {
-        int32 j;
-        i--; /* msg does not have extra word so shift down */
-        j = msg_as_int32[i];
-        msg_as_int32[i] = 0;
-        i = j;
-    }
-    /* signal that data has been removed by zeroing: */
-    bzero((char *) &queue->buffer[head], sizeof(int32) * queue->msg_size);
-
-    /* update head */
-    head += queue->msg_size;
-    if (head == queue->len) head = 0;
-    queue->head = head;
-    return 1; /* success */
-}
-
-
-
-PmError Pm_SetOverflow(PmQueue *q)
-{
-    PmQueueRep *queue = (PmQueueRep *) q;
-    long tail;
-    /* no more enqueue until receiver acknowledges overflow */
-    if (queue->overflow) return pmBufferOverflow;
-    if (!queue)
-        return pmBadPtr;
-    tail = queue->tail;
-    queue->overflow = tail + 1;
-    return pmBufferOverflow;
-}
-
-
-PmError Pm_Enqueue(PmQueue *q, void *msg)
-{
-    PmQueueRep *queue = (PmQueueRep *) q;
-    long tail;
-    int i;
-    int32 *src = (int32 *) msg;
-    int32 *ptr;
-
-    int32 *dest;
-
-    int rslt;
-    /* no more enqueue until receiver acknowledges overflow */
-    if (!queue) return pmBadPtr;
-    if (queue->overflow) return pmBufferOverflow;
-    rslt = Pm_QueueFull(q);
-    /* already checked above: if (rslt == pmBadPtr) return rslt; */
-    tail = queue->tail;
-    if (rslt) {
-        queue->overflow = tail + 1;
-        return pmBufferOverflow;
-    }
-
-    /* queue is has room for message, and overflow flag is cleared */
-    ptr = &queue->buffer[tail];
-    dest = ptr + 1;
-    for (i = 1; i < queue->msg_size; i++) {
-        int32 j = src[i - 1];
-        if (!j) {
-            *ptr = i;
-            ptr = dest;
-        } else {
-            *dest = j;
-        }
-        dest++;
-    }
-    *ptr = i;
-#ifdef QUEUE_DEBUG
-    printf("Pm_Enqueue:");
-    for (i = 0; i < queue->msg_size; i++) {
-        printf(" %d", queue->buffer[tail + i]);
-    }
-    printf("\n");
-#endif
-    tail += queue->msg_size;
-    if (tail == queue->len) tail = 0;
-    queue->tail = tail;
-    return pmNoError;
-}
-
-
-int Pm_QueueEmpty(PmQueue *q)
-{ 
-    PmQueueRep *queue = (PmQueueRep *) q;
-    if (!queue) return TRUE;
-    return (queue->buffer[queue->head] == 0);
-}
-
-
-int Pm_QueueFull(PmQueue *q)
-{
-    PmQueueRep *queue = (PmQueueRep *) q;
-    int tail;
-    int i; 
-    /* arg checking */
-    if (!queue)
-        return pmBadPtr;
-    tail = queue->tail;
-    /* test to see if there is space in the queue */
-    for (i = 0; i < queue->msg_size; i++) {
-        if (queue->buffer[tail + i]) {
-            return TRUE;
-        }
-    }
-    return FALSE;
-}
-
-void *Pm_QueuePeek(PmQueue *q)
-{
-    PmQueueRep *queue = (PmQueueRep *) q;
-    PmError rslt;
-    long temp;
-
-    /* arg checking */
-    if (!queue)
-        return NULL;
-
-    if (queue->peek_flag) {
-        return queue->peek;
-    }
-    /* this is ugly: if peek_overflow is set, then Pm_Dequeue() 
-     * returns immediately with pmBufferOverflow, but here, we
-     * want Pm_Dequeue() to really check for data. If data is
-     * there, we can return it
-     */
-    temp = queue->peek_overflow;
-    queue->peek_overflow = FALSE;
-    rslt = Pm_Dequeue(q, queue->peek);
-    queue->peek_overflow = temp;
-
-    if (rslt == 1) {
-        queue->peek_flag = TRUE;
-        return queue->peek;
-    } else if (rslt == pmBufferOverflow) {
-        /* when overflow is indicated, the queue is empty and the 
-         * first message that was dropped by Enqueue (signalling
-         * pmBufferOverflow to its caller) would have been the next
-         * message in the queue. Pm_QueuePeek will return NULL, but
-         * remember that an overflow occurred. (see Pm_Dequeue)
-         */
-        queue->peek_overflow = TRUE;
-    }
-    return NULL;
-}
-
+/* pmutil.c -- some helpful utilities for building midi
+               applications that use PortMidi
+ */
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include "portmidi.h"
+#include "pmutil.h"
+#include "pminternal.h"
+
+#ifdef WIN32
+#define bzero(addr, siz) memset(addr, 0, siz)
+#endif
+
+// #define QUEUE_DEBUG 1
+#ifdef QUEUE_DEBUG
+#include "stdio.h"
+#endif
+
+typedef struct {
+    long head;
+    long tail;
+    long len;
+    long overflow;
+    int32_t msg_size; /* number of int32_t in a message including extra word */
+    int32_t peek_overflow;
+    int32_t *buffer;
+    int32_t *peek;
+    int32_t peek_flag;
+} PmQueueRep;
+
+
+PMEXPORT PmQueue *Pm_QueueCreate(long num_msgs, int32_t bytes_per_msg)
+{
+    int32_t int32s_per_msg = 
+            (int32_t) (((bytes_per_msg + sizeof(int32_t) - 1) &
+                       ~(sizeof(int32_t) - 1)) / sizeof(int32_t));
+    PmQueueRep *queue = (PmQueueRep *) pm_alloc(sizeof(PmQueueRep));
+    if (!queue) /* memory allocation failed */
+        return NULL;
+
+    /* need extra word per message for non-zero encoding */
+    queue->len = num_msgs * (int32s_per_msg + 1);
+    queue->buffer = (int32_t *) pm_alloc(queue->len * sizeof(int32_t));
+    bzero(queue->buffer, queue->len * sizeof(int32_t));
+    if (!queue->buffer) {
+        pm_free(queue);
+        return NULL;
+    } else { /* allocate the "peek" buffer */
+        queue->peek = (int32_t *) pm_alloc(int32s_per_msg * sizeof(int32_t));
+        if (!queue->peek) {
+            /* free everything allocated so far and return */
+            pm_free(queue->buffer);
+            pm_free(queue);
+            return NULL;
+        }
+    }
+    bzero(queue->buffer, queue->len * sizeof(int32_t));
+    queue->head = 0;
+    queue->tail = 0;
+    /* msg_size is in words */
+    queue->msg_size = int32s_per_msg + 1; /* note extra word is counted */
+    queue->overflow = FALSE;
+    queue->peek_overflow = FALSE;
+    queue->peek_flag = FALSE;
+    return queue;
+}
+
+
+PMEXPORT PmError Pm_QueueDestroy(PmQueue *q)
+{
+    PmQueueRep *queue = (PmQueueRep *) q;
+        
+    /* arg checking */
+    if (!queue || !queue->buffer || !queue->peek) 
+                return pmBadPtr;
+    
+    pm_free(queue->peek);
+    pm_free(queue->buffer);
+    pm_free(queue);
+    return pmNoError;
+}
+
+
+PMEXPORT PmError Pm_Dequeue(PmQueue *q, void *msg)
+{
+    long head;
+    PmQueueRep *queue = (PmQueueRep *) q;
+    int i;
+    int32_t *msg_as_int32 = (int32_t *) msg;
+
+    /* arg checking */
+    if (!queue)
+        return pmBadPtr;
+    /* a previous peek operation encountered an overflow, but the overflow
+     * has not yet been reported to client, so do it now. No message is
+     * returned, but on the next call, we will return the peek buffer.
+     */
+    if (queue->peek_overflow) {
+        queue->peek_overflow = FALSE;
+        return pmBufferOverflow;
+    }
+    if (queue->peek_flag) {
+        memcpy(msg, queue->peek, (queue->msg_size - 1) * sizeof(int32_t));
+        queue->peek_flag = FALSE;
+        return pmGotData;
+    }
+
+    head = queue->head;
+    /* if writer overflows, it writes queue->overflow = tail+1 so that
+     * when the reader gets to that position in the buffer, it can 
+     * return the overflow condition to the reader. The problem is that
+     * at overflow, things have wrapped around, so tail == head, and the
+     * reader will detect overflow immediately instead of waiting until
+     * it reads everything in the buffer, wrapping around again to the
+     * point where tail == head. So the condition also checks that
+     * queue->buffer[head] is zero -- if so, then the buffer is now
+     * empty, and we're at the point in the msg stream where overflow
+     * occurred. It's time to signal overflow to the reader. If 
+     * queue->buffer[head] is non-zero, there's a message there and we
+     * should read all the way around the buffer before signalling overflow.
+     * There is a write-order dependency here, but to fail, the overflow
+     * field would have to be written while an entire buffer full of 
+     * writes are still pending. I'm assuming out-of-order writes are
+     * possible, but not that many.
+     */
+    if (queue->overflow == head + 1 && !queue->buffer[head]) {
+        queue->overflow = 0; /* non-overflow condition */
+        return pmBufferOverflow;
+    }
+
+    /* test to see if there is data in the queue -- test from back
+     * to front so if writer is simultaneously writing, we don't
+     * waste time discovering the write is not finished 
+     */
+    for (i = queue->msg_size - 1; i >= 0; i--) {
+        if (!queue->buffer[head + i]) {
+            return pmNoData;
+        }
+    }
+    memcpy(msg, (char *) &queue->buffer[head + 1], 
+           sizeof(int32_t) * (queue->msg_size - 1));
+    /* fix up zeros */
+    i = queue->buffer[head];
+    while (i < queue->msg_size) {
+        int32_t j;
+        i--; /* msg does not have extra word so shift down */
+        j = msg_as_int32[i];
+        msg_as_int32[i] = 0;
+        i = j;
+    }
+    /* signal that data has been removed by zeroing: */
+    bzero((char *) &queue->buffer[head], sizeof(int32_t) * queue->msg_size);
+
+    /* update head */
+    head += queue->msg_size;
+    if (head == queue->len) head = 0;
+    queue->head = head;
+    return pmGotData; /* success */
+}
+
+
+
+PMEXPORT PmError Pm_SetOverflow(PmQueue *q)
+{
+    PmQueueRep *queue = (PmQueueRep *) q;
+    long tail;
+    /* arg checking */
+    if (!queue)
+        return pmBadPtr;
+    /* no more enqueue until receiver acknowledges overflow */
+    if (queue->overflow) return pmBufferOverflow;
+    tail = queue->tail;
+    queue->overflow = tail + 1;
+    return pmBufferOverflow;
+}
+
+
+PMEXPORT PmError Pm_Enqueue(PmQueue *q, void *msg)
+{
+    PmQueueRep *queue = (PmQueueRep *) q;
+    long tail;
+    int i;
+    int32_t *src = (int32_t *) msg;
+    int32_t *ptr;
+    int32_t *dest;
+    int rslt;
+    if (!queue) 
+        return pmBadPtr;
+    /* no more enqueue until receiver acknowledges overflow */
+    if (queue->overflow) return pmBufferOverflow;
+    rslt = Pm_QueueFull(q);
+    /* already checked above: if (rslt == pmBadPtr) return rslt; */
+    tail = queue->tail;
+    if (rslt) {
+        queue->overflow = tail + 1;
+        return pmBufferOverflow;
+    }
+
+    /* queue is has room for message, and overflow flag is cleared */
+    ptr = &queue->buffer[tail];
+    dest = ptr + 1;
+    for (i = 1; i < queue->msg_size; i++) {
+        int32_t j = src[i - 1];
+        if (!j) {
+            *ptr = i;
+            ptr = dest;
+        } else {
+            *dest = j;
+        }
+        dest++;
+    }
+    *ptr = i;
+    tail += queue->msg_size;
+    if (tail == queue->len) tail = 0;
+    queue->tail = tail;
+    return pmNoError;
+}
+
+
+PMEXPORT int Pm_QueueEmpty(PmQueue *q)
+{
+    PmQueueRep *queue = (PmQueueRep *) q;
+    return (!queue) ||  /* null pointer -> return "empty" */
+           (queue->buffer[queue->head] == 0 && !queue->peek_flag);
+}
+
+
+PMEXPORT int Pm_QueueFull(PmQueue *q)
+{
+    long tail;
+    int i; 
+    PmQueueRep *queue = (PmQueueRep *) q;
+    /* arg checking */
+    if (!queue)
+        return pmBadPtr;
+    tail = queue->tail;
+    /* test to see if there is space in the queue */
+    for (i = 0; i < queue->msg_size; i++) {
+        if (queue->buffer[tail + i]) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+
+PMEXPORT void *Pm_QueuePeek(PmQueue *q)
+{
+    PmError rslt;
+    int32_t temp;
+    PmQueueRep *queue = (PmQueueRep *) q;
+    /* arg checking */
+    if (!queue)
+        return NULL;
+
+    if (queue->peek_flag) {
+        return queue->peek;
+    }
+    /* this is ugly: if peek_overflow is set, then Pm_Dequeue() 
+     * returns immediately with pmBufferOverflow, but here, we
+     * want Pm_Dequeue() to really check for data. If data is
+     * there, we can return it
+     */
+    temp = queue->peek_overflow;
+    queue->peek_overflow = FALSE;
+    rslt = Pm_Dequeue(q, queue->peek);
+    queue->peek_overflow = temp;
+
+    if (rslt == 1) {
+        queue->peek_flag = TRUE;
+        return queue->peek;
+    } else if (rslt == pmBufferOverflow) {
+        /* when overflow is indicated, the queue is empty and the 
+         * first message that was dropped by Enqueue (signalling
+         * pmBufferOverflow to its caller) would have been the next
+         * message in the queue. Pm_QueuePeek will return NULL, but
+         * remember that an overflow occurred. (see Pm_Dequeue)
+         */
+        queue->peek_overflow = TRUE;
+    }
+    return NULL;
+}
+
diff --git a/pd/portmidi/pm_common/pmutil.h b/pd/portmidi/pm_common/pmutil.h
old mode 100644
new mode 100755
index 8e4294670f5b770c9542da3829ce03403fd458aa..40dabbff0e769a13e47e145aa6449394d59802ec
--- a/pd/portmidi/pm_common/pmutil.h
+++ b/pd/portmidi/pm_common/pmutil.h
@@ -44,8 +44,8 @@ typedef void PmQueue;
     Pm_QueueDestroy() destroys the queue and frees its storage.
  */
 
-PmQueue *Pm_QueueCreate(long num_msgs, long bytes_per_msg);
-PmError Pm_QueueDestroy(PmQueue *queue);
+PMEXPORT PmQueue *Pm_QueueCreate(long num_msgs, int32_t bytes_per_msg);
+PMEXPORT PmError Pm_QueueDestroy(PmQueue *queue);
 
 /* 
     Pm_Dequeue() removes one item from the queue, copying it into msg.
@@ -56,7 +56,7 @@ PmError Pm_QueueDestroy(PmQueue *queue);
     overflow report. This protocol ensures that the reader will be 
     notified when data is lost due to overflow.
  */
-PmError Pm_Dequeue(PmQueue *queue, void *msg);
+PMEXPORT PmError Pm_Dequeue(PmQueue *queue, void *msg);
 
 
 /*
@@ -64,7 +64,7 @@ PmError Pm_Dequeue(PmQueue *queue, void *msg);
     Returns pmNoError if successful and pmBufferOverflow if the queue was 
     already full. If pmBufferOverflow is returned, the overflow flag is set.
  */
-PmError Pm_Enqueue(PmQueue *queue, void *msg);
+PMEXPORT PmError Pm_Enqueue(PmQueue *queue, void *msg);
 
 
 /*
@@ -78,9 +78,12 @@ PmError Pm_Enqueue(PmQueue *queue, void *msg);
     Pm_Dequeue() could still return 0 after Pm_QueueEmpty() returns
     false. On the other hand, Pm_QueueFull() is pessimistic: if it
     returns false, then Pm_Enqueue() is guaranteed to succeed. 
+
+    Error conditions: Pm_QueueFull() returns pmBadPtr if queue is NULL.
+    Pm_QueueEmpty() returns FALSE if queue is NULL.
  */
-int Pm_QueueFull(PmQueue *queue);
-int Pm_QueueEmpty(PmQueue *queue);
+PMEXPORT int Pm_QueueFull(PmQueue *queue);
+PMEXPORT int Pm_QueueEmpty(PmQueue *queue);
 
 
 /*
@@ -106,7 +109,7 @@ int Pm_QueueEmpty(PmQueue *queue);
     Note that Pm_QueuePeek() is not a fast check, so if possible, you 
     might as well just call Pm_Dequeue() and accept the data if it is there.
  */
-void *Pm_QueuePeek(PmQueue *queue);
+PMEXPORT void *Pm_QueuePeek(PmQueue *queue);
 
 /*
     Pm_SetOverflow() allows the writer (enqueuer) to signal an overflow
@@ -117,7 +120,7 @@ void *Pm_QueuePeek(PmQueue *queue);
     is NULL, returns pmBufferOverflow if buffer is already in an overflow
     state, returns pmNoError if successfully set overflow state.
  */
-PmError Pm_SetOverflow(PmQueue *queue);
+PMEXPORT PmError Pm_SetOverflow(PmQueue *queue);
 
 #ifdef __cplusplus
 }
diff --git a/pd/portmidi/pm_common/portmidi-dynamic.vcproj b/pd/portmidi/pm_common/portmidi-dynamic.vcproj
new file mode 100644
index 0000000000000000000000000000000000000000..788c369635b6028d4b696bfb63e736b7484eb7be
--- /dev/null
+++ b/pd/portmidi/pm_common/portmidi-dynamic.vcproj
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="portmidi-dynamic"
+	ProjectGUID="{7283FAD1-7415-4061-A19A-FF5C7BCE9306}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="portmidi-dynamic.dir\Debug"
+			ConfigurationType="2"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="C:\Users\rbd\portmedia\portmidi\pm_common;C:\Users\rbd\portmedia\portmidi\porttime;&quot;C:\Program Files\Java\jdk1.6.0_16\include&quot;;&quot;C:\Program Files\Java\jdk1.6.0_16\include\win32&quot;;"
+				BasicRuntimeChecks="3"
+				CompileAs="1"
+				DebugInformationFormat="3"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="0"
+				Optimization="0"
+				RuntimeLibrary="3"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;,portmidi_dynamic_EXPORTS"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="C:/Users/rbd/portmedia/portmidi/Debug/portmidi.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="C:\Users\rbd\portmedia\portmidi\pm_common;C:\Users\rbd\portmedia\portmidi\porttime;&quot;C:\Program Files\Java\jdk1.6.0_16\include&quot;;&quot;C:\Program Files\Java\jdk1.6.0_16\include\win32&quot;;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;,portmidi_dynamic_EXPORTS"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;,portmidi_dynamic_EXPORTS"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  winmm.lib "
+				OutputFile="C:\Users\rbd\portmedia\portmidi\Debug\portmidi.dll"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="C:\Users\rbd\portmedia\portmidi\Debug\portmidi.pdb"
+				GenerateDebugInformation="TRUE"
+				ImportLibrary="C:\Users\rbd\portmedia\portmidi\Debug\portmidi.lib"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="portmidi-dynamic.dir\Release"
+			ConfigurationType="2"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="C:\Users\rbd\portmedia\portmidi\pm_common;C:\Users\rbd\portmedia\portmidi\porttime;&quot;C:\Program Files\Java\jdk1.6.0_16\include&quot;;&quot;C:\Program Files\Java\jdk1.6.0_16\include\win32&quot;;"
+				CompileAs="1"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="2"
+				Optimization="2"
+				RuntimeLibrary="2"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;,portmidi_dynamic_EXPORTS"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="C:/Users/rbd/portmedia/portmidi/Release/portmidi.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="C:\Users\rbd\portmedia\portmidi\pm_common;C:\Users\rbd\portmedia\portmidi\porttime;&quot;C:\Program Files\Java\jdk1.6.0_16\include&quot;;&quot;C:\Program Files\Java\jdk1.6.0_16\include\win32&quot;;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;,portmidi_dynamic_EXPORTS"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;,portmidi_dynamic_EXPORTS"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  winmm.lib "
+				OutputFile="C:\Users\rbd\portmedia\portmidi\Release\portmidi.dll"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="C:\Users\rbd\portmedia\portmidi\Release\portmidi.pdb"
+				ImportLibrary="C:\Users\rbd\portmedia\portmidi\Release\portmidi.lib"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+			<File
+				RelativePath="C:\Users\rbd\portmedia\portmidi\pm_common\CMakeLists.txt">
+				<FileConfiguration
+					Name="Debug|Win32">
+					<Tool
+					Name="VCCustomBuildTool"
+					Description="Building Custom Rule C:/Users/rbd/portmedia/portmidi/pm_common/CMakeLists.txt"
+					CommandLine="&quot;C:\Program Files\CMake 2.6\bin\cmake.exe&quot; -HC:/Users/rbd/portmedia/portmidi -BC:/Users/rbd/portmedia/portmidi --check-stamp-file CMakeFiles/generate.stamp"
+					AdditionalDependencies="C:\Users\rbd\portmedia\portmidi\pm_common\CMakeLists.txt;&quot;C:\Program Files\CMake 2.6\share\cmake-2.6\Modules\FindJNI.cmake&quot;;C:\Users\rbd\portmedia\portmidi\pm_common\CMakeLists.txt;"
+					Outputs="CMakeFiles\generate.stamp"/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32">
+					<Tool
+					Name="VCCustomBuildTool"
+					Description="Building Custom Rule C:/Users/rbd/portmedia/portmidi/pm_common/CMakeLists.txt"
+					CommandLine="&quot;C:\Program Files\CMake 2.6\bin\cmake.exe&quot; -HC:/Users/rbd/portmedia/portmidi -BC:/Users/rbd/portmedia/portmidi --check-stamp-file CMakeFiles/generate.stamp"
+					AdditionalDependencies="C:\Users\rbd\portmedia\portmidi\pm_common\CMakeLists.txt;&quot;C:\Program Files\CMake 2.6\share\cmake-2.6\Modules\FindJNI.cmake&quot;;C:\Users\rbd\portmedia\portmidi\pm_common\CMakeLists.txt;"
+					Outputs="CMakeFiles\generate.stamp"/>
+				</FileConfiguration>
+			</File>
+		<Filter
+			Name="Source Files"
+			Filter="">
+			<File
+				RelativePath="C:\Users\rbd\portmedia\portmidi\pm_win\pmwin.c">
+			</File>
+			<File
+				RelativePath="C:\Users\rbd\portmedia\portmidi\pm_win\pmwinmm.c">
+			</File>
+			<File
+				RelativePath="C:\Users\rbd\portmedia\portmidi\porttime\ptwinmm.c">
+			</File>
+			<File
+				RelativePath="C:\Users\rbd\portmedia\portmidi\pm_common\pmutil.c">
+			</File>
+			<File
+				RelativePath="C:\Users\rbd\portmedia\portmidi\pm_common\portmidi.c">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_common/portmidi-static.vcproj b/pd/portmidi/pm_common/portmidi-static.vcproj
new file mode 100644
index 0000000000000000000000000000000000000000..91918d56f7af4641b7ad267674f6655a918685b2
--- /dev/null
+++ b/pd/portmidi/pm_common/portmidi-static.vcproj
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="portmidi-static"
+	ProjectGUID="{2985D5DA-D91E-44E0-924B-E612B6AA33F6}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="portmidi-static.dir\Debug"
+			ConfigurationType="4"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;&quot;C:\Program Files\Java\jdk1.6.0_16\include&quot;;&quot;C:\Program Files\Java\jdk1.6.0_16\include\win32&quot;;"
+				BasicRuntimeChecks="3"
+				CompileAs="1"
+				DebugInformationFormat="3"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="0"
+				Optimization="0"
+				RuntimeLibrary="1"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../Debug/portmidi_s.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;&quot;C:\Program Files\Java\jdk1.6.0_16\include&quot;;&quot;C:\Program Files\Java\jdk1.6.0_16\include\win32&quot;;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="..\Debug\portmidi_s.lib"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="portmidi-static.dir\Release"
+			ConfigurationType="4"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;&quot;C:\Program Files\Java\jdk1.6.0_16\include&quot;;&quot;C:\Program Files\Java\jdk1.6.0_16\include\win32&quot;;"
+				CompileAs="1"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="2"
+				Optimization="2"
+				RuntimeLibrary="0"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../Release/portmidi_s.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;&quot;C:\Program Files\Java\jdk1.6.0_16\include&quot;;&quot;C:\Program Files\Java\jdk1.6.0_16\include\win32&quot;;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="..\Release\portmidi_s.lib"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="">
+			<File
+				RelativePath="..\pm_win\pmwin.c">
+			</File>
+			<File
+				RelativePath="..\pm_win\pmwinmm.c">
+			</File>
+			<File
+				RelativePath="..\porttime\ptwinmm.c">
+			</File>
+			<File
+				RelativePath="..\pm_common\pmutil.c">
+			</File>
+			<File
+				RelativePath="..\pm_common\portmidi.c">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_common/portmidi.c b/pd/portmidi/pm_common/portmidi.c
old mode 100644
new mode 100755
index 71988e471bfba671c8789268b1312f8248ea4757..b7161700d69edea94dd40c3b1ddf483c0da9c657
--- a/pd/portmidi/pm_common/portmidi.c
+++ b/pd/portmidi/pm_common/portmidi.c
@@ -1,1184 +1,1137 @@
-#include "stdlib.h"
-#include "string.h"
-#include "portmidi.h"
-#include "porttime.h"
-#ifdef NEWBUFFER
-#include "pmutil.h"
-#endif
-#include "pminternal.h"
-#include <assert.h>
-
-#define MIDI_CLOCK      0xf8
-#define MIDI_ACTIVE     0xfe
-#define MIDI_STATUS_MASK 0x80
-#define MIDI_SYSEX      0xf0
-#define MIDI_EOX        0xf7
-#define MIDI_START      0xFA
-#define MIDI_STOP       0xFC
-#define MIDI_CONTINUE   0xFB
-#define MIDI_F9         0xF9
-#define MIDI_FD         0xFD
-#define MIDI_RESET      0xFF
-#define MIDI_NOTE_ON    0x90
-#define MIDI_NOTE_OFF   0x80
-#define MIDI_CHANNEL_AT 0xD0
-#define MIDI_POLY_AT    0xA0
-#define MIDI_PROGRAM    0xC0
-#define MIDI_CONTROL    0xB0
-#define MIDI_PITCHBEND  0xE0
-#define MIDI_MTC        0xF1
-#define MIDI_SONGPOS    0xF2
-#define MIDI_SONGSEL    0xF3
-#define MIDI_TUNE       0xF6
-
-#define is_empty(midi) ((midi)->tail == (midi)->head)
-
-static int pm_initialized = FALSE;
-int pm_hosterror;
-char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];
-
-#ifdef PM_CHECK_ERRORS
-
-#include <stdio.h>
-
-#define STRING_MAX 80
-
-static void prompt_and_exit(void)
-{
-    char line[STRING_MAX];
-    printf("type ENTER...");
-    fgets(line, STRING_MAX, stdin);
-    /* this will clean up open ports: */
-    exit(-1);
-}
-
-
-static PmError pm_errmsg(PmError err)
-{
-    if (err == pmHostError) {
-        /* it seems pointless to allocate memory and copy the string,
-         * so I will do the work of Pm_GetHostErrorText directly
-         */
-        printf("PortMidi found host error...\n  %s\n", pm_hosterror_text);
-        pm_hosterror = FALSE;
-        pm_hosterror_text[0] = 0; /* clear the message */
-        prompt_and_exit();
-    } else if (err < 0) {
-        printf("PortMidi call failed...\n  %s\n", Pm_GetErrorText(err));
-        prompt_and_exit();
-    }
-    return err;
-}
-#else
-#define pm_errmsg(err) err
-#endif
-
-/*
-====================================================================
-system implementation of portmidi interface
-====================================================================
-*/
-
-int pm_descriptor_max = 0;
-int pm_descriptor_index = 0;
-descriptor_type descriptors = NULL;
-
-/* pm_add_device -- describe interface/device pair to library 
- *
- * This is called at intialization time, once for each 
- * interface (e.g. DirectSound) and device (e.g. SoundBlaster 1)
- * The strings are retained but NOT COPIED, so do not destroy them!
- *
- * returns pmInvalidDeviceId if device memory is exceeded
- * otherwise returns pmNoError
- */
-PmError pm_add_device(char *interf, char *name, int input, 
-                      void *descriptor, pm_fns_type dictionary) {
-    if (pm_descriptor_index >= pm_descriptor_max) {
-        // expand descriptors
-        descriptor_type new_descriptors = 
-                pm_alloc(sizeof(descriptor_node) * (pm_descriptor_max + 32));
-        if (!new_descriptors) return pmInsufficientMemory;
-        if (descriptors) {
-            memcpy(new_descriptors, descriptors, 
-                   sizeof(descriptor_node) * pm_descriptor_max);
-            free(descriptors);
-        }
-        pm_descriptor_max += 32;
-        descriptors = new_descriptors;
-    }
-    descriptors[pm_descriptor_index].pub.interf = interf;
-    descriptors[pm_descriptor_index].pub.name = name;
-    descriptors[pm_descriptor_index].pub.input = input;
-    descriptors[pm_descriptor_index].pub.output = !input;
-
-    /* default state: nothing to close (for automatic device closing) */
-    descriptors[pm_descriptor_index].pub.opened = FALSE;
-
-    /* ID number passed to win32 multimedia API open */
-    descriptors[pm_descriptor_index].descriptor = descriptor;
-    
-    /* points to PmInternal, allows automatic device closing */
-    descriptors[pm_descriptor_index].internalDescriptor = NULL;
-
-    descriptors[pm_descriptor_index].dictionary = dictionary;
-    
-    pm_descriptor_index++;
-    
-    return pmNoError;
-}
-
-
-/*
-====================================================================
-portmidi implementation
-====================================================================
-*/
-
-int Pm_CountDevices( void ) {
-    Pm_Initialize();
-    /* no error checking -- Pm_Initialize() does not fail */
-    return pm_descriptor_index;
-}
-
-
-const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id ) {
-    Pm_Initialize(); /* no error check needed */
-    if (id >= 0 && id < pm_descriptor_index) {
-        return &descriptors[id].pub;
-    }
-    return NULL;
-}
-
-/* pm_success_fn -- "noop" function pointer */
-PmError pm_success_fn(PmInternal *midi) {
-    return pmNoError;
-}
-
-/* none_write -- returns an error if called */
-PmError none_write_short(PmInternal *midi, PmEvent *buffer) {
-    return pmBadPtr;
-}
-
-/* pm_fail_timestamp_fn -- placeholder for begin_sysex and flush */
-PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp) {
-    return pmBadPtr;
-}
-
-PmError none_write_byte(PmInternal *midi, unsigned char byte, 
-                        PmTimestamp timestamp) {
-    return pmBadPtr;
-}
-
-/* pm_fail_fn -- generic function, returns error if called */
-PmError pm_fail_fn(PmInternal *midi) {
-    return pmBadPtr;
-}
-
-static PmError none_open(PmInternal *midi, void *driverInfo) {
-    return pmBadPtr;
-}
-static void none_get_host_error(PmInternal * midi, char * msg, unsigned int len) {
-    strcpy(msg, "");
-}
-static unsigned int none_has_host_error(PmInternal * midi) {
-    return FALSE;
-}
-PmTimestamp none_synchronize(PmInternal *midi) {
-    return 0;
-}
-
-#define none_abort pm_fail_fn
-#define none_close pm_fail_fn
-
-pm_fns_node pm_none_dictionary = {
-    none_write_short,
-    none_sysex,
-    none_sysex,
-    none_write_byte,
-    none_write_short,
-    none_write_flush,
-    none_synchronize,
-    none_open,
-    none_abort, 
-    none_close,
-    none_poll,
-    none_has_host_error,
-    none_get_host_error 
-};
-
-
-const char *Pm_GetErrorText( PmError errnum ) {
-    const char *msg;
-
-    switch(errnum)
-    {
-    case pmNoError:                  
-        msg = ""; 
-        break;
-    case pmHostError:                
-        msg = "PortMidi: `Host error'"; 
-        break;
-    case pmInvalidDeviceId:          
-        msg = "PortMidi: `Invalid device ID'"; 
-        break;
-    case pmInsufficientMemory:       
-        msg = "PortMidi: `Insufficient memory'"; 
-        break;
-    case pmBufferTooSmall:           
-        msg = "PortMidi: `Buffer too small'"; 
-        break;
-    case pmBadPtr:                   
-        msg = "PortMidi: `Bad pointer'"; 
-        break;
-    case pmInternalError:            
-        msg = "PortMidi: `Internal PortMidi Error'"; 
-        break;
-    case pmBufferOverflow:
-        msg = "PortMidi: `Buffer overflow'";
-        break;
-    case pmBadData:
-        msg = "PortMidi: `Invalid MIDI message Data'";
-        break;
-    case pmBufferMaxSize:
-        msg = "PortMidi: `Buffer cannot be made larger'";
-        break;
-    default:                         
-        msg = "PortMidi: `Illegal error number'"; 
-        break;
-    }
-    return msg;
-}
-
-
-/* This can be called whenever you get a pmHostError return value.
- * The error will always be in the global pm_hosterror_text.
- */
-void Pm_GetHostErrorText(char * msg, unsigned int len) {
-    assert(msg);
-    assert(len > 0);
-    if (pm_hosterror) {
-        strncpy(msg, (char *) pm_hosterror_text, len);
-        pm_hosterror = FALSE;
-        pm_hosterror_text[0] = 0; /* clear the message; not necessary, but it
-                                     might help with debugging */
-        msg[len - 1] = 0; /* make sure string is terminated */
-    } else {
-        msg[0] = 0; /* no string to return */
-    }
-}
-
-
-int Pm_HasHostError(PortMidiStream * stream) {
-    if (pm_hosterror) return TRUE;
-    if (stream) {
-        PmInternal * midi = (PmInternal *) stream;
-        pm_hosterror = (*midi->dictionary->has_host_error)(midi);
-        if (pm_hosterror) {
-            midi->dictionary->host_error(midi, pm_hosterror_text, 
-                                         PM_HOST_ERROR_MSG_LEN);
-            /* now error message is global */
-            return TRUE;
-        }
-    }
-    return FALSE;
-}
-
-
-PmError Pm_Initialize( void ) {
-    if (!pm_initialized) {
-        pm_hosterror = FALSE;
-        pm_hosterror_text[0] = 0; /* the null string */
-        pm_init();
-        pm_initialized = TRUE;
-    }
-    return pmNoError;
-}
-
-
-PmError Pm_Terminate( void ) {
-    if (pm_initialized) {
-        pm_term();
-        // if there are no devices, descriptors might still be NULL
-        if (descriptors != NULL) {
-            free(descriptors);
-            descriptors = NULL;
-        }
-        pm_descriptor_index = 0;
-        pm_descriptor_max = 0;
-        pm_initialized = FALSE;
-    }
-    return pmNoError;
-}
-
-
-/* Pm_Read -- read up to length longs from source into buffer */
-/*
- * returns number of longs actually read, or error code
- */
-PmError Pm_Read(PortMidiStream *stream, PmEvent *buffer, long length) {
-    PmInternal *midi = (PmInternal *) stream;
-    int n = 0;
-#ifndef NEWBUFFER
-    long head;
-#endif
-    PmError err = pmNoError;
-    pm_hosterror = FALSE;
-    /* arg checking */
-    if(midi == NULL)
-        err = pmBadPtr;
-    else if(!descriptors[midi->device_id].pub.opened)
-        err = pmBadPtr;
-    else if(!descriptors[midi->device_id].pub.input)
-        err = pmBadPtr;    
-    /* First poll for data in the buffer...
-     * This either simply checks for data, or attempts first to fill the buffer
-     * with data from the MIDI hardware; this depends on the implementation.
-     * We could call Pm_Poll here, but that would redo a lot of redundant
-     * parameter checking, so I copied some code from Pm_Poll to here: */
-    else err = (*(midi->dictionary->poll))(midi);
-
-    if (err != pmNoError) {
-        if (err == pmHostError) {
-            midi->dictionary->host_error(midi, pm_hosterror_text, 
-                                         PM_HOST_ERROR_MSG_LEN);
-          pm_hosterror = TRUE;
-        }
-        return pm_errmsg(err);
-    }
-
-#ifdef NEWBUFFER
-    while (n < length) {
-        PmError err = Pm_Dequeue(midi->queue, buffer++);
-        if (err == pmBufferOverflow) {
-            /* ignore the data we have retreived so far */
-            return pm_errmsg(pmBufferOverflow);
-        } else if (err == 0) { /* empty queue */
-            break;
-        }
-        n++;
-    }
-#else
-    head = midi->head;
-    while (head != midi->tail && n < length) {
-        PmEvent event = midi->buffer[head++];
-        *buffer++ = event;
-        if (head == midi->buffer_len) head = 0;
-        n++;
-    }
-    midi->head = head;
-    if (midi->overflow) {
-        midi->head = midi->tail;
-        midi->overflow = FALSE;
-        return pm_errmsg(pmBufferOverflow);
-    }
-#endif
-    return n;
-}
-
-PmError Pm_Poll( PortMidiStream *stream )
-{
-    PmInternal *midi = (PmInternal *) stream;
-    PmError err;
-#ifdef NEWBUFFER
-    PmEvent *event;
-#endif
-
-    pm_hosterror = FALSE;
-    /* arg checking */
-    if(midi == NULL)
-        err = pmBadPtr;
-    else if(!descriptors[midi->device_id].pub.opened)
-        err = pmBadPtr;
-    else if(!descriptors[midi->device_id].pub.input)
-        err = pmBadPtr;
-    else
-        err = (*(midi->dictionary->poll))(midi);
-
-    if (err != pmNoError) {
-        if (err == pmHostError) {
-            midi->dictionary->host_error(midi, pm_hosterror_text, 
-                                         PM_HOST_ERROR_MSG_LEN);
-           pm_hosterror = TRUE;
-        }
-        return pm_errmsg(err);
-    }
-
-#ifdef NEWBUFFER
-    event = (PmEvent *) Pm_QueuePeek(midi->queue);
-    return event != NULL;
-#else
-    return midi->head != midi->tail;
-#endif
-}
-
-
-/* this is called from Pm_Write and Pm_WriteSysEx to issue a
- * call to the system-dependent end_sysex function and handle 
- * the error return
- */
-static PmError pm_end_sysex(PmInternal *midi)
-{
-    PmError err = (*midi->dictionary->end_sysex)(midi, 0);
-    midi->sysex_in_progress = FALSE;
-    if (err == pmHostError) {
-        midi->dictionary->host_error(midi, pm_hosterror_text, 
-                                     PM_HOST_ERROR_MSG_LEN);
-        pm_hosterror = TRUE;
-    }
-    return err;
-}
-
-
-/* to facilitate correct error-handling, Pm_Write, Pm_WriteShort, and
-   Pm_WriteSysEx all operate a state machine that "outputs" calls to
-   write_short, begin_sysex, write_byte, end_sysex, and write_realtime */
-
-PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length)
-{
-    PmInternal *midi = (PmInternal *) stream;
-    PmError err;
-    int i;
-    int bits;
-    
-    pm_hosterror = FALSE;
-    /* arg checking */
-    if(midi == NULL)
-        err = pmBadPtr;
-    else if(!descriptors[midi->device_id].pub.opened)
-        err = pmBadPtr;
-    else if(!descriptors[midi->device_id].pub.output)
-        err = pmBadPtr;
-    else
-        err = pmNoError;
-    
-    if (err != pmNoError) goto pm_write_error;
-    
-    if (midi->latency == 0) {
-        midi->now = 0;
-    } else {
-        midi->now = (*(midi->time_proc))(midi->time_info);
-        if (midi->first_message || midi->sync_time + 100 /*ms*/ < midi->now) {
-            /* time to resync */
-            midi->now = (*midi->dictionary->synchronize)(midi);
-            midi->first_message = FALSE;
-        }
-    }
-    /* error recovery: when a sysex is detected, we call
-     *   dictionary->begin_sysex() followed by calls to
-     *   dictionary->write_byte() and dictionary->write_realtime()
-     *   until an end-of-sysex is detected, when we call
-     *   dictionary->end_sysex(). After an error occurs, 
-     *   Pm_Write() continues to call functions. For example,
-     *   it will continue to call write_byte() even after
-     *   an error sending a sysex message, and end_sysex() will be
-     *   called when an EOX or non-real-time status is found.
-     * When errors are detected, Pm_Write() returns immediately, 
-     *   so it is possible that this will drop data and leave
-     *   sysex messages in a partially transmitted state.
-     */
-    for (i = 0; i < length; i++) {
-        unsigned long msg = buffer[i].message;
-        bits = 0;
-        /* is this a sysex message? */
-        if (Pm_MessageStatus(msg) == MIDI_SYSEX) {
-            if (midi->sysex_in_progress) {
-                /* error: previous sysex was not terminated by EOX */
-                midi->sysex_in_progress = FALSE;
-                err = pmBadData;
-                goto pm_write_error;
-            }
-            midi->sysex_in_progress = TRUE;
-            if ((err = (*midi->dictionary->begin_sysex)(midi, 
-                               buffer[i].timestamp)) != pmNoError)
-                goto pm_write_error;
-            if ((err = (*midi->dictionary->write_byte)(midi, MIDI_SYSEX,
-                               buffer[i].timestamp)) != pmNoError) 
-                goto pm_write_error;
-            bits = 8;
-            /* fall through to continue sysex processing */
-        } else if ((msg & MIDI_STATUS_MASK) && 
-                   (Pm_MessageStatus(msg) != MIDI_EOX)) {
-            /* a non-sysex message */
-            if (midi->sysex_in_progress) {
-                /* this should be a realtime message */
-                if (is_real_time(msg)) {
-                    if ((err = (*midi->dictionary->write_realtime)(midi, 
-                                       &(buffer[i]))) != pmNoError)
-                        goto pm_write_error;
-                } else {
-                    midi->sysex_in_progress = FALSE;
-                    err = pmBadData;
-                    /* ignore any error from this, because we already have one */
-                    /* pass 0 as timestamp -- it's ignored */
-                    (*midi->dictionary->end_sysex)(midi, 0);
-                    goto pm_write_error;
-                }
-            } else { /* regular short midi message */
-                if ((err = (*midi->dictionary->write_short)(midi, 
-                                   &(buffer[i]))) != pmNoError)
-                    goto pm_write_error;
-                continue;
-            }
-        }
-        if (midi->sysex_in_progress) { /* send sysex bytes until EOX */
-            /* see if we can accelerate data transfer */
-            if (bits == 0 && midi->fill_base && /* 4 bytes to copy */
-                (*midi->fill_offset_ptr) + 4 <= midi->fill_length &&
-                (msg & 0x80808080) == 0) { /* all data */
-                    /* copy 4 bytes from msg to fill_base + fill_offset */
-                    unsigned char *ptr = midi->fill_base + 
-                                         *(midi->fill_offset_ptr);
-                    ptr[0] = msg; ptr[1] = msg >> 8; 
-                    ptr[2] = msg >> 18; ptr[3] = msg >> 24;
-                    (*midi->fill_offset_ptr) += 4;
-                     continue;
-            }
-            /* no acceleration, so do byte-by-byte copying */
-            while (bits < 32) {
-                unsigned char midi_byte = (unsigned char) (msg >> bits);
-                if ((err = (*midi->dictionary->write_byte)(midi, midi_byte, 
-                                   buffer[i].timestamp)) != pmNoError)
-                    goto pm_write_error;
-                if (midi_byte == MIDI_EOX) {
-                    err = pm_end_sysex(midi);
-                    if (err != pmNoError) goto error_exit;
-                    break; /* from while loop */
-                }
-                bits += 8;
-            }
-        } else {
-            /* not in sysex mode, but message did not start with status */
-            err = pmBadData;
-            goto pm_write_error;
-        }
-    }
-    /* after all messages are processed, send the data */
-    if (!midi->sysex_in_progress)
-        err = (*midi->dictionary->write_flush)(midi, 0);
-pm_write_error:
-    if (err == pmHostError) {
-        midi->dictionary->host_error(midi, pm_hosterror_text, 
-                                     PM_HOST_ERROR_MSG_LEN);
-        pm_hosterror = TRUE;
-    }
-error_exit:
-    return pm_errmsg(err);
-}
-
-
-PmError Pm_WriteShort( PortMidiStream *stream, long when, long msg)
-{
-    PmEvent event;
-    
-    event.timestamp = when;
-    event.message = msg;
-    return Pm_Write(stream, &event, 1);
-}
-
-
-PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when, 
-                      unsigned char *msg)
-{
-    /* allocate buffer space for PM_DEFAULT_SYSEX_BUFFER_SIZE bytes */
-    /* each PmEvent holds sizeof(PmMessage) bytes of sysex data */
-#define BUFLEN (PM_DEFAULT_SYSEX_BUFFER_SIZE / sizeof(PmMessage))
-    PmEvent buffer[BUFLEN];
-    int buffer_size = 1; /* first time, send 1. After that, it's BUFLEN */
-    PmInternal *midi = (PmInternal *) stream;
-    /* the next byte in the buffer is represented by an index, bufx, and
-       a shift in bits */
-    int shift = 0;
-    int bufx = 0;
-    buffer[0].message = 0;
-    buffer[0].timestamp = when;
-
-    while (1) {
-        /* insert next byte into buffer */
-        buffer[bufx].message |= ((*msg) << shift);
-        shift += 8;
-        if (*msg++ == MIDI_EOX) break;
-        if (shift == 32) {
-            shift = 0;
-            bufx++;
-            if (bufx == buffer_size) {
-                PmError err = Pm_Write(stream, buffer, buffer_size);
-                /* note: Pm_Write has already called errmsg() */
-                if (err) return err;
-                /* prepare to fill another buffer */
-                bufx = 0;
-                buffer_size = BUFLEN;
-                /* optimization: maybe we can just copy bytes */
-                if (midi->fill_base) {
-                    PmError err;
-                    while (*(midi->fill_offset_ptr) < midi->fill_length) {
-                        midi->fill_base[(*midi->fill_offset_ptr)++] = *msg;
-                        if (*msg++ == MIDI_EOX) {
-                            err = pm_end_sysex(midi);
-                            if (err != pmNoError) return pm_errmsg(err);
-                            goto end_of_sysex;
-                        }
-                    }
-                    /* I thought that I could do a pm_Write here and
-                     * change this if to a loop, avoiding calls in Pm_Write
-                     * to the slower write_byte, but since 
-                     * sysex_in_progress is true, this will not flush
-                     * the buffer, and we'll infinite loop: */
-                    /* err = Pm_Write(stream, buffer, 0);
-                       if (err) return err; */
-                    /* instead, the way this works is that Pm_Write calls
-                     * write_byte on 4 bytes. The first, since the buffer
-                     * is full, will flush the buffer and allocate a new
-                     * one. This primes the buffer so
-                     * that we can return to the loop above and fill it
-                     * efficiently without a lot of function calls.
-                     */
-                    buffer_size = 1; /* get another message started */
-                }
-            }
-            buffer[bufx].message = 0;
-            buffer[bufx].timestamp = when;
-        } 
-        /* keep inserting bytes until you find MIDI_EOX */
-    }
-end_of_sysex:
-    /* we're finished sending full buffers, but there may
-     * be a partial one left.
-     */
-    if (shift != 0) bufx++; /* add partial message to buffer len */
-    if (bufx) { /* bufx is number of PmEvents to send from buffer */
-        PmError err = Pm_Write(stream, buffer, bufx);
-        if (err) return err;
-    }
-    return pmNoError;
-}
-
-
-
-PmError Pm_OpenInput(PortMidiStream** stream,
-                     PmDeviceID inputDevice,
-                     void *inputDriverInfo,
-                     long bufferSize,
-                     PmTimeProcPtr time_proc,
-                     void *time_info) {
-    PmInternal *midi;
-    PmError err = pmNoError;
-    pm_hosterror = FALSE;
-    *stream = NULL;
-    
-    /* arg checking */
-    if (inputDevice < 0 || inputDevice >= pm_descriptor_index) 
-        err = pmInvalidDeviceId;
-    else if (!descriptors[inputDevice].pub.input) 
-        err =  pmBadPtr;
-    else if(descriptors[inputDevice].pub.opened)
-        err =  pmBadPtr;
-    
-    if (err != pmNoError) 
-        goto error_return;
-
-    /* create portMidi internal data */
-    midi = (PmInternal *) pm_alloc(sizeof(PmInternal)); 
-    *stream = midi;
-    if (!midi) {
-        err = pmInsufficientMemory;
-        goto error_return;
-    }
-    midi->device_id = inputDevice;
-    midi->write_flag = FALSE;
-    midi->time_proc = time_proc;
-    midi->time_info = time_info;
-    /* windows adds timestamps in the driver and these are more accurate than
-       using a time_proc, so do not automatically provide a time proc. Non-win
-       implementations may want to provide a default time_proc in their
-       system-specific midi_out_open() method.
-     */
-    if (bufferSize <= 0) bufferSize = 256; /* default buffer size */
-#ifdef NEWBUFFER
-    midi->queue = Pm_QueueCreate(bufferSize, sizeof(PmEvent));
-    if (!midi->queue) {
-#else
-    else bufferSize++; /* buffer holds N-1 msgs, so increase request by 1 */
-    midi->buffer = (PmEvent *) pm_alloc(sizeof(PmEvent) * midi->buffer_len); 
-    midi->head = 0;
-    midi->tail = 0;
-    midi->overflow = FALSE;
-    if (!midi->buffer) { 
-#endif
-        /* free portMidi data */
-        *stream = NULL;
-        pm_free(midi); 
-        err = pmInsufficientMemory;
-        goto error_return;
-    }
-    midi->buffer_len = bufferSize; /* portMidi input storage */
-    midi->latency = 0; /* not used */
-    midi->sysex_in_progress = FALSE;
-    midi->sysex_message = 0; 
-    midi->sysex_message_count = 0; 
-    midi->filters = PM_FILT_ACTIVE;
-    midi->channel_mask = 0xFFFF;
-    midi->sync_time = 0;
-    midi->first_message = TRUE;
-    midi->dictionary = descriptors[inputDevice].dictionary;
-    midi->fill_base = NULL;
-    midi->fill_offset_ptr = NULL;
-    midi->fill_length = 0;
-    descriptors[inputDevice].internalDescriptor = midi;
-    /* open system dependent input device */
-    err = (*midi->dictionary->open)(midi, inputDriverInfo);
-    if (err) {
-        *stream = NULL;
-        descriptors[inputDevice].internalDescriptor = NULL;
-        /* free portMidi data */
-#ifdef NEWBUFFER
-        Pm_QueueDestroy(midi->queue);
-#else
-        pm_free(midi->buffer);  
-#endif
-        pm_free(midi);
-    } else {
-        /* portMidi input open successful */
-        descriptors[inputDevice].pub.opened = TRUE;
-    }
-error_return:
-    /* note: if there is a pmHostError, it is the responsibility
-     * of the system-dependent code (*midi->dictionary->open)()
-     * to set pm_hosterror and pm_hosterror_text
-     */
-    return pm_errmsg(err);
-}
-
-
-PmError Pm_OpenOutput(PortMidiStream** stream,
-                      PmDeviceID outputDevice,
-                      void *outputDriverInfo,
-                      long bufferSize,
-                      PmTimeProcPtr time_proc,
-                      void *time_info,
-                      long latency ) {
-    PmInternal *midi;
-    PmError err = pmNoError;
-    pm_hosterror = FALSE;
-    *stream =  NULL;
-    
-    /* arg checking */
-    if (outputDevice < 0 || outputDevice >= pm_descriptor_index)
-        err = pmInvalidDeviceId;
-    else if (!descriptors[outputDevice].pub.output) 
-        err = pmInvalidDeviceId;
-    else if (descriptors[outputDevice].pub.opened)
-        err = pmInvalidDeviceId;
-    if (err != pmNoError) 
-        goto error_return;
-
-    /* create portMidi internal data */
-    midi = (PmInternal *) pm_alloc(sizeof(PmInternal)); 
-    *stream = midi;                 
-    if (!midi) {
-        err = pmInsufficientMemory;
-        goto error_return;
-    }
-    midi->device_id = outputDevice;
-    midi->write_flag = TRUE;
-    midi->time_proc = time_proc;
-    /* if latency > 0, we need a time reference. If none is provided,
-       use PortTime library */
-    if (time_proc == NULL && latency != 0) {
-        if (!Pt_Started()) 
-            Pt_Start(1, 0, 0);
-        /* time_get does not take a parameter, so coerce */
-        midi->time_proc = (PmTimeProcPtr) Pt_Time;
-    }
-    midi->time_info = time_info;
-    midi->buffer_len = bufferSize;
-#ifdef NEWBUFFER
-    midi->queue = NULL; /* unused by output */
-#else
-    midi->buffer = NULL;
-    midi->head = 0; /* unused by output */
-    midi->tail = 0; /* unused by output */
-    midi->overflow = FALSE; /* not used */
-#endif
-    /* if latency zero, output immediate (timestamps ignored) */
-    /* if latency < 0, use 0 but don't return an error */
-    if (latency < 0) latency = 0;
-    midi->latency = latency;
-    midi->sysex_in_progress = FALSE;
-    midi->sysex_message = 0; /* unused by output */
-    midi->sysex_message_count = 0; /* unused by output */
-    midi->filters = 0; /* not used for output */
-    midi->channel_mask = 0xFFFF;
-    midi->sync_time = 0;
-    midi->first_message = TRUE;
-    midi->dictionary = descriptors[outputDevice].dictionary;
-    midi->fill_base = NULL;
-    midi->fill_offset_ptr = NULL;
-    midi->fill_length = 0;
-    descriptors[outputDevice].internalDescriptor = midi;
-    /* open system dependent output device */
-    err = (*midi->dictionary->open)(midi, outputDriverInfo);
-    if (err) {
-        *stream = NULL;
-        descriptors[outputDevice].internalDescriptor = NULL;
-        /* free portMidi data */
-        pm_free(midi); 
-    } else {
-        /* portMidi input open successful */
-        descriptors[outputDevice].pub.opened = TRUE;
-    }
-error_return:
-    /* note: system-dependent code must set pm_hosterror and
-     * pm_hosterror_text if a pmHostError occurs
-     */
-    return pm_errmsg(err);
-}
-
-
-PmError Pm_SetChannelMask(PortMidiStream *stream, int mask)
-{
-    PmInternal *midi = (PmInternal *) stream;
-    PmError err = pmNoError;
-
-    if (midi == NULL)
-        err = pmBadPtr;
-    else
-        midi->channel_mask = mask;
-
-    return pm_errmsg(err);
-}
-
-
-PmError Pm_SetFilter(PortMidiStream *stream, long filters) {
-    PmInternal *midi = (PmInternal *) stream;
-    PmError err = pmNoError;
-
-    /* arg checking */
-    if (midi == NULL)
-        err = pmBadPtr;
-    else if (!descriptors[midi->device_id].pub.opened)
-        err = pmBadPtr;
-    else
-        midi->filters = filters;
-    return pm_errmsg(err);
-}
-
-
-PmError Pm_Close( PortMidiStream *stream ) {
-    PmInternal *midi = (PmInternal *) stream;
-    PmError err = pmNoError;
-
-    pm_hosterror = FALSE;
-    /* arg checking */
-    if (midi == NULL) /* midi must point to something */
-        err = pmBadPtr;
-    /* if it is an open device, the device_id will be valid */
-    else if (midi->device_id < 0 || midi->device_id >= pm_descriptor_index)
-        err = pmBadPtr;
-    /* and the device should be in the opened state */
-    else if (!descriptors[midi->device_id].pub.opened)
-        err = pmBadPtr;
-    
-    if (err != pmNoError) 
-        goto error_return;
-
-    /* close the device */
-    err = (*midi->dictionary->close)(midi);
-    /* even if an error occurred, continue with cleanup */
-    descriptors[midi->device_id].internalDescriptor = NULL;
-    descriptors[midi->device_id].pub.opened = FALSE;
-#ifdef NEWBUFFER
-    if (midi->queue) Pm_QueueDestroy(midi->queue);
-#else
-    if (midi->buffer) pm_free(midi->buffer);       
-#endif
-    pm_free(midi); 
-error_return:
-    /* system dependent code must set pm_hosterror and
-     * pm_hosterror_text if a pmHostError occurs.
-     */
-    return pm_errmsg(err);
-}
-
-
-PmError Pm_Abort( PortMidiStream* stream ) {
-    PmInternal *midi = (PmInternal *) stream;
-    PmError err;
-    /* arg checking */
-    if (midi == NULL)
-        err = pmBadPtr;
-    if (!descriptors[midi->device_id].pub.output)
-        err = pmBadPtr;
-    if (!descriptors[midi->device_id].pub.opened)
-        err = pmBadPtr;
-    else
-        err = (*midi->dictionary->abort)(midi);
-
-    if (err == pmHostError) {
-        midi->dictionary->host_error(midi, pm_hosterror_text, 
-                                     PM_HOST_ERROR_MSG_LEN);
-        pm_hosterror = TRUE;
-    }
-    return pm_errmsg(err);
-}
-
-#ifndef NEWBUFFER
-/* this is apparently an orphan routine -- I can find no reference to it now -RBD */
-
-/* in win32 multimedia API (via callbacks) some of these functions used; assume never fail */
-long pm_next_time(PmInternal *midi) {
-
-    /* arg checking */
-    assert(midi != NULL);
-    
-    return midi->buffer[midi->head].timestamp;
-}
-#endif
-
-
-/* pm_channel_filtered returns non-zero if the channel mask is blocking the current channel */
-#define pm_channel_filtered(status, mask) \
-    ((((status) & 0xF0) != 0xF0) && (!(Pm_Channel((status) & 0x0F) & (mask))))
-
-
-/* The following two functions will checks to see if a MIDI message matches
-   the filtering criteria.  Since the sysex routines only want to filter realtime messages,
-   we need to have separate routines.
- */
-
-
-/* pm_realtime_filtered returns non-zero if the filter will kill the current message.
-   Note that only realtime messages are checked here.
- */
-#define pm_realtime_filtered(status, filters) \
-    ((((status) & 0xF0) == 0xF0) && ((1 << ((status) & 0xF)) & (filters)))
-
-/*
-    return ((status == MIDI_ACTIVE) && (filters & PM_FILT_ACTIVE))
-            ||  ((status == MIDI_CLOCK) && (filters & PM_FILT_CLOCK))
-            ||  ((status == MIDI_START) && (filters & PM_FILT_PLAY))
-            ||  ((status == MIDI_STOP) && (filters & PM_FILT_PLAY))
-            ||  ((status == MIDI_CONTINUE) && (filters & PM_FILT_PLAY))
-            ||  ((status == MIDI_F9) && (filters & PM_FILT_F9))
-            ||  ((status == MIDI_FD) && (filters & PM_FILT_FD))
-            ||  ((status == MIDI_RESET) && (filters & PM_FILT_RESET))
-            ||  ((status == MIDI_MTC) && (filters & PM_FILT_MTC))
-            ||  ((status == MIDI_SONGPOS) && (filters & PM_FILT_SONG_POSITION))
-            ||  ((status == MIDI_SONGSEL) && (filters & PM_FILT_SONG_SELECT))
-            ||  ((status == MIDI_TUNE) && (filters & PM_FILT_TUNE));
-}*/
-
-
-/* pm_status_filtered returns non-zero if a filter will kill the current message, based on status.
-   Note that sysex and real time are not checked.  It is up to the subsystem (winmm, core midi, alsa)
-   to filter sysex, as it is handled more easily and efficiently at that level.
-   Realtime message are filtered in pm_realtime_filtered.
- */
-#define pm_status_filtered(status, filters) ((1 << (16 + ((status) >> 4))) & (filters))
-
-
-/*
-    return  ((status == MIDI_NOTE_ON) && (filters & PM_FILT_NOTE))
-            ||  ((status == MIDI_NOTE_OFF) && (filters & PM_FILT_NOTE))
-            ||  ((status == MIDI_CHANNEL_AT) && (filters & PM_FILT_CHANNEL_AFTERTOUCH))
-            ||  ((status == MIDI_POLY_AT) && (filters & PM_FILT_POLY_AFTERTOUCH))
-            ||  ((status == MIDI_PROGRAM) && (filters & PM_FILT_PROGRAM))
-            ||  ((status == MIDI_CONTROL) && (filters & PM_FILT_CONTROL))
-            ||  ((status == MIDI_PITCHBEND) && (filters & PM_FILT_PITCHBEND));
-
-}
-*/
-
-void pm_flush_sysex(PmInternal *midi, PmTimestamp timestamp)
-{
-    PmEvent event;
-    
-    /* there may be nothing in the buffer */
-    if (midi->sysex_message_count == 0) return; /* nothing to flush */
-    
-    event.message = midi->sysex_message;
-    event.timestamp = timestamp;
-    /* copied from pm_read_short, avoids filtering */
-    if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
-        midi->sysex_in_progress = FALSE;
-    }
-    midi->sysex_message_count = 0;
-    midi->sysex_message = 0;
-}
-
-
-/* pm_read_short and pm_read_bytes
-   are the interface between system-dependent MIDI input handlers
-   and the system-independent PortMIDI code.
-   The input handler MUST obey these rules:
-   1) all short input messages must be sent to pm_read_short, which
-      enqueues them to a FIFO for the application.
-   2) eash buffer of sysex bytes should be reported by calling pm_read_bytes
-      (which sets midi->sysex_in_progress). After the eox byte, 
-      pm_read_bytes will clear sysex_in_progress
- */
-
-/* pm_read_short is the place where all input messages arrive from 
-   system-dependent code such as pmwinmm.c. Here, the messages
-   are entered into the PortMidi input buffer. 
- */
-void pm_read_short(PmInternal *midi, PmEvent *event)
-{ 
-#ifndef NEWBUFFER
-    long tail;
-#endif
-    int status;
-    /* arg checking */
-    assert(midi != NULL);
-    /* midi filtering is applied here */
-    status = Pm_MessageStatus(event->message);
-    if (!pm_status_filtered(status, midi->filters)
-        && (!is_real_time(status) || 
-            !pm_realtime_filtered(status, midi->filters))
-        && !pm_channel_filtered(status, midi->channel_mask)) {
-        /* if sysex is in progress and we get a status byte, it had
-           better be a realtime message or the starting SYSEX byte;
-           otherwise, we exit the sysex_in_progress state
-         */
-        if (midi->sysex_in_progress && (status & MIDI_STATUS_MASK)) {
-            /* two choices: real-time or not. If it's real-time, then
-             * this should be delivered as a sysex byte because it is
-             * embedded in a sysex message
-             */
-            if (is_real_time(status)) {
-                midi->sysex_message |= 
-                        (status << (8 * midi->sysex_message_count++));
-                if (midi->sysex_message_count == 4) {
-                    pm_flush_sysex(midi, event->timestamp);
-                }
-            } else { /* otherwise, it's not real-time. This interrupts
-                      * a sysex message in progress */
-                midi->sysex_in_progress = FALSE;
-            }
-#ifdef NEWBUFFER
-        } else if (Pm_Enqueue(midi->queue, event) == pmBufferOverflow) {
-            midi->sysex_in_progress = FALSE;
-        }
-#else
-        } else {
-            /* don't try to do anything more in an overflow state */
-            if (midi->overflow) return;
-
-            /* insert the message */
-            tail = midi->tail;
-            midi->buffer[tail++] = *event;
-            if (tail == midi->buffer_len) tail = 0;
-            if (tail == midi->head || midi->overflow) {
-                midi->overflow = TRUE;
-                midi->sysex_in_progress = FALSE; 
-                /* drop the rest of the message, this must be cleared 
-                   by caller when EOX is received */
-                   return;
-            }
-            midi->tail = tail; /* complete the write */
-        }
-#endif
-    }
-}
-
-/* pm_read_bytes -- read one (partial) sysex msg from MIDI data */
-/*
- * returns how many bytes processed
- */
-unsigned int pm_read_bytes(PmInternal *midi, unsigned char *data, 
-                    int len, PmTimestamp timestamp)
-{
-    unsigned int i = 0; /* index into data */
-    PmEvent event;
-    event.timestamp = timestamp;
-    assert(midi);
-    /* note that since buffers may not have multiples of 4 bytes,
-     * pm_read_bytes may be called in the middle of an outgoing
-     * 4-byte PortMidi message. sysex_in_progress indicates that
-     * a sysex has been sent but no eox.
-     */
-    if (len == 0) return 0; /* sanity check */
-    if (!midi->sysex_in_progress) {
-        while (i < len) { /* process all data */
-            unsigned char byte = data[i++];
-            if (byte == MIDI_SYSEX &&
-                !pm_realtime_filtered(byte, midi->filters)) {
-                midi->sysex_in_progress = TRUE;
-                i--; /* back up so code below will get SYSEX byte */
-                break; /* continue looping below to process msg */
-            } else if (byte == MIDI_EOX) {
-                midi->sysex_in_progress = FALSE;
-                return i; /* done with one message */
-            } else if (byte & MIDI_STATUS_MASK) {
-                /* We're getting MIDI but no sysex in progress.
-                 * Either the SYSEX status byte was dropped or
-                 * the message was filtered. Drop the data, but
-                 * send any embedded realtime bytes.
-                 */
-                /* assume that this is a real-time message:
-                 * it is an error to pass non-real-time messages
-                 * to pm_read_bytes
-                 */
-                event.message = byte;
-                pm_read_short(midi, &event);
-            }
-        } /* all bytes in the buffer are processed */
-    }
-    /* Now, i<len implies sysex_in_progress. If sysex_in_progress
-     * becomes false in the loop, there must have been an overflow
-     * and we can just drop all remaining bytes 
-     */
-    while (i < len && midi->sysex_in_progress) {
-        if (midi->sysex_message_count == 0 && i <= len - 4 &&
-            ((event.message = (((long) data[i]) | 
-                             (((long) data[i+1]) << 8) |
-                             (((long) data[i+2]) << 16) |
-                             (((long) data[i+3]) << 24))) &
-             0x80808080) == 0) { /* all data, no status */ 
-            if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
-                midi->sysex_in_progress = FALSE;
-            }
-            i += 4;
-        } else {
-            while (i < len) {
-                /* send one byte at a time */
-                unsigned char byte = data[i++];
-                if (is_real_time(byte) && 
-                    pm_realtime_filtered(byte, midi->filters)) {
-                    continue; /* real-time data is filtered, so omit */
-                }
-                midi->sysex_message |= 
-                    (byte << (8 * midi->sysex_message_count++));
-                if (byte == MIDI_EOX) {
-                    midi->sysex_in_progress = FALSE;
-                    pm_flush_sysex(midi, event.timestamp);
-                    return i;
-                } else if (midi->sysex_message_count == 4) {
-                    pm_flush_sysex(midi, event.timestamp);
-                    /* after handling at least one non-data byte
-                     * and reaching a 4-byte message boundary,
-                     * resume trying to send 4 at a time in outer loop
-                     */
-                    break;
-                }
-            }
-        }
-    }
-    return i;
-}
-
-
-#ifndef NEWBUFFER
-/* this code is apparently never called */
-int pm_queue_full(PmInternal *midi)
-{
-    long tail;
-
-    /* arg checking */
-    assert(midi != NULL);
-    
-    tail = midi->tail + 1;
-    if (tail == midi->buffer_len) tail = 0;
-    return tail == midi->head;
-}
-#endif
+#ifdef _MSC_VER
+ #pragma warning(disable: 4244) // stop warnings about downsize typecasts
+ #pragma warning(disable: 4018) // stop warnings about signed/unsigned
+#endif
+
+#include "stdlib.h"
+#include "string.h"
+#include "portmidi.h"
+#include "porttime.h"
+#include "pmutil.h"
+#include "pminternal.h"
+#include <assert.h>
+
+#define MIDI_CLOCK      0xf8
+#define MIDI_ACTIVE     0xfe
+#define MIDI_STATUS_MASK 0x80
+#define MIDI_SYSEX      0xf0
+#define MIDI_EOX        0xf7
+#define MIDI_START      0xFA
+#define MIDI_STOP       0xFC
+#define MIDI_CONTINUE   0xFB
+#define MIDI_F9         0xF9
+#define MIDI_FD         0xFD
+#define MIDI_RESET      0xFF
+#define MIDI_NOTE_ON    0x90
+#define MIDI_NOTE_OFF   0x80
+#define MIDI_CHANNEL_AT 0xD0
+#define MIDI_POLY_AT    0xA0
+#define MIDI_PROGRAM    0xC0
+#define MIDI_CONTROL    0xB0
+#define MIDI_PITCHBEND  0xE0
+#define MIDI_MTC        0xF1
+#define MIDI_SONGPOS    0xF2
+#define MIDI_SONGSEL    0xF3
+#define MIDI_TUNE       0xF6
+
+#define is_empty(midi) ((midi)->tail == (midi)->head)
+
+/* this is not static so that pm_init can set it directly if
+ *   (see pmmac.c:pm_init())
+ */
+int pm_initialized = FALSE;
+
+int pm_hosterror;
+char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];
+
+#ifdef PM_CHECK_ERRORS
+
+#include <stdio.h>
+
+#define STRING_MAX 80
+
+static void prompt_and_exit(void)
+{
+    char line[STRING_MAX];
+    printf("type ENTER...");
+    fgets(line, STRING_MAX, stdin);
+    /* this will clean up open ports: */
+    exit(-1);
+}
+
+
+static PmError pm_errmsg(PmError err)
+{
+    if (err == pmHostError) {
+        /* it seems pointless to allocate memory and copy the string,
+         * so I will do the work of Pm_GetHostErrorText directly
+         */
+        printf("PortMidi found host error...\n  %s\n", pm_hosterror_text);
+        pm_hosterror = FALSE;
+        pm_hosterror_text[0] = 0; /* clear the message */
+        prompt_and_exit();
+    } else if (err < 0) {
+        printf("PortMidi call failed...\n  %s\n", Pm_GetErrorText(err));
+        prompt_and_exit();
+    }
+    return err;
+}
+#else
+#define pm_errmsg(err) err
+#endif
+
+/*
+====================================================================
+system implementation of portmidi interface
+====================================================================
+*/
+
+int pm_descriptor_max = 0;
+int pm_descriptor_index = 0;
+descriptor_type descriptors = NULL;
+
+/* pm_add_device -- describe interface/device pair to library 
+ *
+ * This is called at intialization time, once for each 
+ * interface (e.g. DirectSound) and device (e.g. SoundBlaster 1)
+ * The strings are retained but NOT COPIED, so do not destroy them!
+ *
+ * returns pmInvalidDeviceId if device memory is exceeded
+ * otherwise returns pmNoError
+ */
+PmError pm_add_device(char *interf, char *name, int input, 
+                      void *descriptor, pm_fns_type dictionary) {
+    if (pm_descriptor_index >= pm_descriptor_max) {
+        // expand descriptors
+        descriptor_type new_descriptors = (descriptor_type) 
+            pm_alloc(sizeof(descriptor_node) * (pm_descriptor_max + 32));
+        if (!new_descriptors) return pmInsufficientMemory;
+        if (descriptors) {
+            memcpy(new_descriptors, descriptors, 
+                   sizeof(descriptor_node) * pm_descriptor_max);
+            free(descriptors);
+        }
+        pm_descriptor_max += 32;
+        descriptors = new_descriptors;
+    }
+    descriptors[pm_descriptor_index].pub.interf = interf;
+    descriptors[pm_descriptor_index].pub.name = name;
+    descriptors[pm_descriptor_index].pub.input = input;
+    descriptors[pm_descriptor_index].pub.output = !input;
+
+    /* default state: nothing to close (for automatic device closing) */
+    descriptors[pm_descriptor_index].pub.opened = FALSE;
+
+    /* ID number passed to win32 multimedia API open */
+    descriptors[pm_descriptor_index].descriptor = descriptor;
+    
+    /* points to PmInternal, allows automatic device closing */
+    descriptors[pm_descriptor_index].internalDescriptor = NULL;
+
+    descriptors[pm_descriptor_index].dictionary = dictionary;
+    
+    pm_descriptor_index++;
+    
+    return pmNoError;
+}
+
+
+/* utility to look up device, given a pattern, 
+   note: pattern is modified
+ */
+int pm_find_default_device(char *pattern, int is_input)
+{
+    int id = pmNoDevice;
+    int i;
+    /* first parse pattern into name, interf parts */
+    char *interf_pref = ""; /* initially assume it is not there */
+    char *name_pref = strstr(pattern, ", ");
+
+    if (name_pref) { /* found separator, adjust the pointer */
+        interf_pref = pattern;
+        name_pref[0] = 0;
+        name_pref += 2;
+    } else {
+        name_pref = pattern; /* whole string is the name pattern */
+    }
+    for (i = 0; i < pm_descriptor_index; i++) {
+        const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+        if (info->input == is_input &&
+            strstr(info->name, name_pref) &&
+            strstr(info->interf, interf_pref)) {
+            id = i;
+            break;
+        }
+    }    
+    return id;
+}
+
+
+/*
+====================================================================
+portmidi implementation
+====================================================================
+*/
+
+PMEXPORT int Pm_CountDevices( void ) {
+    Pm_Initialize();
+    /* no error checking -- Pm_Initialize() does not fail */
+    return pm_descriptor_index;
+}
+
+
+PMEXPORT const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id ) {
+    Pm_Initialize(); /* no error check needed */
+    if (id >= 0 && id < pm_descriptor_index) {
+        return &descriptors[id].pub;
+    }
+    return NULL;
+}
+
+/* pm_success_fn -- "noop" function pointer */
+PmError pm_success_fn(PmInternal *midi) {
+    return pmNoError;
+}
+
+/* none_write -- returns an error if called */
+PmError none_write_short(PmInternal *midi, PmEvent *buffer) {
+    return pmBadPtr;
+}
+
+/* pm_fail_timestamp_fn -- placeholder for begin_sysex and flush */
+PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp) {
+    return pmBadPtr;
+}
+
+PmError none_write_byte(PmInternal *midi, unsigned char byte, 
+                        PmTimestamp timestamp) {
+    return pmBadPtr;
+}
+
+/* pm_fail_fn -- generic function, returns error if called */
+PmError pm_fail_fn(PmInternal *midi) {
+    return pmBadPtr;
+}
+
+static PmError none_open(PmInternal *midi, void *driverInfo) {
+    return pmBadPtr;
+}
+static void none_get_host_error(PmInternal * midi, char * msg, unsigned int len) {
+    *msg = 0; // empty string
+}
+static unsigned int none_has_host_error(PmInternal * midi) {
+    return FALSE;
+}
+PmTimestamp none_synchronize(PmInternal *midi) {
+    return 0;
+}
+
+#define none_abort pm_fail_fn
+#define none_close pm_fail_fn
+
+pm_fns_node pm_none_dictionary = {
+    none_write_short,
+    none_sysex,
+    none_sysex,
+    none_write_byte,
+    none_write_short,
+    none_write_flush,
+    none_synchronize,
+    none_open,
+    none_abort, 
+    none_close,
+    none_poll,
+    none_has_host_error,
+    none_get_host_error 
+};
+
+
+PMEXPORT const char *Pm_GetErrorText( PmError errnum ) {
+    const char *msg;
+
+    switch(errnum)
+    {
+    case pmNoError:                  
+        msg = ""; 
+        break;
+    case pmHostError:                
+        msg = "PortMidi: `Host error'"; 
+        break;
+    case pmInvalidDeviceId:          
+        msg = "PortMidi: `Invalid device ID'"; 
+        break;
+    case pmInsufficientMemory:       
+        msg = "PortMidi: `Insufficient memory'"; 
+        break;
+    case pmBufferTooSmall:           
+        msg = "PortMidi: `Buffer too small'"; 
+        break;
+    case pmBadPtr:                   
+        msg = "PortMidi: `Bad pointer'"; 
+        break;
+    case pmInternalError:            
+        msg = "PortMidi: `Internal PortMidi Error'"; 
+        break;
+    case pmBufferOverflow:
+        msg = "PortMidi: `Buffer overflow'";
+        break;
+    case pmBadData:
+        msg = "PortMidi: `Invalid MIDI message Data'";
+        break;
+    case pmBufferMaxSize:
+        msg = "PortMidi: `Buffer cannot be made larger'";
+        break;
+    default:                         
+        msg = "PortMidi: `Illegal error number'"; 
+        break;
+    }
+    return msg;
+}
+
+
+/* This can be called whenever you get a pmHostError return value.
+ * The error will always be in the global pm_hosterror_text.
+ */
+PMEXPORT void Pm_GetHostErrorText(char * msg, unsigned int len) {
+    assert(msg);
+    assert(len > 0);
+    if (pm_hosterror) {
+        strncpy(msg, (char *) pm_hosterror_text, len);
+        pm_hosterror = FALSE;
+        pm_hosterror_text[0] = 0; /* clear the message; not necessary, but it
+                                     might help with debugging */
+        msg[len - 1] = 0; /* make sure string is terminated */
+    } else {
+        msg[0] = 0; /* no string to return */
+    }
+}
+
+
+PMEXPORT int Pm_HasHostError(PortMidiStream * stream) {
+    if (pm_hosterror) return TRUE;
+    if (stream) {
+        PmInternal * midi = (PmInternal *) stream;
+        pm_hosterror = (*midi->dictionary->has_host_error)(midi);
+        if (pm_hosterror) {
+            midi->dictionary->host_error(midi, pm_hosterror_text, 
+                                         PM_HOST_ERROR_MSG_LEN);
+            /* now error message is global */
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+
+PMEXPORT PmError Pm_Initialize( void ) {
+    if (!pm_initialized) {
+        pm_hosterror = FALSE;
+        pm_hosterror_text[0] = 0; /* the null string */
+        pm_init();
+        pm_initialized = TRUE;
+    }
+    return pmNoError;
+}
+
+
+PMEXPORT PmError Pm_Terminate( void ) {
+    if (pm_initialized) {
+        pm_term();
+        // if there are no devices, descriptors might still be NULL
+        if (descriptors != NULL) {
+            free(descriptors);
+            descriptors = NULL;
+        }
+        pm_descriptor_index = 0;
+        pm_descriptor_max = 0;
+        pm_initialized = FALSE;
+    }
+    return pmNoError;
+}
+
+
+/* Pm_Read -- read up to length messages from source into buffer */
+/*
+ * returns number of messages actually read, or error code
+ */
+PMEXPORT int Pm_Read(PortMidiStream *stream, PmEvent *buffer, int32_t length) {
+    PmInternal *midi = (PmInternal *) stream;
+    int n = 0;
+    PmError err = pmNoError;
+    pm_hosterror = FALSE;
+    /* arg checking */
+    if(midi == NULL)
+        err = pmBadPtr;
+    else if(!descriptors[midi->device_id].pub.opened)
+        err = pmBadPtr;
+    else if(!descriptors[midi->device_id].pub.input)
+        err = pmBadPtr;    
+    /* First poll for data in the buffer...
+     * This either simply checks for data, or attempts first to fill the buffer
+     * with data from the MIDI hardware; this depends on the implementation.
+     * We could call Pm_Poll here, but that would redo a lot of redundant
+     * parameter checking, so I copied some code from Pm_Poll to here: */
+    else err = (*(midi->dictionary->poll))(midi);
+
+    if (err != pmNoError) {
+        if (err == pmHostError) {
+            midi->dictionary->host_error(midi, pm_hosterror_text, 
+                                         PM_HOST_ERROR_MSG_LEN);
+          pm_hosterror = TRUE;
+        }
+        return pm_errmsg(err);
+    }
+
+    while (n < length) {
+        PmError err = Pm_Dequeue(midi->queue, buffer++);
+        if (err == pmBufferOverflow) {
+            /* ignore the data we have retreived so far */
+            return pm_errmsg(pmBufferOverflow);
+        } else if (err == 0) { /* empty queue */
+            break;
+        }
+        n++;
+    }
+    return n;
+}
+
+PMEXPORT PmError Pm_Poll( PortMidiStream *stream )
+{
+    PmInternal *midi = (PmInternal *) stream;
+    PmError err;
+
+    pm_hosterror = FALSE;
+    /* arg checking */
+    if(midi == NULL)
+        err = pmBadPtr;
+    else if (!descriptors[midi->device_id].pub.opened)
+        err = pmBadPtr;
+    else if (!descriptors[midi->device_id].pub.input)
+        err = pmBadPtr;
+    else
+        err = (*(midi->dictionary->poll))(midi);
+
+    if (err != pmNoError) {
+        if (err == pmHostError) {
+            midi->dictionary->host_error(midi, pm_hosterror_text, 
+                                         PM_HOST_ERROR_MSG_LEN);
+           pm_hosterror = TRUE;
+        }
+        return pm_errmsg(err);
+    }
+
+    return !Pm_QueueEmpty(midi->queue);
+}
+
+
+/* this is called from Pm_Write and Pm_WriteSysEx to issue a
+ * call to the system-dependent end_sysex function and handle 
+ * the error return
+ */
+static PmError pm_end_sysex(PmInternal *midi)
+{
+    PmError err = (*midi->dictionary->end_sysex)(midi, 0);
+    midi->sysex_in_progress = FALSE;
+    if (err == pmHostError) {
+        midi->dictionary->host_error(midi, pm_hosterror_text, 
+                                     PM_HOST_ERROR_MSG_LEN);
+        pm_hosterror = TRUE;
+    }
+    return err;
+}
+
+
+/* to facilitate correct error-handling, Pm_Write, Pm_WriteShort, and
+   Pm_WriteSysEx all operate a state machine that "outputs" calls to
+   write_short, begin_sysex, write_byte, end_sysex, and write_realtime */
+
+PMEXPORT PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, int32_t length)
+{
+    PmInternal *midi = (PmInternal *) stream;
+    PmError err = pmNoError;
+    int i;
+    int bits;
+    
+    pm_hosterror = FALSE;
+    /* arg checking */
+    if(midi == NULL)
+        err = pmBadPtr;
+    else if(!descriptors[midi->device_id].pub.opened)
+        err = pmBadPtr;
+    else if(!descriptors[midi->device_id].pub.output)
+        err = pmBadPtr;
+    else
+        err = pmNoError;
+    
+    if (err != pmNoError) goto pm_write_error;
+    
+    if (midi->latency == 0) {
+        midi->now = 0;
+    } else {
+        midi->now = (*(midi->time_proc))(midi->time_info);
+        if (midi->first_message || midi->sync_time + 100 /*ms*/ < midi->now) {
+            /* time to resync */
+            midi->now = (*midi->dictionary->synchronize)(midi);
+            midi->first_message = FALSE;
+        }
+    }
+    /* error recovery: when a sysex is detected, we call
+     *   dictionary->begin_sysex() followed by calls to
+     *   dictionary->write_byte() and dictionary->write_realtime()
+     *   until an end-of-sysex is detected, when we call
+     *   dictionary->end_sysex(). After an error occurs, 
+     *   Pm_Write() continues to call functions. For example,
+     *   it will continue to call write_byte() even after
+     *   an error sending a sysex message, and end_sysex() will be
+     *   called when an EOX or non-real-time status is found.
+     * When errors are detected, Pm_Write() returns immediately, 
+     *   so it is possible that this will drop data and leave
+     *   sysex messages in a partially transmitted state.
+     */
+    for (i = 0; i < length; i++) {
+        uint32_t msg = buffer[i].message;
+        bits = 0;
+        /* is this a sysex message? */
+        if (Pm_MessageStatus(msg) == MIDI_SYSEX) {
+            if (midi->sysex_in_progress) {
+                /* error: previous sysex was not terminated by EOX */
+                midi->sysex_in_progress = FALSE;
+                err = pmBadData;
+                goto pm_write_error;
+            }
+            midi->sysex_in_progress = TRUE;
+            if ((err = (*midi->dictionary->begin_sysex)(midi, 
+                               buffer[i].timestamp)) != pmNoError)
+                goto pm_write_error;
+            if ((err = (*midi->dictionary->write_byte)(midi, MIDI_SYSEX,
+                               buffer[i].timestamp)) != pmNoError) 
+                goto pm_write_error;
+            bits = 8;
+            /* fall through to continue sysex processing */
+        } else if ((msg & MIDI_STATUS_MASK) && 
+                   (Pm_MessageStatus(msg) != MIDI_EOX)) {
+            /* a non-sysex message */
+            if (midi->sysex_in_progress) {
+                /* this should be a realtime message */
+                if (is_real_time(msg)) {
+                    if ((err = (*midi->dictionary->write_realtime)(midi, 
+                                       &(buffer[i]))) != pmNoError)
+                        goto pm_write_error;
+                } else {
+                    midi->sysex_in_progress = FALSE;
+                    err = pmBadData;
+                    /* ignore any error from this, because we already have one */
+                    /* pass 0 as timestamp -- it's ignored */
+                    (*midi->dictionary->end_sysex)(midi, 0);
+                    goto pm_write_error;
+                }
+            } else { /* regular short midi message */
+                if ((err = (*midi->dictionary->write_short)(midi, 
+                                   &(buffer[i]))) != pmNoError)
+                    goto pm_write_error;
+                continue;
+            }
+        }
+        if (midi->sysex_in_progress) { /* send sysex bytes until EOX */
+            /* see if we can accelerate data transfer */
+            if (bits == 0 && midi->fill_base && /* 4 bytes to copy */
+                (*midi->fill_offset_ptr) + 4 <= midi->fill_length &&
+                (msg & 0x80808080) == 0) { /* all data */
+                    /* copy 4 bytes from msg to fill_base + fill_offset */
+                    unsigned char *ptr = midi->fill_base + 
+                                         *(midi->fill_offset_ptr);
+                    ptr[0] = msg; ptr[1] = msg >> 8; 
+                    ptr[2] = msg >> 16; ptr[3] = msg >> 24;
+                    (*midi->fill_offset_ptr) += 4;
+                     continue;
+            }
+            /* no acceleration, so do byte-by-byte copying */
+            while (bits < 32) {
+                unsigned char midi_byte = (unsigned char) (msg >> bits);
+                if ((err = (*midi->dictionary->write_byte)(midi, midi_byte, 
+                                   buffer[i].timestamp)) != pmNoError)
+                    goto pm_write_error;
+                if (midi_byte == MIDI_EOX) {
+                    err = pm_end_sysex(midi);
+                    if (err != pmNoError) goto error_exit;
+                    break; /* from while loop */
+                }
+                bits += 8;
+            }
+        } else {
+            /* not in sysex mode, but message did not start with status */
+            err = pmBadData;
+            goto pm_write_error;
+        }
+    }
+    /* after all messages are processed, send the data */
+    if (!midi->sysex_in_progress)
+        err = (*midi->dictionary->write_flush)(midi, 0);
+pm_write_error:
+    if (err == pmHostError) {
+        midi->dictionary->host_error(midi, pm_hosterror_text, 
+                                     PM_HOST_ERROR_MSG_LEN);
+        pm_hosterror = TRUE;
+    }
+error_exit:
+    return pm_errmsg(err);
+}
+
+
+PMEXPORT PmError Pm_WriteShort(PortMidiStream *stream, PmTimestamp when, PmMessage msg)
+{
+    PmEvent event;
+    
+    event.timestamp = when;
+    event.message = msg;
+    return Pm_Write(stream, &event, 1);
+}
+
+
+PMEXPORT PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when, 
+                      unsigned char *msg)
+{
+    /* allocate buffer space for PM_DEFAULT_SYSEX_BUFFER_SIZE bytes */
+    /* each PmEvent holds sizeof(PmMessage) bytes of sysex data */
+    #define BUFLEN ((int) (PM_DEFAULT_SYSEX_BUFFER_SIZE / sizeof(PmMessage)))
+    PmEvent buffer[BUFLEN];
+    int buffer_size = 1; /* first time, send 1. After that, it's BUFLEN */
+    PmInternal *midi = (PmInternal *) stream;
+    /* the next byte in the buffer is represented by an index, bufx, and
+       a shift in bits */
+    int shift = 0;
+    int bufx = 0;
+    buffer[0].message = 0;
+    buffer[0].timestamp = when;
+
+    while (1) {
+        /* insert next byte into buffer */
+        buffer[bufx].message |= ((*msg) << shift);
+        shift += 8;
+        if (*msg++ == MIDI_EOX) break;
+        if (shift == 32) {
+            shift = 0;
+            bufx++;
+            if (bufx == buffer_size) {
+                PmError err = Pm_Write(stream, buffer, buffer_size);
+                /* note: Pm_Write has already called errmsg() */
+                if (err) return err;
+                /* prepare to fill another buffer */
+                bufx = 0;
+                buffer_size = BUFLEN;
+                /* optimization: maybe we can just copy bytes */
+                if (midi->fill_base) {
+                    PmError err;
+                    while (*(midi->fill_offset_ptr) < midi->fill_length) {
+                        midi->fill_base[(*midi->fill_offset_ptr)++] = *msg;
+                        if (*msg++ == MIDI_EOX) {
+                            err = pm_end_sysex(midi);
+                            if (err != pmNoError) return pm_errmsg(err);
+                            goto end_of_sysex;
+                        }
+                    }
+                    /* I thought that I could do a pm_Write here and
+                     * change this if to a loop, avoiding calls in Pm_Write
+                     * to the slower write_byte, but since 
+                     * sysex_in_progress is true, this will not flush
+                     * the buffer, and we'll infinite loop: */
+                    /* err = Pm_Write(stream, buffer, 0);
+                       if (err) return err; */
+                    /* instead, the way this works is that Pm_Write calls
+                     * write_byte on 4 bytes. The first, since the buffer
+                     * is full, will flush the buffer and allocate a new
+                     * one. This primes the buffer so
+                     * that we can return to the loop above and fill it
+                     * efficiently without a lot of function calls.
+                     */
+                    buffer_size = 1; /* get another message started */
+                }
+            }
+            buffer[bufx].message = 0;
+            buffer[bufx].timestamp = when;
+        } 
+        /* keep inserting bytes until you find MIDI_EOX */
+    }
+end_of_sysex:
+    /* we're finished sending full buffers, but there may
+     * be a partial one left.
+     */
+    if (shift != 0) bufx++; /* add partial message to buffer len */
+    if (bufx) { /* bufx is number of PmEvents to send from buffer */
+        PmError err = Pm_Write(stream, buffer, bufx);
+        if (err) return err;
+    }
+    return pmNoError;
+}
+
+
+
+PMEXPORT PmError Pm_OpenInput(PortMidiStream** stream,
+                     PmDeviceID inputDevice,
+                     void *inputDriverInfo,
+                     int32_t bufferSize,
+                     PmTimeProcPtr time_proc,
+                     void *time_info)
+{
+    PmInternal *midi;
+    PmError err = pmNoError;
+    pm_hosterror = FALSE;
+    *stream = NULL;
+    
+    /* arg checking */
+    if (inputDevice < 0 || inputDevice >= pm_descriptor_index) 
+        err = pmInvalidDeviceId;
+    else if (!descriptors[inputDevice].pub.input) 
+        err =  pmInvalidDeviceId;
+    else if(descriptors[inputDevice].pub.opened)
+        err =  pmInvalidDeviceId;
+    
+    if (err != pmNoError) 
+        goto error_return;
+
+    /* create portMidi internal data */
+    midi = (PmInternal *) pm_alloc(sizeof(PmInternal)); 
+    *stream = midi;
+    if (!midi) {
+        err = pmInsufficientMemory;
+        goto error_return;
+    }
+    midi->device_id = inputDevice;
+    midi->write_flag = FALSE;
+    midi->time_proc = time_proc;
+    midi->time_info = time_info;
+    /* windows adds timestamps in the driver and these are more accurate than
+       using a time_proc, so do not automatically provide a time proc. Non-win
+       implementations may want to provide a default time_proc in their
+       system-specific midi_out_open() method.
+     */
+    if (bufferSize <= 0) bufferSize = 256; /* default buffer size */
+    midi->queue = Pm_QueueCreate(bufferSize, (int32_t) sizeof(PmEvent));
+    if (!midi->queue) {
+        /* free portMidi data */
+        *stream = NULL;
+        pm_free(midi); 
+        err = pmInsufficientMemory;
+        goto error_return;
+    }
+    midi->buffer_len = bufferSize; /* portMidi input storage */
+    midi->latency = 0; /* not used */
+    midi->sysex_in_progress = FALSE;
+    midi->sysex_message = 0; 
+    midi->sysex_message_count = 0; 
+    midi->filters = PM_FILT_ACTIVE;
+    midi->channel_mask = 0xFFFF;
+    midi->sync_time = 0;
+    midi->first_message = TRUE;
+    midi->dictionary = descriptors[inputDevice].dictionary;
+    midi->fill_base = NULL;
+    midi->fill_offset_ptr = NULL;
+    midi->fill_length = 0;
+    descriptors[inputDevice].internalDescriptor = midi;
+    /* open system dependent input device */
+    err = (*midi->dictionary->open)(midi, inputDriverInfo);
+    if (err) {
+        *stream = NULL;
+        descriptors[inputDevice].internalDescriptor = NULL;
+        /* free portMidi data */
+        Pm_QueueDestroy(midi->queue);
+        pm_free(midi);
+    } else {
+        /* portMidi input open successful */
+        descriptors[inputDevice].pub.opened = TRUE;
+    }
+error_return:
+    /* note: if there is a pmHostError, it is the responsibility
+     * of the system-dependent code (*midi->dictionary->open)()
+     * to set pm_hosterror and pm_hosterror_text
+     */
+    return pm_errmsg(err);
+}
+
+
+PMEXPORT PmError Pm_OpenOutput(PortMidiStream** stream,
+                      PmDeviceID outputDevice,
+                      void *outputDriverInfo,
+                      int32_t bufferSize,
+                      PmTimeProcPtr time_proc,
+                      void *time_info,
+                      int32_t latency ) 
+{
+    PmInternal *midi;
+    PmError err = pmNoError;
+    pm_hosterror = FALSE;
+    *stream =  NULL;
+    
+    /* arg checking */
+    if (outputDevice < 0 || outputDevice >= pm_descriptor_index)
+        err = pmInvalidDeviceId;
+    else if (!descriptors[outputDevice].pub.output) 
+        err = pmInvalidDeviceId;
+    else if (descriptors[outputDevice].pub.opened)
+        err = pmInvalidDeviceId;
+    if (err != pmNoError) 
+        goto error_return;
+
+    /* create portMidi internal data */
+    midi = (PmInternal *) pm_alloc(sizeof(PmInternal)); 
+    *stream = midi;                 
+    if (!midi) {
+        err = pmInsufficientMemory;
+        goto error_return;
+    }
+    midi->device_id = outputDevice;
+    midi->write_flag = TRUE;
+    midi->time_proc = time_proc;
+    /* if latency > 0, we need a time reference. If none is provided,
+       use PortTime library */
+    if (time_proc == NULL && latency != 0) {
+        if (!Pt_Started()) 
+            Pt_Start(1, 0, 0);
+        /* time_get does not take a parameter, so coerce */
+        midi->time_proc = (PmTimeProcPtr) Pt_Time;
+    }
+    midi->time_info = time_info;
+    midi->buffer_len = bufferSize;
+    midi->queue = NULL; /* unused by output */
+    /* if latency zero, output immediate (timestamps ignored) */
+    /* if latency < 0, use 0 but don't return an error */
+    if (latency < 0) latency = 0;
+    midi->latency = latency;
+    midi->sysex_in_progress = FALSE;
+    midi->sysex_message = 0; /* unused by output */
+    midi->sysex_message_count = 0; /* unused by output */
+    midi->filters = 0; /* not used for output */
+    midi->channel_mask = 0xFFFF;
+    midi->sync_time = 0;
+    midi->first_message = TRUE;
+    midi->dictionary = descriptors[outputDevice].dictionary;
+    midi->fill_base = NULL;
+    midi->fill_offset_ptr = NULL;
+    midi->fill_length = 0;
+    descriptors[outputDevice].internalDescriptor = midi;
+    /* open system dependent output device */
+    err = (*midi->dictionary->open)(midi, outputDriverInfo);
+    if (err) {
+        *stream = NULL;
+        descriptors[outputDevice].internalDescriptor = NULL;
+        /* free portMidi data */
+        pm_free(midi); 
+    } else {
+        /* portMidi input open successful */
+        descriptors[outputDevice].pub.opened = TRUE;
+    }
+error_return:
+    /* note: system-dependent code must set pm_hosterror and
+     * pm_hosterror_text if a pmHostError occurs
+     */
+    return pm_errmsg(err);
+}
+
+
+PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask)
+{
+    PmInternal *midi = (PmInternal *) stream;
+    PmError err = pmNoError;
+
+    if (midi == NULL)
+        err = pmBadPtr;
+    else
+        midi->channel_mask = mask;
+
+    return pm_errmsg(err);
+}
+
+
+PMEXPORT PmError Pm_SetFilter(PortMidiStream *stream, int32_t filters) {
+    PmInternal *midi = (PmInternal *) stream;
+    PmError err = pmNoError;
+
+    /* arg checking */
+    if (midi == NULL)
+        err = pmBadPtr;
+    else if (!descriptors[midi->device_id].pub.opened)
+        err = pmBadPtr;
+    else
+        midi->filters = filters;
+    return pm_errmsg(err);
+}
+
+
+PMEXPORT PmError Pm_Close( PortMidiStream *stream ) {
+    PmInternal *midi = (PmInternal *) stream;
+    PmError err = pmNoError;
+
+    pm_hosterror = FALSE;
+    /* arg checking */
+    if (midi == NULL) /* midi must point to something */
+        err = pmBadPtr;
+    /* if it is an open device, the device_id will be valid */
+    else if (midi->device_id < 0 || midi->device_id >= pm_descriptor_index)
+        err = pmBadPtr;
+    /* and the device should be in the opened state */
+    else if (!descriptors[midi->device_id].pub.opened)
+        err = pmBadPtr;
+    
+    if (err != pmNoError) 
+        goto error_return;
+
+    /* close the device */
+    err = (*midi->dictionary->close)(midi);
+    /* even if an error occurred, continue with cleanup */
+    descriptors[midi->device_id].internalDescriptor = NULL;
+    descriptors[midi->device_id].pub.opened = FALSE;
+    if (midi->queue) Pm_QueueDestroy(midi->queue);
+    pm_free(midi); 
+error_return:
+    /* system dependent code must set pm_hosterror and
+     * pm_hosterror_text if a pmHostError occurs.
+     */
+    return pm_errmsg(err);
+}
+
+PmError Pm_Synchronize( PortMidiStream* stream ) {
+    PmInternal *midi = (PmInternal *) stream;
+    PmError err = pmNoError;
+    if (midi == NULL)
+        err = pmBadPtr;
+    else if (!descriptors[midi->device_id].pub.output)
+        err = pmBadPtr;
+    else if (!descriptors[midi->device_id].pub.opened)
+        err = pmBadPtr;
+    else
+        midi->first_message = TRUE;
+    return err;
+}
+
+PMEXPORT PmError Pm_Abort( PortMidiStream* stream ) {
+    PmInternal *midi = (PmInternal *) stream;
+    PmError err;
+    /* arg checking */
+    if (midi == NULL)
+        err = pmBadPtr;
+    else if (!descriptors[midi->device_id].pub.output)
+        err = pmBadPtr;
+    else if (!descriptors[midi->device_id].pub.opened)
+        err = pmBadPtr;
+    else
+        err = (*midi->dictionary->abort)(midi);
+
+    if (err == pmHostError) {
+        midi->dictionary->host_error(midi, pm_hosterror_text, 
+                                     PM_HOST_ERROR_MSG_LEN);
+        pm_hosterror = TRUE;
+    }
+    return pm_errmsg(err);
+}
+
+
+
+/* pm_channel_filtered returns non-zero if the channel mask is blocking the current channel */
+#define pm_channel_filtered(status, mask) \
+    ((((status) & 0xF0) != 0xF0) && (!(Pm_Channel((status) & 0x0F) & (mask))))
+
+
+/* The following two functions will checks to see if a MIDI message matches
+   the filtering criteria.  Since the sysex routines only want to filter realtime messages,
+   we need to have separate routines.
+ */
+
+
+/* pm_realtime_filtered returns non-zero if the filter will kill the current message.
+   Note that only realtime messages are checked here.
+ */
+#define pm_realtime_filtered(status, filters) \
+    ((((status) & 0xF0) == 0xF0) && ((1 << ((status) & 0xF)) & (filters)))
+
+/*
+    return ((status == MIDI_ACTIVE) && (filters & PM_FILT_ACTIVE))
+            ||  ((status == MIDI_CLOCK) && (filters & PM_FILT_CLOCK))
+            ||  ((status == MIDI_START) && (filters & PM_FILT_PLAY))
+            ||  ((status == MIDI_STOP) && (filters & PM_FILT_PLAY))
+            ||  ((status == MIDI_CONTINUE) && (filters & PM_FILT_PLAY))
+            ||  ((status == MIDI_F9) && (filters & PM_FILT_F9))
+            ||  ((status == MIDI_FD) && (filters & PM_FILT_FD))
+            ||  ((status == MIDI_RESET) && (filters & PM_FILT_RESET))
+            ||  ((status == MIDI_MTC) && (filters & PM_FILT_MTC))
+            ||  ((status == MIDI_SONGPOS) && (filters & PM_FILT_SONG_POSITION))
+            ||  ((status == MIDI_SONGSEL) && (filters & PM_FILT_SONG_SELECT))
+            ||  ((status == MIDI_TUNE) && (filters & PM_FILT_TUNE));
+}*/
+
+
+/* pm_status_filtered returns non-zero if a filter will kill the current message, based on status.
+   Note that sysex and real time are not checked.  It is up to the subsystem (winmm, core midi, alsa)
+   to filter sysex, as it is handled more easily and efficiently at that level.
+   Realtime message are filtered in pm_realtime_filtered.
+ */
+#define pm_status_filtered(status, filters) ((1 << (16 + ((status) >> 4))) & (filters))
+
+
+/*
+    return  ((status == MIDI_NOTE_ON) && (filters & PM_FILT_NOTE))
+            ||  ((status == MIDI_NOTE_OFF) && (filters & PM_FILT_NOTE))
+            ||  ((status == MIDI_CHANNEL_AT) && (filters & PM_FILT_CHANNEL_AFTERTOUCH))
+            ||  ((status == MIDI_POLY_AT) && (filters & PM_FILT_POLY_AFTERTOUCH))
+            ||  ((status == MIDI_PROGRAM) && (filters & PM_FILT_PROGRAM))
+            ||  ((status == MIDI_CONTROL) && (filters & PM_FILT_CONTROL))
+            ||  ((status == MIDI_PITCHBEND) && (filters & PM_FILT_PITCHBEND));
+
+}
+*/
+
+static void pm_flush_sysex(PmInternal *midi, PmTimestamp timestamp)
+{
+    PmEvent event;
+    
+    /* there may be nothing in the buffer */
+    if (midi->sysex_message_count == 0) return; /* nothing to flush */
+    
+    event.message = midi->sysex_message;
+    event.timestamp = timestamp;
+    /* copied from pm_read_short, avoids filtering */
+    if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
+        midi->sysex_in_progress = FALSE;
+    }
+    midi->sysex_message_count = 0;
+    midi->sysex_message = 0;
+}
+
+
+/* pm_read_short and pm_read_bytes
+   are the interface between system-dependent MIDI input handlers
+   and the system-independent PortMIDI code.
+   The input handler MUST obey these rules:
+   1) all short input messages must be sent to pm_read_short, which
+      enqueues them to a FIFO for the application.
+   2) each buffer of sysex bytes should be reported by calling pm_read_bytes
+      (which sets midi->sysex_in_progress). After the eox byte, 
+      pm_read_bytes will clear sysex_in_progress
+ */
+
+/* pm_read_short is the place where all input messages arrive from 
+   system-dependent code such as pmwinmm.c. Here, the messages
+   are entered into the PortMidi input buffer. 
+ */
+void pm_read_short(PmInternal *midi, PmEvent *event)
+{ 
+    int status;
+    /* arg checking */
+    assert(midi != NULL);
+    /* midi filtering is applied here */
+    status = Pm_MessageStatus(event->message);
+    if (!pm_status_filtered(status, midi->filters)
+        && (!is_real_time(status) || 
+            !pm_realtime_filtered(status, midi->filters))
+        && !pm_channel_filtered(status, midi->channel_mask)) {
+        /* if sysex is in progress and we get a status byte, it had
+           better be a realtime message or the starting SYSEX byte;
+           otherwise, we exit the sysex_in_progress state
+         */
+        if (midi->sysex_in_progress && (status & MIDI_STATUS_MASK)) {
+            /* two choices: real-time or not. If it's real-time, then
+             * this should be delivered as a sysex byte because it is
+             * embedded in a sysex message
+             */
+            if (is_real_time(status)) {
+                midi->sysex_message |= 
+                        (status << (8 * midi->sysex_message_count++));
+                if (midi->sysex_message_count == 4) {
+                    pm_flush_sysex(midi, event->timestamp);
+                }
+            } else { /* otherwise, it's not real-time. This interrupts
+                      * a sysex message in progress */
+                midi->sysex_in_progress = FALSE;
+            }
+        } else if (Pm_Enqueue(midi->queue, event) == pmBufferOverflow) {
+            midi->sysex_in_progress = FALSE;
+        }
+    }
+}
+
+/* pm_read_bytes -- read one (partial) sysex msg from MIDI data */
+/*
+ * returns how many bytes processed
+ */
+unsigned int pm_read_bytes(PmInternal *midi, const unsigned char *data, 
+                    int len, PmTimestamp timestamp)
+{
+    int i = 0; /* index into data, must not be unsigned (!) */
+    PmEvent event;
+    event.timestamp = timestamp;
+    assert(midi);
+    /* note that since buffers may not have multiples of 4 bytes,
+     * pm_read_bytes may be called in the middle of an outgoing
+     * 4-byte PortMidi message. sysex_in_progress indicates that
+     * a sysex has been sent but no eox.
+     */
+    if (len == 0) return 0; /* sanity check */
+    if (!midi->sysex_in_progress) {
+        while (i < len) { /* process all data */
+            unsigned char byte = data[i++];
+            if (byte == MIDI_SYSEX &&
+                !pm_realtime_filtered(byte, midi->filters)) {
+                midi->sysex_in_progress = TRUE;
+                i--; /* back up so code below will get SYSEX byte */
+                break; /* continue looping below to process msg */
+            } else if (byte == MIDI_EOX) {
+                midi->sysex_in_progress = FALSE;
+                return i; /* done with one message */
+            } else if (byte & MIDI_STATUS_MASK) {
+                /* We're getting MIDI but no sysex in progress.
+                 * Either the SYSEX status byte was dropped or
+                 * the message was filtered. Drop the data, but
+                 * send any embedded realtime bytes.
+                 */
+                /* assume that this is a real-time message:
+                 * it is an error to pass non-real-time messages
+                 * to pm_read_bytes
+                 */
+                event.message = byte;
+                pm_read_short(midi, &event);
+            }
+        } /* all bytes in the buffer are processed */
+    }
+    /* Now, i<len implies sysex_in_progress. If sysex_in_progress
+     * becomes false in the loop, there must have been an overflow
+     * and we can just drop all remaining bytes 
+     */
+    while (i < len && midi->sysex_in_progress) {
+        if (midi->sysex_message_count == 0 && i <= len - 4 &&
+            ((event.message = (((PmMessage) data[i]) | 
+                             (((PmMessage) data[i+1]) << 8) |
+                             (((PmMessage) data[i+2]) << 16) |
+                             (((PmMessage) data[i+3]) << 24))) &
+             0x80808080) == 0) { /* all data, no status */ 
+            if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
+                midi->sysex_in_progress = FALSE;
+            }
+            i += 4;
+        } else {
+            while (i < len) {
+                /* send one byte at a time */
+                unsigned char byte = data[i++];
+                if (is_real_time(byte) && 
+                    pm_realtime_filtered(byte, midi->filters)) {
+                    continue; /* real-time data is filtered, so omit */
+                }
+                midi->sysex_message |= 
+                    (byte << (8 * midi->sysex_message_count++));
+                if (byte == MIDI_EOX) {
+                    midi->sysex_in_progress = FALSE;
+                    pm_flush_sysex(midi, event.timestamp);
+                    return i;
+                } else if (midi->sysex_message_count == 4) {
+                    pm_flush_sysex(midi, event.timestamp);
+                    /* after handling at least one non-data byte
+                     * and reaching a 4-byte message boundary,
+                     * resume trying to send 4 at a time in outer loop
+                     */
+                    break;
+                }
+            }
+        }
+    }
+    return i;
+}
+
+
diff --git a/pd/portmidi/pm_common/portmidi.h b/pd/portmidi/pm_common/portmidi.h
old mode 100644
new mode 100755
index 8f4879f38339075e0abd403f0f605154e50d160f..e07991e0d685f8398c362b1908fa592b0e73e090
--- a/pd/portmidi/pm_common/portmidi.h
+++ b/pd/portmidi/pm_common/portmidi.h
@@ -1,606 +1,654 @@
-#ifndef PORT_MIDI_H
-#define PORT_MIDI_H
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/*
- * PortMidi Portable Real-Time MIDI Library
- * PortMidi API Header File
- * Latest version available at: http://www.cs.cmu.edu/~music/portmidi/
- *
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
- * Copyright (c) 2001-2006 Roger B. Dannenberg
- *
- * Latest version available at: http://www.cs.cmu.edu/~music/portmidi/
- *
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
- * Copyright (c) 2001-2006 Roger B. Dannenberg
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights 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 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 text above constitutes the entire PortMidi license; however, 
- * the PortMusic community also makes the following non-binding requests:
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version. It is also
- * requested that these non-binding requests be included along with the 
- * license above.
- */
-
-/* CHANGELOG FOR PORTMIDI
- *     (see ../CHANGELOG.txt)
- *
- * IMPORTANT INFORMATION ABOUT A WIN32 BUG:
- *
- *    Windows apparently has a serious midi bug -- if you do not close ports, Windows
- *    may crash. PortMidi tries to protect against this by using a DLL to clean up.
- *
- *    If client exits for example with:
- *      i)  assert 
- *      ii) Ctrl^c, 
- *    then DLL clean-up routine called. However, when client does something 
- *    really bad (e.g. assigns value to NULL pointer) then DLL CLEANUP ROUTINE
- *    NEVER RUNS! In this state, if you wait around long enough, you will
- *    probably get the blue screen of death. Can also go into Pview and there will
- *    exist zombie process that you can't kill.
- *
- *    You can enable the DLL cleanup routine by defining USE_DLL_FOR_CLEANUP.
- *    Do not define this preprocessor symbol if you do not want to use this
- *    feature.
- *
- * NOTES ON HOST ERROR REPORTING: 
- *
- *    PortMidi errors (of type PmError) are generic, system-independent errors.
- *    When an error does not map to one of the more specific PmErrors, the
- *    catch-all code pmHostError is returned. This means that PortMidi has
- *    retained a more specific system-dependent error code. The caller can
- *    get more information by calling Pm_HasHostError() to test if there is
- *    a pending host error, and Pm_GetHostErrorText() to get a text string
- *    describing the error. Host errors are reported on a per-device basis 
- *    because only after you open a device does PortMidi have a place to 
- *    record the host error code. I.e. only 
- *    those routines that receive a (PortMidiStream *) argument check and 
- *    report errors. One exception to this is that Pm_OpenInput() and 
- *    Pm_OpenOutput() can report errors even though when an error occurs,
- *    there is no PortMidiStream* to hold the error. Fortunately, both
- *    of these functions return any error immediately, so we do not really
- *    need per-device error memory. Instead, any host error code is stored
- *    in a global, pmHostError is returned, and the user can call 
- *    Pm_GetHostErrorText() to get the error message (and the invalid stream
- *    parameter will be ignored.) The functions 
- *    pm_init and pm_term do not fail or raise
- *    errors. The job of pm_init is to locate all available devices so that
- *    the caller can get information via PmDeviceInfo(). If an error occurs,
- *    the device is simply not listed as available.
- *
- *    Host errors come in two flavors:
- *      a) host error 
- *      b) host error during callback
- *    These can occur w/midi input or output devices. (b) can only happen 
- *    asynchronously (during callback routines), whereas (a) only occurs while
- *    synchronously running PortMidi and any resulting system dependent calls.
- *    Both (a) and (b) are reported by the next read or write call. You can
- *    also query for asynchronous errors (b) at any time by calling
- *    Pm_HasHostError().
- *
- * NOTES ON COMPILE-TIME SWITCHES
- *
- *    DEBUG assumes stdio and a console. Use this if you want automatic, simple
- *        error reporting, e.g. for prototyping. If you are using MFC or some 
- *        other graphical interface with no console, DEBUG probably should be
- *        undefined.
- *    PM_CHECK_ERRORS more-or-less takes over error checking for return values,
- *        stopping your program and printing error messages when an error
- *        occurs. This also uses stdio for console text I/O.
- *    USE_DLL_FOR_CLEANUP is described above. (Windows only.)
- *    
- */ 
-
-#ifndef FALSE
-    #define FALSE 0
-#endif
-#ifndef TRUE
-    #define TRUE 1
-#endif
-
-/* default size of buffers for sysex transmission: */
-#define PM_DEFAULT_SYSEX_BUFFER_SIZE 1024
-
-
-typedef enum {
-    pmNoError = 0,
-    pmHostError = -10000,
-    pmInvalidDeviceId, /* out of range or 
-                        * output device when input is requested or 
-                        * input device when output is requested or
-                        * device is already opened 
-                        */
-    pmInsufficientMemory,
-    pmBufferTooSmall,
-    pmBufferOverflow,
-    pmBadPtr,
-    pmBadData, /* illegal midi data, e.g. missing EOX */
-    pmInternalError,
-    pmBufferMaxSize /* buffer is already as large as it can be */
-    /* NOTE: If you add a new error type, be sure to update Pm_GetErrorText() */
-} PmError;
-
-/*
-    Pm_Initialize() is the library initialisation function - call this before
-    using the library.
-*/
-
-PmError Pm_Initialize( void );
-
-/*
-    Pm_Terminate() is the library termination function - call this after
-    using the library.
-*/
-
-PmError Pm_Terminate( void );
-
-/*  A single PortMidiStream is a descriptor for an open MIDI device.
-*/
-typedef void PortMidiStream;
-#define PmStream PortMidiStream
-
-/*
-    Test whether stream has a pending host error. Normally, the client finds
-    out about errors through returned error codes, but some errors can occur
-    asynchronously where the client does not
-    explicitly call a function, and therefore cannot receive an error code.
-    The client can test for a pending error using Pm_HasHostError(). If true,
-    the error can be accessed and cleared by calling Pm_GetErrorText(). 
-    Errors are also cleared by calling other functions that can return
-    errors, e.g. Pm_OpenInput(), Pm_OpenOutput(), Pm_Read(), Pm_Write(). The
-    client does not need to call Pm_HasHostError(). Any pending error will be
-    reported the next time the client performs an explicit function call on 
-    the stream, e.g. an input or output operation. Until the error is cleared,
-    no new error codes will be obtained, even for a different stream.
-*/
-int Pm_HasHostError( PortMidiStream * stream );
-
-
-/*  Translate portmidi error number into human readable message.
-    These strings are constants (set at compile time) so client has 
-    no need to allocate storage
-*/
-const char *Pm_GetErrorText( PmError errnum );
-
-/*  Translate portmidi host error into human readable message.
-    These strings are computed at run time, so client has to allocate storage.
-    After this routine executes, the host error is cleared. 
-*/
-void Pm_GetHostErrorText(char * msg, unsigned int len);
-
-#define HDRLENGTH 50
-#define PM_HOST_ERROR_MSG_LEN 256u /* any host error msg will occupy less 
-                                      than this number of characters */
-
-/*
-    Device enumeration mechanism.
-
-    Device ids range from 0 to Pm_CountDevices()-1.
-
-*/
-typedef int PmDeviceID;
-#define pmNoDevice -1
-typedef struct {
-    int structVersion; 
-    const char *interf; /* underlying MIDI API, e.g. MMSystem or DirectX */
-    const char *name;   /* device name, e.g. USB MidiSport 1x1 */
-    int input; /* true iff input is available */
-    int output; /* true iff output is available */
-    int opened; /* used by generic PortMidi code to do error checking on arguments */
-
-} PmDeviceInfo;
-
-
-int Pm_CountDevices( void );
-/*
-    Pm_GetDefaultInputDeviceID(), Pm_GetDefaultOutputDeviceID()
-
-    Return the default device ID or pmNoDevice if there are no devices.
-    The result can be passed to Pm_OpenMidi().
-    
-    On the PC, the user can specify a default device by
-    setting an environment variable. For example, to use device #1.
-
-        set PM_RECOMMENDED_OUTPUT_DEVICE=1
-    
-    The user should first determine the available device ID by using
-    the supplied application "testin" or "testout".
-
-    In general, the registry is a better place for this kind of info,
-    and with USB devices that can come and go, using integers is not
-    very reliable for device identification. Under Windows, if
-    PM_RECOMMENDED_OUTPUT_DEVICE (or PM_RECOMMENDED_INPUT_DEVICE) is
-    *NOT* found in the environment, then the default device is obtained
-    by looking for a string in the registry under:
-        HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Input_Device
-    and HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Output_Device
-    for a string. The number of the first device with a substring that
-    matches the string exactly is returned. For example, if the string
-    in the registry is "USB", and device 1 is named 
-    "In USB MidiSport 1x1", then that will be the default
-    input because it contains the string "USB".
-
-    In addition to the name, PmDeviceInfo has the member "interf", which
-    is the interface name. (The "interface" is the underlying software
-    system or API used by PortMidi to access devices. Examples are 
-    MMSystem, DirectX (not implemented), ALSA, OSS (not implemented), etc.)
-    At present, the only Win32 interface is "MMSystem", the only Linux
-    interface is "ALSA", and the only Max OS X interface is "CoreMIDI".
-    To specify both the interface and the device name in the registry,
-    separate the two with a comma and a space, e.g.:
-        MMSystem, In USB MidiSport 1x1
-    In this case, the string before the comma must be a substring of
-    the "interf" string, and the string after the space must be a 
-    substring of the "name" name string in order to match the device.
-
-    Note: in the current release, the default is simply the first device
-    (the input or output device with the lowest PmDeviceID).
-*/
-PmDeviceID Pm_GetDefaultInputDeviceID( void );
-PmDeviceID Pm_GetDefaultOutputDeviceID( void );
-
-/*
-    PmTimestamp is used to represent a millisecond clock with arbitrary
-    start time. The type is used for all MIDI timestampes and clocks.
-*/
-typedef long PmTimestamp;
-typedef PmTimestamp (*PmTimeProcPtr)(void *time_info);
-
-/* TRUE if t1 before t2 */
-#define PmBefore(t1,t2) ((t1-t2) < 0)
-
-/*
-    Pm_GetDeviceInfo() returns a pointer to a PmDeviceInfo structure
-    referring to the device specified by id.
-    If id is out of range the function returns NULL.
-
-    The returned structure is owned by the PortMidi implementation and must
-    not be manipulated or freed. The pointer is guaranteed to be valid
-    between calls to Pm_Initialize() and Pm_Terminate().
-*/
-const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id );
-
-/*
-    Pm_OpenInput() and Pm_OpenOutput() open devices.
-
-    stream is the address of a PortMidiStream pointer which will receive
-    a pointer to the newly opened stream.
-
-    inputDevice is the id of the device used for input (see PmDeviceID above).
-
-    inputDriverInfo is a pointer to an optional driver specific data structure
-    containing additional information for device setup or handle processing.
-    inputDriverInfo is never required for correct operation. If not used
-    inputDriverInfo should be NULL.
-
-    outputDevice is the id of the device used for output (see PmDeviceID above.)
-
-    outputDriverInfo is a pointer to an optional driver specific data structure
-    containing additional information for device setup or handle processing.
-    outputDriverInfo is never required for correct operation. If not used
-    outputDriverInfo should be NULL.
-
-    For input, the buffersize specifies the number of input events to be 
-    buffered waiting to be read using Pm_Read(). For output, buffersize 
-    specifies the number of output events to be buffered waiting for output. 
-    (In some cases -- see below -- PortMidi does not buffer output at all
-    and merely passes data to a lower-level API, in which case buffersize
-    is ignored.)
-    
-    latency is the delay in milliseconds applied to timestamps to determine 
-    when the output should actually occur. (If latency is < 0, 0 is assumed.) 
-    If latency is zero, timestamps are ignored and all output is delivered
-    immediately. If latency is greater than zero, output is delayed until
-    the message timestamp plus the latency. (NOTE: time is measured relative
-    to the time source indicated by time_proc. Timestamps are absolute, not
-    relative delays or offsets.) In some cases, PortMidi can obtain
-    better timing than your application by passing timestamps along to the
-    device driver or hardware. Latency may also help you to synchronize midi
-    data to audio data by matching midi latency to the audio buffer latency.
-
-    time_proc is a pointer to a procedure that returns time in milliseconds. It
-    may be NULL, in which case a default millisecond timebase (PortTime) is 
-    used. If the application wants to use PortTime, it should start the timer
-    (call Pt_Start) before calling Pm_OpenInput or Pm_OpenOutput. If the
-    application tries to start the timer *after* Pm_OpenInput or Pm_OpenOutput,
-    it may get a ptAlreadyStarted error from Pt_Start, and the application's
-    preferred time resolution and callback function will be ignored.
-    time_proc result values are appended to incoming MIDI data, and time_proc
-    times are used to schedule outgoing MIDI data (when latency is non-zero).
-
-    time_info is a pointer passed to time_proc. 
-
-    return value:
-    Upon success Pm_Open() returns PmNoError and places a pointer to a
-    valid PortMidiStream in the stream argument.
-    If a call to Pm_Open() fails a nonzero error code is returned (see
-    PMError above) and the value of port is invalid.
-
-    Any stream that is successfully opened should eventually be closed
-    by calling Pm_Close().
-
-*/
-PmError Pm_OpenInput( PortMidiStream** stream,
-                PmDeviceID inputDevice,
-                void *inputDriverInfo,
-                long bufferSize,
-                PmTimeProcPtr time_proc,
-                void *time_info );
-
-PmError Pm_OpenOutput( PortMidiStream** stream,
-                PmDeviceID outputDevice,
-                void *outputDriverInfo,
-                long bufferSize,
-                PmTimeProcPtr time_proc,
-                void *time_info,
-                long latency );
-
-/* 
-    Pm_SetFilter() sets filters on an open input stream to drop selected
-    input types. By default, only active sensing messages are filtered.
-    To prohibit, say, active sensing and sysex messages, call
-    Pm_SetFilter(stream, PM_FILT_ACTIVE | PM_FILT_SYSEX);
-
-    Filtering is useful when midi routing or midi thru functionality is being
-    provided by the user application.
-    For example, you may want to exclude timing messages (clock, MTC, start/stop/continue),
-    while allowing note-related messages to pass.
-    Or you may be using a sequencer or drum-machine for MIDI clock information but want to
-    exclude any notes it may play.
- */
-
-/* filter active sensing messages (0xFE): */
-#define PM_FILT_ACTIVE (1 << 0x0E)
-/* filter system exclusive messages (0xF0): */
-#define PM_FILT_SYSEX (1 << 0x00)
-/* filter clock messages (CLOCK 0xF8, START 0xFA, STOP 0xFC, and CONTINUE 0xFB) */
-#define PM_FILT_CLOCK ((1 << 0x08) | (1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B))
-/* filter play messages (start 0xFA, stop 0xFC, continue 0xFB) */
-#define PM_FILT_PLAY (1 << 0x0A)
-/* filter tick messages (0xF9) */
-#define PM_FILT_TICK (1 << 0x09)
-/* filter undefined FD messages */
-#define PM_FILT_FD (1 << 0x0D)
-/* filter undefined real-time messages */
-#define PM_FILT_UNDEFINED PM_FILT_FD
-/* filter reset messages (0xFF) */
-#define PM_FILT_RESET (1 << 0x0F)
-/* filter all real-time messages */
-#define PM_FILT_REALTIME (PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_CLOCK | \
-    PM_FILT_PLAY | PM_FILT_UNDEFINED | PM_FILT_RESET | PM_FILT_TICK)
-/* filter note-on and note-off (0x90-0x9F and 0x80-0x8F */
-#define PM_FILT_NOTE ((1 << 0x19) | (1 << 0x18))
-/* filter channel aftertouch (most midi controllers use this) (0xD0-0xDF)*/
-#define PM_FILT_CHANNEL_AFTERTOUCH (1 << 0x1D)
-/* per-note aftertouch (0xA0-0xAF) */
-#define PM_FILT_POLY_AFTERTOUCH (1 << 0x1A)
-/* filter both channel and poly aftertouch */
-#define PM_FILT_AFTERTOUCH (PM_FILT_CHANNEL_AFTERTOUCH | PM_FILT_POLY_AFTERTOUCH)
-/* Program changes (0xC0-0xCF) */
-#define PM_FILT_PROGRAM (1 << 0x1C)
-/* Control Changes (CC's) (0xB0-0xBF)*/
-#define PM_FILT_CONTROL (1 << 0x1B)
-/* Pitch Bender (0xE0-0xEF*/
-#define PM_FILT_PITCHBEND (1 << 0x1E)
-/* MIDI Time Code (0xF1)*/
-#define PM_FILT_MTC (1 << 0x01)
-/* Song Position (0xF2) */
-#define PM_FILT_SONG_POSITION (1 << 0x02)
-/* Song Select (0xF3)*/
-#define PM_FILT_SONG_SELECT (1 << 0x03)
-/* Tuning request (0xF6)*/
-#define PM_FILT_TUNE (1 << 0x06)
-/* All System Common messages (mtc, song position, song select, tune request) */
-#define PM_FILT_SYSTEMCOMMON (PM_FILT_MTC | PM_FILT_SONG_POSITION | PM_FILT_SONG_SELECT | PM_FILT_TUNE)
-
-
-PmError Pm_SetFilter( PortMidiStream* stream, long filters );
-
-/*
-    Pm_SetChannelMask() filters incoming messages based on channel.
-    The mask is a 16-bit bitfield corresponding to appropriate channels
-    The Pm_Channel macro can assist in calling this function.
-    i.e. to set receive only input on channel 1, call with
-    Pm_SetChannelMask(Pm_Channel(1));
-    Multiple channels should be OR'd together, like
-    Pm_SetChannelMask(Pm_Channel(10) | Pm_Channel(11))
-
-    All channels are allowed by default
-*/
-#define Pm_Channel(channel) (1<<(channel))
-
-PmError Pm_SetChannelMask(PortMidiStream *stream, int mask);
-
-/*
-    Pm_Abort() terminates outgoing messages immediately
-    The caller should immediately close the output port;
-    this call may result in transmission of a partial midi message.
-    There is no abort for Midi input because the user can simply
-    ignore messages in the buffer and close an input device at
-    any time.
- */
-PmError Pm_Abort( PortMidiStream* stream );
-     
-/*
-    Pm_Close() closes a midi stream, flushing any pending buffers.
-    (PortMidi attempts to close open streams when the application 
-    exits -- this is particularly difficult under Windows.)
-*/
-PmError Pm_Close( PortMidiStream* stream );
-
-/*
-    Pm_Message() encodes a short Midi message into a long word. If data1
-    and/or data2 are not present, use zero.
-
-    Pm_MessageStatus(), Pm_MessageData1(), and 
-    Pm_MessageData2() extract fields from a long-encoded midi message.
-*/
-#define Pm_Message(status, data1, data2) \
-         ((((data2) << 16) & 0xFF0000) | \
-          (((data1) << 8) & 0xFF00) | \
-          ((status) & 0xFF))
-#define Pm_MessageStatus(msg) ((msg) & 0xFF)
-#define Pm_MessageData1(msg) (((msg) >> 8) & 0xFF)
-#define Pm_MessageData2(msg) (((msg) >> 16) & 0xFF)
-
-/* All midi data comes in the form of PmEvent structures. A sysex
-   message is encoded as a sequence of PmEvent structures, with each
-   structure carrying 4 bytes of the message, i.e. only the first
-   PmEvent carries the status byte.
-
-   Note that MIDI allows nested messages: the so-called "real-time" MIDI 
-   messages can be inserted into the MIDI byte stream at any location, 
-   including within a sysex message. MIDI real-time messages are one-byte
-   messages used mainly for timing (see the MIDI spec). PortMidi retains 
-   the order of non-real-time MIDI messages on both input and output, but 
-   it does not specify exactly how real-time messages are processed. This
-   is particulary problematic for MIDI input, because the input parser 
-   must either prepare to buffer an unlimited number of sysex message 
-   bytes or to buffer an unlimited number of real-time messages that 
-   arrive embedded in a long sysex message. To simplify things, the input
-   parser is allowed to pass real-time MIDI messages embedded within a 
-   sysex message, and it is up to the client to detect, process, and 
-   remove these messages as they arrive.
-
-   When receiving sysex messages, the sysex message is terminated
-   by either an EOX status byte (anywhere in the 4 byte messages) or
-   by a non-real-time status byte in the low order byte of the message.
-   If you get a non-real-time status byte but there was no EOX byte, it 
-   means the sysex message was somehow truncated. This is not
-   considered an error; e.g., a missing EOX can result from the user
-   disconnecting a MIDI cable during sysex transmission.
-
-   A real-time message can occur within a sysex message. A real-time 
-   message will always occupy a full PmEvent with the status byte in 
-   the low-order byte of the PmEvent message field. (This implies that
-   the byte-order of sysex bytes and real-time message bytes may not
-   be preserved -- for example, if a real-time message arrives after
-   3 bytes of a sysex message, the real-time message will be delivered
-   first. The first word of the sysex message will be delivered only
-   after the 4th byte arrives, filling the 4-byte PmEvent message field.
-   
-   The timestamp field is observed when the output port is opened with
-   a non-zero latency. A timestamp of zero means "use the current time",
-   which in turn means to deliver the message with a delay of
-   latency (the latency parameter used when opening the output port.)
-   Do not expect PortMidi to sort data according to timestamps -- 
-   messages should be sent in the correct order, and timestamps MUST 
-   be non-decreasing.
-
-   A sysex message will generally fill many PmEvent structures. On 
-   output to a PortMidiStream with non-zero latency, the first timestamp
-   on sysex message data will determine the time to begin sending the 
-   message. PortMidi implementations may ignore timestamps for the 
-   remainder of the sysex message. 
-   
-   On input, the timestamp ideally denotes the arrival time of the 
-   status byte of the message. The first timestamp on sysex message 
-   data will be valid. Subsequent timestamps may denote 
-   when message bytes were actually received, or they may be simply 
-   copies of the first timestamp.
-
-   Timestamps for nested messages: If a real-time message arrives in 
-   the middle of some other message, it is enqueued immediately with 
-   the timestamp corresponding to its arrival time. The interrupted 
-   non-real-time message or 4-byte packet of sysex data will be enqueued 
-   later. The timestamp of interrupted data will be equal to that of
-   the interrupting real-time message to insure that timestamps are
-   non-decreasing.
- */
-typedef long PmMessage;
-typedef struct {
-    PmMessage      message;
-    PmTimestamp    timestamp;
-} PmEvent;
-
-/*
-    Pm_Read() retrieves midi data into a buffer, and returns the number
-    of events read. Result is a non-negative number unless an error occurs, 
-    in which case a PmError value will be returned.
-
-    Buffer Overflow
-
-    The problem: if an input overflow occurs, data will be lost, ultimately 
-    because there is no flow control all the way back to the data source. 
-    When data is lost, the receiver should be notified and some sort of 
-    graceful recovery should take place, e.g. you shouldn't resume receiving 
-    in the middle of a long sysex message.
-
-    With a lock-free fifo, which is pretty much what we're stuck with to 
-    enable portability to the Mac, it's tricky for the producer and consumer 
-    to synchronously reset the buffer and resume normal operation.
-
-    Solution: the buffer managed by PortMidi will be flushed when an overflow
-    occurs. The consumer (Pm_Read()) gets an error message (pmBufferOverflow)
-    and ordinary processing resumes as soon as a new message arrives. The
-    remainder of a partial sysex message is not considered to be a "new
-    message" and will be flushed as well.
-
-*/
-PmError Pm_Read( PortMidiStream *stream, PmEvent *buffer, long length );
-
-/*
-    Pm_Poll() tests whether input is available, 
-    returning TRUE, FALSE, or an error value.
-*/
-PmError Pm_Poll( PortMidiStream *stream);
-
-/* 
-    Pm_Write() writes midi data from a buffer. This may contain:
-        - short messages 
-    or 
-        - sysex messages that are converted into a sequence of PmEvent
-          structures, e.g. sending data from a file or forwarding them
-          from midi input.
-
-    Use Pm_WriteSysEx() to write a sysex message stored as a contiguous 
-    array of bytes.
-
-    Sysex data may contain embedded real-time messages.
-*/
-PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length );
-
-/*
-    Pm_WriteShort() writes a timestamped non-system-exclusive midi message.
-    Messages are delivered in order as received, and timestamps must be 
-    non-decreasing. (But timestamps are ignored if the stream was opened
-    with latency = 0.)
-*/
-PmError Pm_WriteShort( PortMidiStream *stream, PmTimestamp when, long msg);
-
-/*
-    Pm_WriteSysEx() writes a timestamped system-exclusive midi message.
-*/
-PmError Pm_WriteSysEx( PortMidiStream *stream, PmTimestamp when, unsigned char *msg);
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PORT_MIDI_H */
+#ifndef PORT_MIDI_H
+#define PORT_MIDI_H
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * PortMidi Portable Real-Time MIDI Library
+ * PortMidi API Header File
+ * Latest version available at: http://sourceforge.net/projects/portmedia
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ * Copyright (c) 2001-2006 Roger B. Dannenberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights 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 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 text above constitutes the entire PortMidi license; however, 
+ * the PortMusic community also makes the following non-binding requests:
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version. It is also
+ * requested that these non-binding requests be included along with the 
+ * license above.
+ */
+
+/* CHANGELOG FOR PORTMIDI
+ *     (see ../CHANGELOG.txt)
+ *
+ * NOTES ON HOST ERROR REPORTING: 
+ *
+ *    PortMidi errors (of type PmError) are generic, system-independent errors.
+ *    When an error does not map to one of the more specific PmErrors, the
+ *    catch-all code pmHostError is returned. This means that PortMidi has
+ *    retained a more specific system-dependent error code. The caller can
+ *    get more information by calling Pm_HasHostError() to test if there is
+ *    a pending host error, and Pm_GetHostErrorText() to get a text string
+ *    describing the error. Host errors are reported on a per-device basis 
+ *    because only after you open a device does PortMidi have a place to 
+ *    record the host error code. I.e. only 
+ *    those routines that receive a (PortMidiStream *) argument check and 
+ *    report errors. One exception to this is that Pm_OpenInput() and 
+ *    Pm_OpenOutput() can report errors even though when an error occurs,
+ *    there is no PortMidiStream* to hold the error. Fortunately, both
+ *    of these functions return any error immediately, so we do not really
+ *    need per-device error memory. Instead, any host error code is stored
+ *    in a global, pmHostError is returned, and the user can call 
+ *    Pm_GetHostErrorText() to get the error message (and the invalid stream
+ *    parameter will be ignored.) The functions 
+ *    pm_init and pm_term do not fail or raise
+ *    errors. The job of pm_init is to locate all available devices so that
+ *    the caller can get information via PmDeviceInfo(). If an error occurs,
+ *    the device is simply not listed as available.
+ *
+ *    Host errors come in two flavors:
+ *      a) host error 
+ *      b) host error during callback
+ *    These can occur w/midi input or output devices. (b) can only happen 
+ *    asynchronously (during callback routines), whereas (a) only occurs while
+ *    synchronously running PortMidi and any resulting system dependent calls.
+ *    Both (a) and (b) are reported by the next read or write call. You can
+ *    also query for asynchronous errors (b) at any time by calling
+ *    Pm_HasHostError().
+ *
+ * NOTES ON COMPILE-TIME SWITCHES
+ *
+ *    DEBUG assumes stdio and a console. Use this if you want automatic, simple
+ *        error reporting, e.g. for prototyping. If you are using MFC or some 
+ *        other graphical interface with no console, DEBUG probably should be
+ *        undefined.
+ *    PM_CHECK_ERRORS more-or-less takes over error checking for return values,
+ *        stopping your program and printing error messages when an error
+ *        occurs. This also uses stdio for console text I/O.
+ */
+
+#ifndef WIN32
+// Linux and OS X have stdint.h
+#include <stdint.h>
+#else
+#ifndef INT32_DEFINED
+// rather than having users install a special .h file for windows, 
+// just put the required definitions inline here. porttime.h uses
+// these too, so the definitions are (unfortunately) duplicated there
+typedef int int32_t;
+typedef unsigned int uint32_t;
+#define INT32_DEFINED
+#endif
+#endif
+
+#ifdef _WINDLL
+#define PMEXPORT __declspec(dllexport)
+#else
+#define PMEXPORT 
+#endif
+
+#ifndef FALSE
+    #define FALSE 0
+#endif
+#ifndef TRUE
+    #define TRUE 1
+#endif
+
+/* default size of buffers for sysex transmission: */
+#define PM_DEFAULT_SYSEX_BUFFER_SIZE 1024
+
+/** List of portmidi errors.*/
+typedef enum {
+    pmNoError = 0,
+    pmNoData = 0, /**< A "no error" return that also indicates no data avail. */
+    pmGotData = 1, /**< A "no error" return that also indicates data available */
+    pmHostError = -10000,
+    pmInvalidDeviceId, /** out of range or 
+                        * output device when input is requested or 
+                        * input device when output is requested or
+                        * device is already opened 
+                        */
+    pmInsufficientMemory,
+    pmBufferTooSmall,
+    pmBufferOverflow,
+    pmBadPtr, /* PortMidiStream parameter is NULL or
+               * stream is not opened or
+               * stream is output when input is required or
+               * stream is input when output is required */
+    pmBadData, /** illegal midi data, e.g. missing EOX */
+    pmInternalError,
+    pmBufferMaxSize /** buffer is already as large as it can be */
+    /* NOTE: If you add a new error type, be sure to update Pm_GetErrorText() */
+} PmError;
+
+/**
+    Pm_Initialize() is the library initialisation function - call this before
+    using the library.
+*/
+PMEXPORT PmError Pm_Initialize( void );
+
+/**
+    Pm_Terminate() is the library termination function - call this after
+    using the library.
+*/
+PMEXPORT PmError Pm_Terminate( void );
+
+/**  A single PortMidiStream is a descriptor for an open MIDI device.
+*/
+typedef void PortMidiStream;
+#define PmStream PortMidiStream
+
+/**
+    Test whether stream has a pending host error. Normally, the client finds
+    out about errors through returned error codes, but some errors can occur
+    asynchronously where the client does not
+    explicitly call a function, and therefore cannot receive an error code.
+    The client can test for a pending error using Pm_HasHostError(). If true,
+    the error can be accessed and cleared by calling Pm_GetErrorText(). 
+    Errors are also cleared by calling other functions that can return
+    errors, e.g. Pm_OpenInput(), Pm_OpenOutput(), Pm_Read(), Pm_Write(). The
+    client does not need to call Pm_HasHostError(). Any pending error will be
+    reported the next time the client performs an explicit function call on 
+    the stream, e.g. an input or output operation. Until the error is cleared,
+    no new error codes will be obtained, even for a different stream.
+*/
+PMEXPORT int Pm_HasHostError( PortMidiStream * stream );
+
+
+/**  Translate portmidi error number into human readable message.
+    These strings are constants (set at compile time) so client has 
+    no need to allocate storage
+*/
+PMEXPORT const char *Pm_GetErrorText( PmError errnum );
+
+/**  Translate portmidi host error into human readable message.
+    These strings are computed at run time, so client has to allocate storage.
+    After this routine executes, the host error is cleared. 
+*/
+PMEXPORT void Pm_GetHostErrorText(char * msg, unsigned int len);
+
+#define HDRLENGTH 50
+#define PM_HOST_ERROR_MSG_LEN 256u /* any host error msg will occupy less 
+                                      than this number of characters */
+
+/**
+    Device enumeration mechanism.
+
+    Device ids range from 0 to Pm_CountDevices()-1.
+
+*/
+typedef int PmDeviceID;
+#define pmNoDevice -1
+typedef struct {
+    int structVersion; /**< this internal structure version */ 
+    const char *interf; /**< underlying MIDI API, e.g. MMSystem or DirectX */
+    const char *name;   /**< device name, e.g. USB MidiSport 1x1 */
+    int input; /**< true iff input is available */
+    int output; /**< true iff output is available */
+    int opened; /**< used by generic PortMidi code to do error checking on arguments */
+
+} PmDeviceInfo;
+
+/**  Get devices count, ids range from 0 to Pm_CountDevices()-1. */
+PMEXPORT int Pm_CountDevices( void );
+/**
+    Pm_GetDefaultInputDeviceID(), Pm_GetDefaultOutputDeviceID()
+
+    Return the default device ID or pmNoDevice if there are no devices.
+    The result (but not pmNoDevice) can be passed to Pm_OpenMidi().
+    
+    The default device can be specified using a small application
+    named pmdefaults that is part of the PortMidi distribution. This
+    program in turn uses the Java Preferences object created by
+    java.util.prefs.Preferences.userRoot().node("/PortMidi"); the
+    preference is set by calling 
+        prefs.put("PM_RECOMMENDED_OUTPUT_DEVICE", prefName);
+    or  prefs.put("PM_RECOMMENDED_INPUT_DEVICE", prefName);
+    
+    In the statements above, prefName is a string describing the
+    MIDI device in the form "interf, name" where interf identifies
+    the underlying software system or API used by PortMdi to access
+    devices and name is the name of the device. These correspond to 
+    the interf and name fields of a PmDeviceInfo. (Currently supported
+    interfaces are "MMSystem" for Win32, "ALSA" for Linux, and 
+    "CoreMIDI" for OS X, so in fact, there is no choice of interface.)
+    In "interf, name", the strings are actually substrings of 
+    the full interface and name strings. For example, the preference 
+    "Core, Sport" will match a device with interface "CoreMIDI"
+    and name "In USB MidiSport 1x1". It will also match "CoreMIDI"
+    and "In USB MidiSport 2x2". The devices are enumerated in device
+    ID order, so the lowest device ID that matches the pattern becomes
+    the default device. Finally, if the comma-space (", ") separator
+    between interface and name parts of the preference is not found,
+    the entire preference string is interpreted as a name, and the
+    interface part is the empty string, which matches anything.
+
+    On the MAC, preferences are stored in 
+      /Users/$NAME/Library/Preferences/com.apple.java.util.prefs.plist
+    which is a binary file. In addition to the pmdefaults program,
+    there are utilities that can read and edit this preference file.
+
+    On the PC, 
+
+    On Linux, 
+
+*/
+PMEXPORT PmDeviceID Pm_GetDefaultInputDeviceID( void );
+/** see PmDeviceID Pm_GetDefaultInputDeviceID() */
+PMEXPORT PmDeviceID Pm_GetDefaultOutputDeviceID( void );
+
+/**
+    PmTimestamp is used to represent a millisecond clock with arbitrary
+    start time. The type is used for all MIDI timestampes and clocks.
+*/
+typedef int32_t PmTimestamp;
+typedef PmTimestamp (*PmTimeProcPtr)(void *time_info);
+
+/** TRUE if t1 before t2 */
+#define PmBefore(t1,t2) ((t1-t2) < 0)
+/** 
+    \defgroup grp_device Input/Output Devices Handling
+    @{
+*/
+/**
+    Pm_GetDeviceInfo() returns a pointer to a PmDeviceInfo structure
+    referring to the device specified by id.
+    If id is out of range the function returns NULL.
+
+    The returned structure is owned by the PortMidi implementation and must
+    not be manipulated or freed. The pointer is guaranteed to be valid
+    between calls to Pm_Initialize() and Pm_Terminate().
+*/
+PMEXPORT const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id );
+
+/**
+    Pm_OpenInput() and Pm_OpenOutput() open devices.
+
+    stream is the address of a PortMidiStream pointer which will receive
+    a pointer to the newly opened stream.
+
+    inputDevice is the id of the device used for input (see PmDeviceID above).
+
+    inputDriverInfo is a pointer to an optional driver specific data structure
+    containing additional information for device setup or handle processing.
+    inputDriverInfo is never required for correct operation. If not used
+    inputDriverInfo should be NULL.
+
+    outputDevice is the id of the device used for output (see PmDeviceID above.)
+
+    outputDriverInfo is a pointer to an optional driver specific data structure
+    containing additional information for device setup or handle processing.
+    outputDriverInfo is never required for correct operation. If not used
+    outputDriverInfo should be NULL.
+
+    For input, the buffersize specifies the number of input events to be 
+    buffered waiting to be read using Pm_Read(). For output, buffersize 
+    specifies the number of output events to be buffered waiting for output. 
+    (In some cases -- see below -- PortMidi does not buffer output at all
+    and merely passes data to a lower-level API, in which case buffersize
+    is ignored.)
+    
+    latency is the delay in milliseconds applied to timestamps to determine 
+    when the output should actually occur. (If latency is < 0, 0 is assumed.) 
+    If latency is zero, timestamps are ignored and all output is delivered
+    immediately. If latency is greater than zero, output is delayed until the
+    message timestamp plus the latency. (NOTE: the time is measured relative 
+    to the time source indicated by time_proc. Timestamps are absolute,
+    not relative delays or offsets.) In some cases, PortMidi can obtain
+    better timing than your application by passing timestamps along to the
+    device driver or hardware. Latency may also help you to synchronize midi
+    data to audio data by matching midi latency to the audio buffer latency.
+
+    time_proc is a pointer to a procedure that returns time in milliseconds. It
+    may be NULL, in which case a default millisecond timebase (PortTime) is 
+    used. If the application wants to use PortTime, it should start the timer
+    (call Pt_Start) before calling Pm_OpenInput or Pm_OpenOutput. If the
+    application tries to start the timer *after* Pm_OpenInput or Pm_OpenOutput,
+    it may get a ptAlreadyStarted error from Pt_Start, and the application's
+    preferred time resolution and callback function will be ignored.
+    time_proc result values are appended to incoming MIDI data, and time_proc
+    times are used to schedule outgoing MIDI data (when latency is non-zero).
+
+    time_info is a pointer passed to time_proc.
+
+    Example: If I provide a timestamp of 5000, latency is 1, and time_proc
+    returns 4990, then the desired output time will be when time_proc returns
+    timestamp+latency = 5001. This will be 5001-4990 = 11ms from now.
+
+    return value:
+    Upon success Pm_Open() returns PmNoError and places a pointer to a
+    valid PortMidiStream in the stream argument.
+    If a call to Pm_Open() fails a nonzero error code is returned (see
+    PMError above) and the value of port is invalid.
+
+    Any stream that is successfully opened should eventually be closed
+    by calling Pm_Close().
+
+*/
+PMEXPORT PmError Pm_OpenInput( PortMidiStream** stream,
+                PmDeviceID inputDevice,
+                void *inputDriverInfo,
+                int32_t bufferSize,
+                PmTimeProcPtr time_proc,
+                void *time_info );
+
+PMEXPORT PmError Pm_OpenOutput( PortMidiStream** stream,
+                PmDeviceID outputDevice,
+                void *outputDriverInfo,
+                int32_t bufferSize,
+                PmTimeProcPtr time_proc,
+                void *time_info,
+                int32_t latency );
+  /** @} */
+
+/**
+   \defgroup grp_events_filters Events and Filters Handling
+   @{
+*/
+
+/*  \function PmError Pm_SetFilter( PortMidiStream* stream, int32_t filters )
+    Pm_SetFilter() sets filters on an open input stream to drop selected
+    input types. By default, only active sensing messages are filtered.
+    To prohibit, say, active sensing and sysex messages, call
+    Pm_SetFilter(stream, PM_FILT_ACTIVE | PM_FILT_SYSEX);
+
+    Filtering is useful when midi routing or midi thru functionality is being
+    provided by the user application.
+    For example, you may want to exclude timing messages (clock, MTC, start/stop/continue),
+    while allowing note-related messages to pass.
+    Or you may be using a sequencer or drum-machine for MIDI clock information but want to
+    exclude any notes it may play.
+ */
+    
+/* Filter bit-mask definitions */
+/** filter active sensing messages (0xFE): */
+#define PM_FILT_ACTIVE (1 << 0x0E)
+/** filter system exclusive messages (0xF0): */
+#define PM_FILT_SYSEX (1 << 0x00)
+/** filter MIDI clock message (0xF8) */
+#define PM_FILT_CLOCK (1 << 0x08)
+/** filter play messages (start 0xFA, stop 0xFC, continue 0xFB) */
+#define PM_FILT_PLAY ((1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B))
+/** filter tick messages (0xF9) */
+#define PM_FILT_TICK (1 << 0x09)
+/** filter undefined FD messages */
+#define PM_FILT_FD (1 << 0x0D)
+/** filter undefined real-time messages */
+#define PM_FILT_UNDEFINED PM_FILT_FD
+/** filter reset messages (0xFF) */
+#define PM_FILT_RESET (1 << 0x0F)
+/** filter all real-time messages */
+#define PM_FILT_REALTIME (PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_CLOCK | \
+    PM_FILT_PLAY | PM_FILT_UNDEFINED | PM_FILT_RESET | PM_FILT_TICK)
+/** filter note-on and note-off (0x90-0x9F and 0x80-0x8F */
+#define PM_FILT_NOTE ((1 << 0x19) | (1 << 0x18))
+/** filter channel aftertouch (most midi controllers use this) (0xD0-0xDF)*/
+#define PM_FILT_CHANNEL_AFTERTOUCH (1 << 0x1D)
+/** per-note aftertouch (0xA0-0xAF) */
+#define PM_FILT_POLY_AFTERTOUCH (1 << 0x1A)
+/** filter both channel and poly aftertouch */
+#define PM_FILT_AFTERTOUCH (PM_FILT_CHANNEL_AFTERTOUCH | PM_FILT_POLY_AFTERTOUCH)
+/** Program changes (0xC0-0xCF) */
+#define PM_FILT_PROGRAM (1 << 0x1C)
+/** Control Changes (CC's) (0xB0-0xBF)*/
+#define PM_FILT_CONTROL (1 << 0x1B)
+/** Pitch Bender (0xE0-0xEF*/
+#define PM_FILT_PITCHBEND (1 << 0x1E)
+/** MIDI Time Code (0xF1)*/
+#define PM_FILT_MTC (1 << 0x01)
+/** Song Position (0xF2) */
+#define PM_FILT_SONG_POSITION (1 << 0x02)
+/** Song Select (0xF3)*/
+#define PM_FILT_SONG_SELECT (1 << 0x03)
+/** Tuning request (0xF6)*/
+#define PM_FILT_TUNE (1 << 0x06)
+/** All System Common messages (mtc, song position, song select, tune request) */
+#define PM_FILT_SYSTEMCOMMON (PM_FILT_MTC | PM_FILT_SONG_POSITION | PM_FILT_SONG_SELECT | PM_FILT_TUNE)
+
+
+PMEXPORT PmError Pm_SetFilter( PortMidiStream* stream, int32_t filters );
+
+#define Pm_Channel(channel) (1<<(channel))
+/**
+    Pm_SetChannelMask() filters incoming messages based on channel.
+    The mask is a 16-bit bitfield corresponding to appropriate channels.
+    The Pm_Channel macro can assist in calling this function.
+    i.e. to set receive only input on channel 1, call with
+    Pm_SetChannelMask(Pm_Channel(1));
+    Multiple channels should be OR'd together, like
+    Pm_SetChannelMask(Pm_Channel(10) | Pm_Channel(11))
+
+    Note that channels are numbered 0 to 15 (not 1 to 16). Most 
+    synthesizer and interfaces number channels starting at 1, but
+    PortMidi numbers channels starting at 0.
+
+    All channels are allowed by default
+*/
+PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask);
+
+/**
+    Pm_Abort() terminates outgoing messages immediately
+    The caller should immediately close the output port;
+    this call may result in transmission of a partial midi message.
+    There is no abort for Midi input because the user can simply
+    ignore messages in the buffer and close an input device at
+    any time.
+ */
+PMEXPORT PmError Pm_Abort( PortMidiStream* stream );
+     
+/**
+    Pm_Close() closes a midi stream, flushing any pending buffers.
+    (PortMidi attempts to close open streams when the application 
+    exits -- this is particularly difficult under Windows.)
+*/
+PMEXPORT PmError Pm_Close( PortMidiStream* stream );
+
+/**
+    Pm_Synchronize() instructs PortMidi to (re)synchronize to the
+    time_proc passed when the stream was opened. Typically, this
+    is used when the stream must be opened before the time_proc
+    reference is actually advancing. In this case, message timing
+    may be erratic, but since timestamps of zero mean 
+    "send immediately," initialization messages with zero timestamps
+    can be written without a functioning time reference and without
+    problems. Before the first MIDI message with a non-zero
+    timestamp is written to the stream, the time reference must
+    begin to advance (for example, if the time_proc computes time
+    based on audio samples, time might begin to advance when an 
+    audio stream becomes active). After time_proc return values
+    become valid, and BEFORE writing the first non-zero timestamped 
+    MIDI message, call Pm_Synchronize() so that PortMidi can observe
+    the difference between the current time_proc value and its
+    MIDI stream time. 
+    
+    In the more normal case where time_proc 
+    values advance continuously, there is no need to call 
+    Pm_Synchronize. PortMidi will always synchronize at the 
+    first output message and periodically thereafter.
+*/
+PmError Pm_Synchronize( PortMidiStream* stream );
+
+
+/**
+    Pm_Message() encodes a short Midi message into a 32-bit word. If data1
+    and/or data2 are not present, use zero.
+
+    Pm_MessageStatus(), Pm_MessageData1(), and 
+    Pm_MessageData2() extract fields from a 32-bit midi message.
+*/
+#define Pm_Message(status, data1, data2) \
+         ((((data2) << 16) & 0xFF0000) | \
+          (((data1) << 8) & 0xFF00) | \
+          ((status) & 0xFF))
+#define Pm_MessageStatus(msg) ((msg) & 0xFF)
+#define Pm_MessageData1(msg) (((msg) >> 8) & 0xFF)
+#define Pm_MessageData2(msg) (((msg) >> 16) & 0xFF)
+
+typedef int32_t PmMessage; /**< see PmEvent */
+/**
+   All midi data comes in the form of PmEvent structures. A sysex
+   message is encoded as a sequence of PmEvent structures, with each
+   structure carrying 4 bytes of the message, i.e. only the first
+   PmEvent carries the status byte.
+
+   Note that MIDI allows nested messages: the so-called "real-time" MIDI 
+   messages can be inserted into the MIDI byte stream at any location, 
+   including within a sysex message. MIDI real-time messages are one-byte
+   messages used mainly for timing (see the MIDI spec). PortMidi retains 
+   the order of non-real-time MIDI messages on both input and output, but 
+   it does not specify exactly how real-time messages are processed. This
+   is particulary problematic for MIDI input, because the input parser 
+   must either prepare to buffer an unlimited number of sysex message 
+   bytes or to buffer an unlimited number of real-time messages that 
+   arrive embedded in a long sysex message. To simplify things, the input
+   parser is allowed to pass real-time MIDI messages embedded within a 
+   sysex message, and it is up to the client to detect, process, and 
+   remove these messages as they arrive.
+
+   When receiving sysex messages, the sysex message is terminated
+   by either an EOX status byte (anywhere in the 4 byte messages) or
+   by a non-real-time status byte in the low order byte of the message.
+   If you get a non-real-time status byte but there was no EOX byte, it 
+   means the sysex message was somehow truncated. This is not
+   considered an error; e.g., a missing EOX can result from the user
+   disconnecting a MIDI cable during sysex transmission.
+
+   A real-time message can occur within a sysex message. A real-time 
+   message will always occupy a full PmEvent with the status byte in 
+   the low-order byte of the PmEvent message field. (This implies that
+   the byte-order of sysex bytes and real-time message bytes may not
+   be preserved -- for example, if a real-time message arrives after
+   3 bytes of a sysex message, the real-time message will be delivered
+   first. The first word of the sysex message will be delivered only
+   after the 4th byte arrives, filling the 4-byte PmEvent message field.
+   
+   The timestamp field is observed when the output port is opened with
+   a non-zero latency. A timestamp of zero means "use the current time",
+   which in turn means to deliver the message with a delay of
+   latency (the latency parameter used when opening the output port.)
+   Do not expect PortMidi to sort data according to timestamps -- 
+   messages should be sent in the correct order, and timestamps MUST 
+   be non-decreasing. See also "Example" for Pm_OpenOutput() above.
+
+   A sysex message will generally fill many PmEvent structures. On 
+   output to a PortMidiStream with non-zero latency, the first timestamp
+   on sysex message data will determine the time to begin sending the 
+   message. PortMidi implementations may ignore timestamps for the 
+   remainder of the sysex message. 
+   
+   On input, the timestamp ideally denotes the arrival time of the 
+   status byte of the message. The first timestamp on sysex message 
+   data will be valid. Subsequent timestamps may denote 
+   when message bytes were actually received, or they may be simply 
+   copies of the first timestamp.
+
+   Timestamps for nested messages: If a real-time message arrives in 
+   the middle of some other message, it is enqueued immediately with 
+   the timestamp corresponding to its arrival time. The interrupted 
+   non-real-time message or 4-byte packet of sysex data will be enqueued 
+   later. The timestamp of interrupted data will be equal to that of
+   the interrupting real-time message to insure that timestamps are
+   non-decreasing.
+ */
+typedef struct {
+    PmMessage      message;
+    PmTimestamp    timestamp;
+} PmEvent;
+
+/** 
+    @}
+*/
+/** \defgroup grp_io Reading and Writing Midi Messages
+    @{
+*/
+/**
+    Pm_Read() retrieves midi data into a buffer, and returns the number
+    of events read. Result is a non-negative number unless an error occurs, 
+    in which case a PmError value will be returned.
+
+    Buffer Overflow
+
+    The problem: if an input overflow occurs, data will be lost, ultimately 
+    because there is no flow control all the way back to the data source. 
+    When data is lost, the receiver should be notified and some sort of 
+    graceful recovery should take place, e.g. you shouldn't resume receiving 
+    in the middle of a long sysex message.
+
+    With a lock-free fifo, which is pretty much what we're stuck with to 
+    enable portability to the Mac, it's tricky for the producer and consumer 
+    to synchronously reset the buffer and resume normal operation.
+
+    Solution: the buffer managed by PortMidi will be flushed when an overflow
+    occurs. The consumer (Pm_Read()) gets an error message (pmBufferOverflow)
+    and ordinary processing resumes as soon as a new message arrives. The
+    remainder of a partial sysex message is not considered to be a "new
+    message" and will be flushed as well.
+
+*/
+PMEXPORT int Pm_Read( PortMidiStream *stream, PmEvent *buffer, int32_t length );
+
+/**
+    Pm_Poll() tests whether input is available, 
+    returning TRUE, FALSE, or an error value.
+*/
+PMEXPORT PmError Pm_Poll( PortMidiStream *stream);
+
+/** 
+    Pm_Write() writes midi data from a buffer. This may contain:
+        - short messages 
+    or 
+        - sysex messages that are converted into a sequence of PmEvent
+          structures, e.g. sending data from a file or forwarding them
+          from midi input.
+
+    Use Pm_WriteSysEx() to write a sysex message stored as a contiguous 
+    array of bytes.
+
+    Sysex data may contain embedded real-time messages.
+*/
+PMEXPORT PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, int32_t length );
+
+/**
+    Pm_WriteShort() writes a timestamped non-system-exclusive midi message.
+    Messages are delivered in order as received, and timestamps must be 
+    non-decreasing. (But timestamps are ignored if the stream was opened
+    with latency = 0.)
+*/
+PMEXPORT PmError Pm_WriteShort( PortMidiStream *stream, PmTimestamp when, int32_t msg);
+
+/**
+    Pm_WriteSysEx() writes a timestamped system-exclusive midi message.
+*/
+PMEXPORT PmError Pm_WriteSysEx( PortMidiStream *stream, PmTimestamp when, unsigned char *msg);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PORT_MIDI_H */
diff --git a/pd/portmidi/pm_csharp/README.txt b/pd/portmidi/pm_csharp/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..06a1ad4e39083ce05b949ad15f136c78d202cbda
--- /dev/null
+++ b/pd/portmidi/pm_csharp/README.txt
@@ -0,0 +1,20 @@
+This code was offered by Aaron Oxford as is. The pm_managed directory contains the code. If you develop a more complete C# wrapper for PortMidi, please consider contributing your code to the project. -RBD
+
+---- from Aaron Oxford ----
+
+I've attached the managed C++ project which I've inserted into my 2005 version of PortMIDI's VS solution.  I wouldn't think the functions I've implemented would have changed so it all should still work with the latest version of PM. Obviously you won't want to permanently embed this since it means the whole solution can only be built under VS2005, but it's easy for a VS2005 user to insert the project after the solution is converted or even just build it separately.
+
+Making the managed wrapper turned out to be dead easy in the end (it was more of a battle finding the correct build settings & SDK's and learning to configure VS than anything else). Anyone wanting to use something I've not implemented yet simply needs to add more stubs like this
+
+                int Pm_Initialize()
+                {
+                        ::Pm_Initialize();
+                        return 0;
+                }
+
+to the code. To call from C# it's just a matter of
+
+                ManagedPortMIDI mpm = new ManagedPortMIDI();
+                int err = mpm.Pm_Initialize();
+
+Anyway as the little code example above indicates, the support really is basic and more likely than not to break at the first hint of something unexpected. As I said, I'd be happy to contribute but I don't think there's much to contribute yet. :-)
diff --git a/pd/portmidi/pm_csharp/pm_managed/AssemblyInfo.cpp b/pd/portmidi/pm_csharp/pm_managed/AssemblyInfo.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..57874f89bbf97b755afb2e1c46db0c4993d16462
--- /dev/null
+++ b/pd/portmidi/pm_csharp/pm_managed/AssemblyInfo.cpp
@@ -0,0 +1,40 @@
+#include "stdafx.h"
+
+using namespace System;
+using namespace System::Reflection;
+using namespace System::Runtime::CompilerServices;
+using namespace System::Runtime::InteropServices;
+using namespace System::Security::Permissions;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly:AssemblyTitleAttribute("pm_managed")];
+[assembly:AssemblyDescriptionAttribute("")];
+[assembly:AssemblyConfigurationAttribute("")];
+[assembly:AssemblyCompanyAttribute("Innovative Computer Solutions")];
+[assembly:AssemblyProductAttribute("pm_managed")];
+[assembly:AssemblyCopyrightAttribute("Copyright (c) Innovative Computer Solutions 2006")];
+[assembly:AssemblyTrademarkAttribute("")];
+[assembly:AssemblyCultureAttribute("")];
+
+//
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the value or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly:AssemblyVersionAttribute("1.0.*")];
+
+[assembly:ComVisible(false)];
+
+[assembly:CLSCompliantAttribute(true)];
+
+[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)];
diff --git a/pd/portmidi/pm_csharp/pm_managed/ReadMe.txt b/pd/portmidi/pm_csharp/pm_managed/ReadMe.txt
new file mode 100755
index 0000000000000000000000000000000000000000..90317613aa90033bac4911aa2813874e1b7a0f1a
--- /dev/null
+++ b/pd/portmidi/pm_csharp/pm_managed/ReadMe.txt
@@ -0,0 +1,31 @@
+========================================================================
+    DYNAMIC LINK LIBRARY : pm_managed Project Overview
+========================================================================
+
+AppWizard has created this pm_managed DLL for you.  
+
+This file contains a summary of what you will find in each of the files that
+make up your pm_managed application.
+
+pm_managed.vcproj
+    This is the main project file for VC++ projects generated using an Application Wizard. 
+    It contains information about the version of Visual C++ that generated the file, and 
+    information about the platforms, configurations, and project features selected with the
+    Application Wizard.
+
+pm_managed.cpp
+    This is the main DLL source file.
+
+pm_managed.h
+    This file contains a class declaration.
+
+AssemblyInfo.cpp
+	Contains custom attributes for modifying assembly metadata.
+
+/////////////////////////////////////////////////////////////////////////////
+Other notes:
+
+AppWizard uses "TODO:" to indicate parts of the source code you
+should add to or customize.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/pd/portmidi/pm_csharp/pm_managed/Stdafx.cpp b/pd/portmidi/pm_csharp/pm_managed/Stdafx.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..6355f12e4f2350ed9db7ef106834adb1fcf9f333
--- /dev/null
+++ b/pd/portmidi/pm_csharp/pm_managed/Stdafx.cpp
@@ -0,0 +1,5 @@
+// stdafx.cpp : source file that includes just the standard includes
+// pm_managed.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
diff --git a/pd/portmidi/pm_csharp/pm_managed/Stdafx.h b/pd/portmidi/pm_csharp/pm_managed/Stdafx.h
new file mode 100755
index 0000000000000000000000000000000000000000..2e525d43f5bcbb903725e4f6d416a45be06131e7
--- /dev/null
+++ b/pd/portmidi/pm_csharp/pm_managed/Stdafx.h
@@ -0,0 +1,7 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently,
+// but are changed infrequently
+
+#pragma once
+
+
diff --git a/pd/portmidi/pm_csharp/pm_managed/app.ico b/pd/portmidi/pm_csharp/pm_managed/app.ico
new file mode 100755
index 0000000000000000000000000000000000000000..3a5525fd794f7a7c5c8e6187f470ea3af38cd2b6
Binary files /dev/null and b/pd/portmidi/pm_csharp/pm_managed/app.ico differ
diff --git a/pd/portmidi/pm_csharp/pm_managed/app.rc b/pd/portmidi/pm_csharp/pm_managed/app.rc
new file mode 100755
index 0000000000000000000000000000000000000000..bc5b261d9e35dd512eaed7fcc42b0653bfa41d20
--- /dev/null
+++ b/pd/portmidi/pm_csharp/pm_managed/app.rc
@@ -0,0 +1,63 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon placed first or with lowest ID value becomes application icon
+
+LANGUAGE 9, 3
+#pragma code_page(1252)
+1           ICON         "app.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE  
+BEGIN
+    "resource.h\0"
+    "\0"
+END
+
+2 TEXTINCLUDE  
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE  
+BEGIN
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/pd/portmidi/pm_csharp/pm_managed/pm_managed.cpp b/pd/portmidi/pm_csharp/pm_managed/pm_managed.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..d2a1440e34f296950d145e2839affdc3062cdef5
--- /dev/null
+++ b/pd/portmidi/pm_csharp/pm_managed/pm_managed.cpp
@@ -0,0 +1,6 @@
+// This is the main DLL file.
+
+#include "stdafx.h"
+
+#include "pm_managed.h"
+
diff --git a/pd/portmidi/pm_csharp/pm_managed/pm_managed.h b/pd/portmidi/pm_csharp/pm_managed/pm_managed.h
new file mode 100755
index 0000000000000000000000000000000000000000..5806703858b0365e72dfaa4326c2671ba99b77df
--- /dev/null
+++ b/pd/portmidi/pm_csharp/pm_managed/pm_managed.h
@@ -0,0 +1,53 @@
+// pm_managed.h
+
+#pragma once
+
+#include "portmidi.h"
+
+using namespace System;
+
+namespace pm_managed {
+
+
+	public ref class MpmDeviceInfo
+	{
+	public:
+		int structVersion; 
+		System::String^ interf; /* underlying MIDI API, e.g. MMSystem or DirectX */
+		System::String^ name;   /* device name, e.g. USB MidiSport 1x1 */
+		bool input; /* true iff input is available */
+		bool output; /* true iff output is available */
+		int opened; /* used by generic PortMidi code to do error checking on arguments */
+
+		MpmDeviceInfo(const PmDeviceInfo* info)
+		{
+			structVersion = info->structVersion;
+			input = (info->input != 0);
+			output = (info->output != 0);
+			opened = info->opened;
+
+			interf = gcnew System::String(info->interf);
+			name = gcnew System::String(info->name);
+		}
+	};
+
+	public ref class ManagedPortMIDI
+	{
+	public:
+		int Pm_Initialize()
+		{
+			::Pm_Initialize();
+			return 0;
+		}
+
+		int Pm_CountDevices()
+		{
+			return ::Pm_CountDevices();
+		}
+
+		MpmDeviceInfo^ Pm_GetDeviceInfo(int id)
+		{
+			return gcnew MpmDeviceInfo(::Pm_GetDeviceInfo(id));
+		}
+	};
+}
diff --git a/pd/portmidi/pm_csharp/pm_managed/pm_managed.vcproj b/pd/portmidi/pm_csharp/pm_managed/pm_managed.vcproj
new file mode 100755
index 0000000000000000000000000000000000000000..e60d58f4a162c3a6473fe112d4417eb57e9db190
--- /dev/null
+++ b/pd/portmidi/pm_csharp/pm_managed/pm_managed.vcproj
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="pm_managed"
+	ProjectGUID="{65AABD9A-F5E3-4A30-8BC3-9C732B5447CF}"
+	RootNamespace="pm_managed"
+	Keyword="ManagedCProj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)pm_managed\$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			ManagedExtensions="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../pm_common"
+				PreprocessorDefinitions="WIN32;_DEBUG"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="2"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="$(NoInherit) winmm.lib ..\pm_win\Debug\portmidi.lib ..\porttime\Debug\porttime.lib ..\pm_win\Debug\pm_dll.lib"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				AssemblyDebug="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)pm_managed\$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			ManagedExtensions="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				FavorSizeOrSpeed="1"
+				AdditionalIncludeDirectories="../pm_common"
+				PreprocessorDefinitions="WIN32;NDEBUG"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="2"
+				WarningLevel="3"
+				DebugInformationFormat="0"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="$(NoInherit) winmm.lib ..\pm_win\Release\portmidi.lib ..\porttime\Release\porttime.lib ..\pm_win\Release\pm_dll.lib"
+				LinkIncremental="1"
+				ManifestFile="$(OutDir)\pm_managed.dll.manifest"
+				GenerateDebugInformation="false"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+				OutputManifestFile="$(OutDir)\pm_managed.dll.manifest"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				CommandLine="rem mt.exe –manifest Release\pm_managed.dll.manifest -outputresource:Release\pm_managed.dll;2"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+		<AssemblyReference
+			RelativePath="System.dll"
+			AssemblyName="System, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
+		/>
+		<AssemblyReference
+			RelativePath="System.Data.dll"
+			AssemblyName="System.Data, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=x86"
+		/>
+		<AssemblyReference
+			RelativePath="System.XML.dll"
+			AssemblyName="System.Xml, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
+		/>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\AssemblyInfo.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\pm_managed.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\Stdafx.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\pm_managed.h"
+				>
+			</File>
+			<File
+				RelativePath=".\resource.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Stdafx.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+			<File
+				RelativePath=".\app.ico"
+				>
+			</File>
+			<File
+				RelativePath=".\app.rc"
+				>
+			</File>
+		</Filter>
+		<File
+			RelativePath=".\ReadMe.txt"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_csharp/pm_managed/resource.h b/pd/portmidi/pm_csharp/pm_managed/resource.h
new file mode 100755
index 0000000000000000000000000000000000000000..1f2251c2bdecd53055c446ad232048f7221cfaef
--- /dev/null
+++ b/pd/portmidi/pm_csharp/pm_managed/resource.h
@@ -0,0 +1,3 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by app.rc
diff --git a/pd/portmidi/pm_dylib/CMakeLists.txt b/pd/portmidi/pm_dylib/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f693dd6511a0dac90104b91ec7b8f5cb0c9a2ea3
--- /dev/null
+++ b/pd/portmidi/pm_dylib/CMakeLists.txt
@@ -0,0 +1,127 @@
+# pm_dylib
+
+# set the build directory for libraries to be in portmidi, not in 
+#    portmidi/pm_dylib
+if(APPLE OR WIN32)
+  # set the build directory for .dylib libraries
+  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+  # the "archive" output directory says where to put portmidi.lib, the
+  # static part of the lib/dll pair:
+  set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+
+  # the first time CMake configures, save off CMake's built-in flags
+  if(NOT DEFAULT_DEBUG_FLAGS)
+    set(DEFAULT_DEBUG_FLAGS ${CMAKE_C_FLAGS_DEBUG} CACHE 
+        STRING "CMake's default debug flags" FORCE)
+    set(DEFAULT_RELEASE_FLAGS ${CMAKE_C_FLAGS_RELEASE} CACHE 
+        STRING "CMake's default release flags" FORCE)
+  else(NOT DEFAULT_DEBUG_FLAGS)
+    message(STATUS "DEFAULT_DEBUG_FLAGS not nil: " ${DEFAULT_DEBUG_FLAGS})
+  endif(NOT DEFAULT_DEBUG_FLAGS)
+else(APPLE OR WIN32)
+  set(LINUX_FLAGS "-DPMALSA")
+endif(APPLE OR WIN32)
+
+macro(prepend_path RESULT PATH)
+  set(${RESULT})
+  foreach(FILE ${ARGN})
+    list(APPEND ${RESULT} "${PATH}${FILE}")
+  endforeach(FILE)
+endmacro(prepend_path)
+
+set(CMAKE_C_FLAGS_DEBUG 
+    "${DEFAULT_DEBUG_FLAGS} -DPM_CHECK_ERRORS=1 -DDEBUG ${LINUX_FLAGS}"
+    CACHE STRING "enable extra checks for debugging" FORCE)
+
+set(CMAKE_C_FLAGS_RELEASE "${DEFAULT_RELEASE_FLAGS} ${LINUX_FLAGS}"
+    CACHE STRING "flags for release version" FORCE)
+
+# first include the appropriate system-dependent file:
+if(UNIX)
+  # add the -g switch for Linux and Mac OS X (not used in Win32)
+  set (CMAKE_C_FLAGS_DEBUG "-g ${CMAKE_C_FLAGS_DEBUG}" 
+       CACHE STRING "enable extra checks for debugging" FORCE)
+  if(APPLE)
+    set(MACSRC pmmacosxcm pmmac readbinaryplist finddefault)
+    prepend_path(LIBSRC ../pm_mac/ ${MACSRC})
+    list(APPEND LIBSRC ../porttime/ptmacosx_mach)
+
+    include_directories(${CMAKE_OSX_SYSROOT}/Developer/Headers/FlatCarbon)
+    set(FRAMEWORK_PATH ${CMAKE_OSX_SYSROOT}/System/Library/Frameworks)
+    set(COREAUDIO_LIB "${FRAMEWORK_PATH}/CoreAudio.framework")
+    set(COREFOUNDATION_LIB "${FRAMEWORK_PATH}/CoreFoundation.framework")
+    set(COREMIDI_LIB "${FRAMEWORK_PATH}/CoreMIDI.framework")
+    set(CORESERVICES_LIB "${FRAMEWORK_PATH}/CoreServices.framework")
+    set(PM_NEEDED_LIBS ${COREAUDIO_LIB} ${COREFOUNDATION_LIB}
+                             ${COREMIDI_LIB} ${CORESERVICES_LIB}
+        CACHE INTERNAL "")
+
+    set(JAVAVM_LIB "${FRAMEWORK_PATH}/JavaVM.framework")
+    set(JAVA_INCLUDE_PATHS ${JAVAVM_LIB}/Headers)
+    set(INSTALL_NAME_DIR "/usr/local/lib")
+    message(STATUS "SYSROOT: " ${CMAKE_OSX_SYSROOT})
+  else(APPLE)
+    # LINUX settings...
+    include(FindJNI)
+    # message(STATUS "JAVA_JVM_LIB_PATH is " ${JAVA_JVM_LIB_PATH})
+    # message(STATUS "JAVA_INCLUDE_PATH is " ${JAVA_INCLUDE_PATH})
+    # note: should use JAVA_JVM_LIB_PATH, but it is not set properly
+    # note: user might need to set JAVA_INCLUDE_PATH manually
+    #
+    # this will probably break on BSD and other Unix systems; the fix
+    # depends on whether FindJNI can find Java or not. If yes, then
+    # we should try to rely on automatically set JAVA_INCLUDE_PATH and
+    # JAVA_INCLUDE_PATH2; if no, then we need to make both JAVA_INCLUDE_PATH
+    # and JAVA_INCLUDE_PATH2 set by user (will need clear documentation
+    # because JAVA_INCLUDE_PATH2 is pretty obscure)
+    set(JAVA_INCLUDE_PATH  ${JAVA_INCLUDE_PATH-UNKNOWN}
+        CACHE STRING "where to find Java SDK include directory")
+    set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH}/linux)
+    # libjvm.so is found relative to JAVA_INCLUDE_PATH:
+    set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../jre/lib/i386/client/libjvm.so)
+
+    set(LINUXSRC pmlinuxalsa pmlinux finddefault)
+    prepend_path(LIBSRC ../pm_linux/ ${LINUXSRC})
+    list(APPEND LIBSRC ../porttime/ptlinux)
+
+    set(PM_NEEDED_LIBS pthread asound)
+  endif(APPLE)
+else(UNIX)
+  if(WIN32)
+    # /MDd is multithread debug DLL, /MTd is multithread debug
+    # /MD is multithread DLL, /MT is multithread 
+    
+    include(FindJNI)
+    # note: should use JAVA_JVM_LIB_PATH, but it is not set properly
+    set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../lib/jvm.lib)
+
+    set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})
+    # message(STATUS "JAVA_INCLUDE_PATHS: " ${JAVA_INCLUDE_PATHS})
+
+    set(WINSRC pmwin pmwinmm)
+    prepend_path(LIBSRC ../pm_win/ ${WINSRC})
+    list(APPEND LIBSRC ../porttime/ptwinmm)
+    set(PM_NEEDED_LIBS winmm.lib)
+    # message(STATUS "JAVAVM_LIB: " ${JAVAVM_LIB})
+  endif(WIN32)
+endif(UNIX)
+set(JNI_EXTRA_LIBS ${PM_NEEDED_LIBS} ${JAVAVM_LIB})
+
+# this completes the list of library sources by adding shared code
+set(SHARED_FILES pmutil portmidi)
+prepend_path(SHARED_PATHS ../pm_common/ ${SHARED_FILES})
+list(APPEND LIBSRC ${SHARED_PATHS})
+
+add_library(portmidi-dynamic SHARED ${LIBSRC})
+set_target_properties(portmidi-dynamic PROPERTIES OUTPUT_NAME "portmidi")
+target_link_libraries(portmidi-dynamic ${PM_NEEDED_LIBS})
+
+# install the libraries (Linux and Mac OS X command line)
+if(UNIX)
+  INSTALL(TARGETS portmidi-dynamic
+    LIBRARY DESTINATION /usr/local/lib
+    ARCHIVE DESTINATION /usr/local/lib)
+  INSTALL(FILES ../pm_common/portmidi.h ../porttime/porttime.h
+    DESTINATION /usr/local/include)
+endif(UNIX)
diff --git a/pd/portmidi/pm_dylib/README.txt b/pd/portmidi/pm_dylib/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b7769700bfc02965ad2b918a63ec791a638f5f7a
--- /dev/null
+++ b/pd/portmidi/pm_dylib/README.txt
@@ -0,0 +1,11 @@
+pm_dylib
+
+The purpose of this directory is to provide a separate CMakeLists.txt 
+file for building a dynamic link library version of portmidi. This
+version (in Windows) is linked using the Multithreaded C Runtime DLL
+whereas the static library version in ../pm_common uses the (static)
+Multithreaded C Runtime. There's no good reason not to build both
+versions of portmidi in ../pm_common, but (the current) Cmake
+has the restriction that you must either share compiler flags across
+configurations (debug and release) or across targets (static and 
+dynamic). Here, we need individual settings for all combinations.
diff --git a/pd/portmidi/pm_dylib/portmidi-dynamic.vcproj b/pd/portmidi/pm_dylib/portmidi-dynamic.vcproj
new file mode 100644
index 0000000000000000000000000000000000000000..161b7d1f0cc2a1522301b039116461ce99a1bb0b
--- /dev/null
+++ b/pd/portmidi/pm_dylib/portmidi-dynamic.vcproj
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="portmidi-dynamic"
+	ProjectGUID="{7283FAD1-7415-4061-A19A-FF5C7BCE9306}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="portmidi-dynamic.dir\Debug"
+			ConfigurationType="2"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				BasicRuntimeChecks="3"
+				CompileAs="1"
+				DebugInformationFormat="3"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="0"
+				Optimization="0"
+				RuntimeLibrary="3"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;,portmidi_dynamic_EXPORTS"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../Debug/portmidi.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;,portmidi_dynamic_EXPORTS"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;,portmidi_dynamic_EXPORTS"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  winmm.lib "
+				OutputFile="..\Debug\portmidi.dll"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="..\Debug\portmidi.pdb"
+				GenerateDebugInformation="TRUE"
+				ImportLibrary="..\Debug\portmidi.lib"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="portmidi-dynamic.dir\Release"
+			ConfigurationType="2"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				CompileAs="1"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="2"
+				Optimization="2"
+				RuntimeLibrary="2"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;,portmidi_dynamic_EXPORTS"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../Release/portmidi.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;,portmidi_dynamic_EXPORTS"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;,portmidi_dynamic_EXPORTS"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  winmm.lib "
+				OutputFile="..\Release\portmidi.dll"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="..\Release\portmidi.pdb"
+				ImportLibrary="..\Release\portmidi.lib"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="">
+			<File
+				RelativePath="..\pm_win\pmwin.c">
+			</File>
+			<File
+				RelativePath="..\pm_win\pmwinmm.c">
+			</File>
+			<File
+				RelativePath="..\porttime\ptwinmm.c">
+			</File>
+			<File
+				RelativePath="..\pm_common\pmutil.c">
+			</File>
+			<File
+				RelativePath="..\pm_common\portmidi.c">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_java/CMakeLists.txt b/pd/portmidi/pm_java/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a3506202792293d5f38415e68e5e62cdbec34dc7
--- /dev/null
+++ b/pd/portmidi/pm_java/CMakeLists.txt
@@ -0,0 +1,47 @@
+# pm_java
+
+if(UNIX)
+  if(APPLE)
+    # java not dealt with in CMake -- see pm_mac/pm_mac.xcodeproj
+  else(APPLE)
+    # linux
+    set(JPORTMIDICLASS JPortMidi.class JPortMidiException.class
+    		       JPortMidiApi.class)
+    set(PMDEFAULTSCLASS PmDefaultsFrame.class PmDefaults.class)
+    prepend_path(JPORTMIDICLASS2 jportmidi/ ${JPORTMIDICLASS})
+    prepend_path(PMDEFAULTSCLASS2 pmdefaults/ ${PMDEFAULTSCLASS})
+    set(PMDEFAULTS_ALL_CLASSES ${JPORTMIDICLASS2} ${PMDEFAULTSCLASS2})
+    # message(STATUS "PMDEFAULTS_ALL_CLASSES is " ${PMDEFAULTS_ALL_CLASSES})
+    add_custom_command(OUTPUT pmdefaults/PmDefaultsFrame.class
+        COMMAND javac -classpath . pmdefaults/PmDefaultsFrame.java
+	MAIN_DEPENDENCY pmdefaults/PmDefaultsFrame.java
+	DEPENDS pmdefaults/PmDefaults.java
+	WORKING_DIRECTORY pm_java)
+    add_custom_command(OUTPUT pmdefaults/PmDefaults.class
+        COMMAND javac -classpath . pmdefaults/PmDefaults.java
+	MAIN_DEPENDENCY pmdefaults/PmDefaults.java
+	DEPENDS pmdefaults/PmDefaultsFrame.java
+	WORKING_DIRECTORY pm_java)
+    add_custom_command(OUTPUT ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pmdefaults.jar
+        COMMAND	cp pmdefaults/portmusic_logo.png .
+        COMMAND	jar cmf pmdefaults/manifest.txt pmdefaults.jar
+		pmdefaults/*.class portmusic_logo.png jportmidi/*.class
+  	COMMAND chmod +x pmdefaults/pmdefaults
+	COMMAND cp pmdefaults/pmdefaults ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
+	COMMAND mv pmdefaults.jar ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
+	COMMAND rm portmusic_logo.png
+	MAIN_DEPENDENCY pmdefaults/PmDefaults.class
+	DEPENDS ${PMDEFAULTS_ALL_CLASSES}
+	WORKING_DIRECTORY pm_java)
+    add_custom_target(pmdefaults_target ALL 
+        DEPENDS ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pmdefaults.jar)
+    # message(STATUS "add_custom_target: pmdefaults.jar")
+
+    # install the libraries (Linux only)
+    INSTALL(FILES ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pmdefaults.jar
+      DESTINATION /usr/share/java)
+    INSTALL(PROGRAMS ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pmdefaults
+      DESTINATION /usr/local/bin)
+  endif(APPLE)
+endif(UNIX)
+# In windows, use pm_java/make.bat
diff --git a/pd/portmidi/pm_java/JavaExe.exe b/pd/portmidi/pm_java/JavaExe.exe
new file mode 100644
index 0000000000000000000000000000000000000000..8886d2e8672f2b443657675e51c9be7a7248045d
Binary files /dev/null and b/pd/portmidi/pm_java/JavaExe.exe differ
diff --git a/pd/portmidi/pm_java/README.txt b/pd/portmidi/pm_java/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3f616b776c82d1da3b1b90637feed53c0a61cff1
--- /dev/null
+++ b/pd/portmidi/pm_java/README.txt
@@ -0,0 +1,48 @@
+README.txt
+Roger B. Dannenberg
+16 Jun 2009
+
+This directory was created to implement PmDefaults, a program to
+set default input and output devices for PortMidi applications.
+
+There are three main sub-projects here:
+  1) pmjni -- a JNI (Java Native Interface) to access PortMidi
+  2) jportmidi -- a Java class to access PortMidi (uses pmjni)
+  3) pmdefaults -- the PmDefaults application (uses jportmidi)
+
+For Mac OS X, you should build the PmDefaults application in Xcode.
+
+For Win32, an installer for PmDefaults is included in setup/.
+To build from sources, you should first build everything including 
+the portmidi dll (that will be used by the Java application) using 
+Visual C++ and a provided .sln file in the portmidi home directory. 
+Then, run make.bat in this directory. The subdirectory win32 will be 
+created with the application pmdefaults.exe. You can run this application 
+in the normal way. To move the application, you need to copy *everything* 
+in win32. To build setup/pmdefaults-setup.exe, I have used both
+Setup Generator from Gentee software and Inno Setup from jrsoftware.org.
+A script for Inno Setup is included in this directory, but since paths
+seem to be absolute, you will have to adjust the paths in the script
+before you use it. 
+
+---- implementation notes ----
+
+For windows, we use the free software JavaExe.exe. The copy here was
+downloaded from 
+
+http://software.techrepublic.com.com/abstract.aspx?kw=javaexe&docid=767485
+
+I found this page by visiting http://software.techrepublic.com.com and
+searching in the "Software" category for "JavaExe"
+
+JavaExe works by placing the JavaExe.exe file in the directory with the
+Java application jar file and then *renaming* JavaExe.exe to the name
+of the jar file, but keeping the .exe extension. (See make.bat for this 
+step.) Documentation for JavaExe can be obtained by downloading the
+whole program from the URL(s) above.
+
+
+
+
+
+
diff --git a/pd/portmidi/pm_java/UpdateRsrcJavaExe.exe b/pd/portmidi/pm_java/UpdateRsrcJavaExe.exe
new file mode 100644
index 0000000000000000000000000000000000000000..492ec1679ea1f51e36b41fef7a89f666cdc06c9a
Binary files /dev/null and b/pd/portmidi/pm_java/UpdateRsrcJavaExe.exe differ
diff --git a/pd/portmidi/pm_java/jportmidi/JPortMidi.java b/pd/portmidi/pm_java/jportmidi/JPortMidi.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd3cc2a1c3ad8b069fc4553fcc3ec569c8fe296b
--- /dev/null
+++ b/pd/portmidi/pm_java/jportmidi/JPortMidi.java
@@ -0,0 +1,539 @@
+package jportmidi;
+
+/* PortMidi is a general class intended for any Java program using
+   the PortMidi library. It encapsulates JPortMidiApi with a more
+   object-oriented interface. A single PortMidi object can manage
+   up to one input stream and one output stream.
+
+   This class is not safely callable from multiple threads. It
+   is the client's responsibility to periodically call the Poll
+   method which checks for midi input and handles it.
+*/
+
+import jportmidi.*;
+import jportmidi.JPortMidiApi.*;
+
+public class JPortMidi {
+
+    // timecode to send message immediately
+    public final int NOW = 0;
+
+    // midi codes
+    public final int MIDI_NOTE_OFF = 0x80;
+    public final int MIDI_NOTE_ON = 0x90;
+    public final int CTRL_ALL_OFF = 123;
+    public final int MIDI_PITCH_BEND = 0xE0;
+    public final int MIDI_CLOCK = 0xF8;
+    public final int MIDI_CONTROL = 0xB0;
+    public final int MIDI_PROGRAM = 0xC0;
+    public final int MIDI_START = 0xFA;
+    public final int MIDI_STOP = 0xFC;
+    public final int MIDI_POLY_TOUCH = 0xA0;
+    public final int MIDI_TOUCH = 0xD0;
+
+    // error code -- cannot refresh device list while stream is open:
+    public final int pmStreamOpen = -5000;
+    public final int pmOutputNotOpen = -4999;
+
+    // access to JPortMidiApi is through a single, global instance
+    private static JPortMidiApi pm;
+    // a reference count tracks how many objects have it open
+    private static int pmRefCount = 0;
+    private static int openCount = 0;
+
+    public int error; // user can check here for error codes
+    private PortMidiStream input;
+    private PortMidiStream output;
+    private PmEvent buffer;
+    protected int timestamp; // remember timestamp from incoming messages
+    protected boolean trace = false; // used to print midi msgs for debugging
+    
+
+    public JPortMidi() throws JPortMidiException {
+        if (pmRefCount == 0) {
+            pm = new JPortMidiApi();
+            pmRefCount++;
+            System.out.println("Calling Pm_Initialize");
+            checkError(pm.Pm_Initialize());
+            System.out.println("Called Pm_Initialize");
+        }
+        buffer = new PmEvent();
+    }
+    
+    public boolean getTrace() { return trace; }
+
+    // set the trace flag and return previous value
+    public boolean setTrace(boolean flag) {
+        boolean previous = trace;
+        trace = flag;
+        return previous;
+    }
+
+    // WARNING: you must not call this if any devices are open
+    public void refreshDeviceLists()
+            throws JPortMidiException 
+    {
+        if (openCount > 0) {
+            throw new JPortMidiException(pmStreamOpen,
+                    "RefreshDeviceLists called while stream is open");
+        }
+        checkError(pm.Pm_Terminate());
+        checkError(pm.Pm_Initialize());
+    }
+
+    // there is no control over when/whether this is called, but it seems
+    // to be a good idea to close things when this object is collected
+    public void finalize() {
+        if (input != null) {
+            error = pm.Pm_Close(input);
+        }
+        if (input != null) {
+            int rslt = pm.Pm_Close(output);
+            // we may lose an error code from closing output, but don't
+            // lose any real error from closing input...
+            if (error == pm.pmNoError) error = rslt;
+        }
+        pmRefCount--;
+        if (pmRefCount == 0) {
+            error = pm.Pm_Terminate();
+        }
+    }
+
+    int checkError(int err) throws JPortMidiException
+    {
+        // note that Pm_Read and Pm_Write return positive result values 
+        // which are not errors, so compare with >=
+        if (err >= pm.pmNoError) return err;
+        if (err == pm.pmHostError) {
+            throw new JPortMidiException(err, pm.Pm_GetHostErrorText());
+        } else {
+            throw new JPortMidiException(err, pm.Pm_GetErrorText(err));
+        }
+    }
+
+    // ******** ACCESS TO TIME ***********
+    
+    public void timeStart(int resolution) throws JPortMidiException {
+        checkError(pm.Pt_TimeStart(resolution));
+    }
+        
+    public void timeStop() throws JPortMidiException {
+        checkError(pm.Pt_TimeStop());
+    }
+        
+    public int timeGet() {
+        return pm.Pt_Time();
+    }
+        
+    public boolean timeStarted() {
+        return pm.Pt_TimeStarted();
+    }
+
+    // ******* QUERY DEVICE INFORMATION *********
+        
+    public int countDevices() throws JPortMidiException {
+        return checkError(pm.Pm_CountDevices());
+    }
+
+    public int getDefaultInputDeviceID()  throws JPortMidiException {
+        return checkError(pm.Pm_GetDefaultInputDeviceID());
+    }
+
+    public int getDefaultOutputDeviceID() throws JPortMidiException {
+        return checkError(pm.Pm_GetDefaultOutputDeviceID());
+    }
+
+    public String getDeviceInterf(int i) {
+        return pm.Pm_GetDeviceInterf(i);
+    }
+
+    public String getDeviceName(int i) {
+        return pm.Pm_GetDeviceName(i);
+    }
+
+    public boolean getDeviceInput(int i) {
+        return pm.Pm_GetDeviceInput(i);
+    }
+
+    public boolean getDeviceOutput(int i) {
+        return pm.Pm_GetDeviceOutput(i);
+    }
+
+    // ********** MIDI INTERFACE ************
+
+    public boolean isOpenInput() {
+        return input != null;
+    }
+
+    public void openInput(int inputDevice, int bufferSize) 
+            throws JPortMidiException 
+    {
+        openInput(inputDevice, "", bufferSize);
+    }
+
+    public void openInput(int inputDevice, String inputDriverInfo, int bufferSize) 
+            throws JPortMidiException
+    {
+        if (isOpenInput()) pm.Pm_Close(input);
+        else input = new PortMidiStream();
+        if (trace) {
+            System.out.println("openInput " + getDeviceName(inputDevice));
+        }
+        checkError(pm.Pm_OpenInput(input, inputDevice, 
+                                   inputDriverInfo, bufferSize));
+        // if no exception, then increase count of open streams
+        openCount++;
+    }
+
+    public boolean isOpenOutput() {
+        return output != null;
+    }
+
+    public void openOutput(int outputDevice, int bufferSize, int latency)
+            throws JPortMidiException 
+    {
+        openOutput(outputDevice, "", bufferSize, latency);
+    }
+
+    public void openOutput(int outputDevice, String outputDriverInfo,
+            int bufferSize, int latency) throws JPortMidiException {
+        if (isOpenOutput()) pm.Pm_Close(output);
+        else output = new PortMidiStream();
+        if (trace) {
+            System.out.println("openOutput " + getDeviceName(outputDevice));
+        }
+        checkError(pm.Pm_OpenOutput(output, outputDevice, outputDriverInfo, 
+                                    bufferSize, latency));
+        // if no exception, then increase count of open streams
+        openCount++;
+    }
+
+    public void setFilter(int filters) throws JPortMidiException {
+        if (input == null) return; // no effect if input not open
+        checkError(pm.Pm_SetFilter(input, filters));
+    }
+
+    public void setChannelMask(int mask) throws JPortMidiException {
+        if (input == null) return; // no effect if input not open
+        checkError(pm.Pm_SetChannelMask(input, mask));
+    }
+
+    public void abort() throws JPortMidiException {
+        if (output == null) return; // no effect if output not open
+        checkError(pm.Pm_Abort(output));
+    }
+
+    // In keeping with the idea that this class represents an input and output,
+    // there are separate Close methods for input and output streams, avoiding
+    // the need for clients to ever deal directly with a stream object
+    public void closeInput() throws JPortMidiException {
+        if (input == null) return; // no effect if input not open
+        checkError(pm.Pm_Close(input));
+        input = null;
+        openCount--;
+    }
+
+    public void closeOutput() throws JPortMidiException {
+        if (output == null) return; // no effect if output not open
+        checkError(pm.Pm_Close(output));
+        output = null;
+        openCount--;
+    }
+
+    // Poll should be called by client to process input messages (if any)
+    public void poll() throws JPortMidiException {
+        if (input == null) return; // does nothing until input is opened
+        while (true) {
+            int rslt = pm.Pm_Read(input, buffer);
+            checkError(rslt);
+            if (rslt == 0) return; // no more messages
+            handleMidiIn(buffer);
+        }
+    }    
+
+    public void writeShort(int when, int msg) throws JPortMidiException {
+        if (output == null) 
+            throw new JPortMidiException(pmOutputNotOpen, 
+                                         "Output stream not open");
+        if (trace) {
+            System.out.println("writeShort: " + Integer.toHexString(msg));
+        }
+        checkError(pm.Pm_WriteShort(output, when, msg));
+    }
+
+    public void writeSysEx(int when, byte msg[]) throws JPortMidiException {
+        if (output == null) 
+            throw new JPortMidiException(pmOutputNotOpen, 
+                                         "Output stream not open");
+        if (trace) {
+            System.out.print("writeSysEx: ");
+            for (int i = 0; i < msg.length; i++) {
+                System.out.print(Integer.toHexString(msg[i]));
+            }
+            System.out.print("\n");
+        }
+        checkError(pm.Pm_WriteSysEx(output, when, msg));
+    }
+    
+    public int midiChanMessage(int chan, int status, int data1, int data2) {
+        return (((data2 << 16) & 0xFF0000) |
+                ((data1 << 8) & 0xFF00) |
+                (status & 0xF0) |
+                (chan & 0xF));
+    }
+
+    public int midiMessage(int status, int data1, int data2) {
+        return ((((data2) << 16) & 0xFF0000) |
+                (((data1) << 8) & 0xFF00) |
+                ((status) & 0xFF));
+    }
+
+    public void midiAllOff(int channel) throws JPortMidiException {
+        midiAllOff(channel, NOW); 
+    }
+
+    public void midiAllOff(int chan, int when) throws JPortMidiException {
+        writeShort(when, midiChanMessage(chan, MIDI_CONTROL, CTRL_ALL_OFF, 0));
+    }
+        
+    public void midiPitchBend(int chan, int value) throws JPortMidiException {
+        midiPitchBend(chan, value, NOW);
+    }
+
+    public void midiPitchBend(int chan, int value, int when)
+            throws JPortMidiException {
+        writeShort(when, 
+                   midiChanMessage(chan, MIDI_PITCH_BEND, value, value >> 7));
+    }
+
+    public void midiClock() throws JPortMidiException {
+        midiClock(NOW);
+    }
+
+    public void midiClock(int when) throws JPortMidiException {
+        writeShort(when, midiMessage(MIDI_CLOCK, 0, 0));
+    }
+
+    public void midiControl(int chan, int control, int value)
+            throws JPortMidiException {
+        midiControl(chan, control, value, NOW);
+    }
+
+    public void midiControl(int chan, int control, int value, int when)
+            throws JPortMidiException {
+        writeShort(when, midiChanMessage(chan, MIDI_CONTROL, control, value));
+    }
+
+    public void midiNote(int chan, int pitch, int vel)
+            throws JPortMidiException {
+        midiNote(chan, pitch, vel, NOW);
+    }
+
+    public void midiNote(int chan, int pitch, int vel, int when)
+            throws JPortMidiException {
+        writeShort(when, midiChanMessage(chan, MIDI_NOTE_ON, pitch, vel));
+    }
+
+    public void midiProgram(int chan, int program)
+            throws JPortMidiException {
+        midiProgram(chan, program, NOW);
+    }
+
+    public void midiProgram(int chan, int program, int when)
+            throws JPortMidiException {
+        writeShort(when, midiChanMessage(chan, MIDI_PROGRAM, program, 0));
+    }
+
+    public void midiStart()
+            throws JPortMidiException {
+        midiStart(NOW);
+    }
+
+    public void midiStart(int when)
+            throws JPortMidiException {
+        writeShort(when, midiMessage(MIDI_START, 0, 0));
+    }
+
+    public void midiStop()
+            throws JPortMidiException {
+        midiStop(NOW);
+    }
+
+    public void midiStop(int when)
+            throws JPortMidiException {
+        writeShort(when, midiMessage(MIDI_STOP, 0, 0));
+    }
+
+    public void midiPolyTouch(int chan, int key, int value)
+            throws JPortMidiException {
+        midiPolyTouch(chan, key, value, NOW);
+    }
+
+    public void midiPolyTouch(int chan, int key, int value, int when)
+            throws JPortMidiException {
+        writeShort(when, midiChanMessage(chan, MIDI_POLY_TOUCH, key, value));
+    }
+
+    public void midiTouch(int chan, int value)
+            throws JPortMidiException {
+        midiTouch(chan, value, NOW);
+    }
+
+    public void midiTouch(int chan, int value, int when)
+            throws JPortMidiException {
+        writeShort(when, midiChanMessage(chan, MIDI_TOUCH, value, 0));
+    }
+
+    // ****** now we implement the message handlers ******
+
+    // an array for incoming sysex messages that can grow. 
+    // The downside is that after getting a message, we 
+
+    private byte sysexBuffer[] = null;
+    private int sysexBufferIndex = 0;
+
+    void sysexBufferReset() {
+        sysexBufferIndex = 0;
+        if (sysexBuffer == null) sysexBuffer = new byte[256];
+    }
+
+    void sysexBufferCheck() {
+        if (sysexBuffer.length < sysexBufferIndex + 4) {
+            byte bigger[] = new byte[sysexBuffer.length * 2];
+            for (int i = 0; i < sysexBufferIndex; i++) {
+                bigger[i] = sysexBuffer[i];
+            }
+            sysexBuffer = bigger;
+        }
+        // now we have space to write some bytes
+    }
+
+    // call this to insert Sysex and EOX status bytes
+    // call sysexBufferAppendBytes to insert anything else
+    void sysexBufferAppendStatus(byte status) {
+        sysexBuffer[sysexBufferIndex++] = status;
+    }
+
+    void sysexBufferAppendBytes(int msg, int len) {
+        for (int i = 0; i < len; i++) {
+            byte b = (byte) msg;
+            if ((msg & 0x80) != 0) {
+                if (b == 0xF7) { // end of sysex
+                    sysexBufferAppendStatus(b);
+                    sysex(sysexBuffer, sysexBufferIndex);
+                    return;
+                }
+                // recursively handle embedded real-time messages
+                PmEvent buffer = new PmEvent();
+                buffer.timestamp = timestamp;
+                buffer.message = b;
+                handleMidiIn(buffer);
+            } else {
+                sysexBuffer[sysexBufferIndex++] = b;
+            }
+            msg = msg >> 8;
+        }
+    }
+
+    void sysexBegin(int msg) {
+        sysexBufferReset(); // start from 0, we have at least 256 bytes now
+        sysexBufferAppendStatus((byte) (msg & 0xFF)); // first byte is special
+        sysexBufferAppendBytes(msg >> 8, 3); // process remaining bytes
+    }
+
+    public void handleMidiIn(PmEvent buffer)
+    {
+        if (trace) {
+            System.out.println("handleMidiIn: " + 
+                               Integer.toHexString(buffer.message));
+        }
+        // rather than pass timestamps to every handler, where typically 
+        // timestamps are ignored, just save the timestamp as a member
+        // variable where methods can access it if they want it
+        timestamp = buffer.timestamp;
+        int status = buffer.message & 0xFF;
+        if (status < 0x80) {
+            sysexBufferCheck(); // make enough space
+            sysexBufferAppendBytes(buffer.message, 4); // process 4 bytes
+            return;
+        }
+        int command = status & 0xF0;
+        int channel = status & 0x0F;
+        int data1 = (buffer.message >> 8) & 0xFF;
+        int data2 = (buffer.message >> 16) & 0xFF;
+        switch (command) {
+        case MIDI_NOTE_OFF:
+            noteOff(channel, data1, data2); break;
+        case MIDI_NOTE_ON:
+            if (data2 > 0) {
+                noteOn(channel, data1, data2); break;
+            } else {
+                noteOff(channel, data1);
+            }
+            break;
+        case MIDI_CONTROL:
+            control(channel, data1, data2); break;
+        case MIDI_POLY_TOUCH:
+            polyTouch(channel, data1, data2); break;
+        case MIDI_TOUCH:
+            touch(channel, data1); break;
+        case MIDI_PITCH_BEND:
+            pitchBend(channel, (data1 + (data2 << 7)) - 8192); break;
+        case MIDI_PROGRAM:
+            program(channel, data1); break;
+        case 0xF0:
+            switch (channel) {
+            case 0: sysexBegin(buffer.message); break;
+            case 1: mtcQuarterFrame(data1);
+            case 2: songPosition(data1 + (data2 << 7)); break;
+            case 3: songSelect(data1); break;
+            case 4: /* unused */ break;
+            case 5: /* unused */ break;
+            case 6: tuneRequest(); break;
+            case 7: sysexBufferAppendBytes(buffer.message, buffer.message); break;
+            case 8: clock(); break;
+            case 9: tick(); break;
+            case 0xA: clockStart(); break;
+            case 0xB: clockContinue(); break;
+            case 0xC: clockStop(); break;
+            case 0xD: /* unused */ break;
+            case 0xE: activeSense(); break;
+            case 0xF: reset(); break;
+            }
+        }
+    }
+          
+    // the value ranges from +8181 to -8192. The interpretation is 
+    // synthesizer dependent. Often the range is +/- one whole step
+    // (two semitones), but the range is usually adjustable within
+    // the synthesizer.
+    void pitchBend(int channel, int value) { return; }
+    void control(int channel, int control, int value) { return; }
+    void noteOn(int channel, int pitch, int velocity) { return; }
+    // you can handle velocity in note-off if you want, but the default
+    // is to drop the velocity and call the simpler NoteOff handler
+    void noteOff(int channel, int pitch, int velocity) { 
+        noteOff(channel, pitch);
+    }
+    // if the subclass wants to implement NoteOff with velocity, it
+    // should override the following to make sure all NoteOffs are handled
+    void noteOff(int channel, int pitch) { return; }
+    void program(int channel, int program) { return; }
+    // the byte array may be bigger than the message, length tells how
+    // many bytes in the array are part of the message
+    void sysex(byte[] msg, int length) { return; }
+    void polyTouch(int channel, int key, int value) { return; }
+    void touch(int channel, int value) { return; }
+    void mtcQuarterFrame(int value) { return; }
+    // the value is a 14-bit integer representing 16th notes
+    void songPosition(int value) { return; }
+    void songSelect(int value) { return; }
+    void tuneRequest() { return; }
+    void clock() { return; } // represents 1/24th of a quarter note
+    void tick() { return; } // represents 10ms
+    void clockStart() { return; }
+    void clockStop() { return; }
+    void clockContinue() { return; }
+    void activeSense() { return; }
+    void reset() { return; }
+}
diff --git a/pd/portmidi/pm_java/jportmidi/JPortMidiApi.java b/pd/portmidi/pm_java/jportmidi/JPortMidiApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..45dd9d98b288a5cb1bd34135b6e03f6dadb610c1
--- /dev/null
+++ b/pd/portmidi/pm_java/jportmidi/JPortMidiApi.java
@@ -0,0 +1,117 @@
+package jportmidi;
+
+public class JPortMidiApi {
+    public static class PortMidiStream {
+        private long address;
+    }
+    public static class PmEvent {
+        public int message;
+        public int timestamp;
+    }
+
+    // PmError bindings
+    public final int pmNoError = 0;
+    public final int pmNoData = 0;
+    public final int pmGotData = -1;
+    public final int pmHostError = -10000;
+    public final int pmInvalidDeviceId = -9999;
+    public final int pmInsufficientMemory = -9998;
+    public final int pmBufferTooSmall = -9997;
+    public final int pmBufferOverflow = -9996;
+    public final int pmBadPtr = -9995;
+    public final int pmBadData = -9994;
+    public final int pmInternalError = -9993;
+    public final int pmBufferMaxSize = -9992;
+    
+    static public native int Pm_Initialize();
+    static public native int Pm_Terminate();
+    static public native int Pm_HasHostError(PortMidiStream stream);
+    static public native String Pm_GetErrorText(int errnum);
+    static public native String Pm_GetHostErrorText();
+    final int pmNoDevice = -1;
+    static public native int Pm_CountDevices();
+    static public native int Pm_GetDefaultInputDeviceID();
+    static public native int Pm_GetDefaultOutputDeviceID();
+    static public native String Pm_GetDeviceInterf(int i);
+    static public native String Pm_GetDeviceName(int i);
+    static public native boolean Pm_GetDeviceInput(int i);
+    static public native boolean Pm_GetDeviceOutput(int i);
+    static public native int Pm_OpenInput(PortMidiStream stream,
+                                          int inputDevice, 
+                                          String inputDriverInfo, 
+                                          int bufferSize);
+    static public native int Pm_OpenOutput(PortMidiStream stream,
+                                           int outputDevice, 
+                                           String outnputDriverInfo, 
+                                           int bufferSize,
+                                           int latency);
+    final static public int PM_FILT_ACTIVE = (1 << 0x0E);
+    final static public int PM_FILT_SYSEX = (1 << 0x00);
+    final static public int PM_FILT_CLOCK = (1 << 0x08);
+    final static public int PM_FILT_PLAY = 
+            (1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B);
+    final static public int PM_FILT_TICK = (1 << 0x09);
+    final static public int PM_FILT_FD = (1 << 0x0D);
+    final static public int PM_FILT_UNDEFINED = PM_FILT_FD;
+    final static public int PM_FILT_RESET = (1 << 0x0F);
+    final static public int PM_FILT_REALTIME =
+            PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_CLOCK;
+    final static public int PM_FILT_NOTE = (1 << 0x19) | (1 << 0x18);
+    final static public int PM_FILT_CHANNEL_AFTERTOUCH = (1 << 0x1D);
+    final static public int PM_FILT_POLY_AFTERTOUCH = (1 << 0x1A);
+    final static public int PM_FILT_AFTERTOUCH = 
+            (PM_FILT_CHANNEL_AFTERTOUCH | PM_FILT_POLY_AFTERTOUCH);
+    final static public int PM_FILT_PROGRAM = (1 << 0x1C);
+    final static public int PM_FILT_CONTROL = (1 << 0x1B);
+    final static public int PM_FILT_PITCHBEND = (1 << 0x1E);
+    final static public int PM_FILT_MTC = (1 << 0x01);
+    final static public int PM_FILT_SONG_POSITION = (1 << 0x02);
+    final static public int PM_FILT_SONG_SELECT = (1 << 0x03);
+    final static public int PM_FILT_TUNE = (1 << 0x06);
+    final static public int PM_FILT_SYSTEMCOMMON =
+        (PM_FILT_MTC | PM_FILT_SONG_POSITION | 
+         PM_FILT_SONG_SELECT | PM_FILT_TUNE);
+    static public native int Pm_SetFilter(PortMidiStream stream, int filters);
+    static public int Pm_Channel(int channel) { return 1 << channel; }
+    final static public native int Pm_SetChannelMask(PortMidiStream stream, 
+                                                     int mask);
+    final static public native int Pm_Abort(PortMidiStream stream);
+    final static public native int Pm_Close(PortMidiStream stream);
+    static public int Pm_Message(int status, int data1, int data2) {
+        return (((data2 << 16) & 0xFF0000) |
+                ((data1 << 8) & 0xFF00) |
+                (status & 0xFF));
+    }
+    static public int Pm_MessageStatus(int msg) {
+        return msg & 0xFF;
+    }
+    static public int Pm_MessageData1(int msg) {
+        return (msg >> 8) & 0xFF;
+    }
+    static public int Pm_MessageData2(int msg) {
+        return (msg >> 16) & 0xFF;
+    }
+    // only supports reading one buffer at a time
+    static public native int Pm_Read(PortMidiStream stream, PmEvent buffer);
+    static public native int Pm_Poll(PortMidiStream stream);
+    // only supports writing one buffer at a time
+    static public native int Pm_Write(PortMidiStream stream, PmEvent buffer);
+    static public native int Pm_WriteShort(PortMidiStream stream, 
+                                           int when, int msg);
+    static public native int Pm_WriteSysEx(PortMidiStream stream, 
+                                           int when, byte msg[]);
+    
+    public final int ptNoError = 0;
+    public final int ptAlreadyStarted = -10000;
+    public final int ptAlreadyStopped = -9999;
+    public final int PtInsufficientMemory = -9998;
+    static public native int Pt_TimeStart(int resolution);
+    static public native int Pt_TimeStop();
+    static public native int Pt_Time();
+    static public native boolean Pt_TimeStarted();
+    static {
+        System.out.println("Loading pmjni");
+        System.loadLibrary("pmjni");
+        System.out.println("done loading pmjni");
+    }
+}
diff --git a/pd/portmidi/pm_java/jportmidi/JPortMidiException.java b/pd/portmidi/pm_java/jportmidi/JPortMidiException.java
new file mode 100644
index 0000000000000000000000000000000000000000..9be8aaf6a7555b5b0f43980dc0d56bed05ff8c77
--- /dev/null
+++ b/pd/portmidi/pm_java/jportmidi/JPortMidiException.java
@@ -0,0 +1,12 @@
+// JPortMidiException -- thrown by JPortMidi methods
+
+package jportmidi;
+
+public class JPortMidiException extends Exception {
+    public int error = 0;
+    public JPortMidiException(int err, String msg) {
+        super(msg);
+        error = err;
+    }
+}
+
diff --git a/pd/portmidi/pm_java/mac-make.sh b/pd/portmidi/pm_java/mac-make.sh
new file mode 100644
index 0000000000000000000000000000000000000000..e5e9592b0a0331b52280b7a70c0253db09a54038
--- /dev/null
+++ b/pd/portmidi/pm_java/mac-make.sh
@@ -0,0 +1,26 @@
+# script to build a jar file to run PmDefaults from the command line on OS X
+# (This is for debugging. Normally, you would use XCode to build PmDefaults.app.)
+
+# Compile the java Portidi interface classes.
+javac jportmidi/*.java
+
+# Compile the pmdefaults application.
+javac -classpath . pmdefaults/*.java
+
+# Temporarily copy the portmusic_logo.png file here to add to the jar file.
+cp pmdefaults/portmusic_logo.png . 
+
+# Create a directory to hold the distribution.
+mkdir mac-osx
+
+# Copy the interface DLL to the distribution directory.
+cp ../Release/libpmjni.dylib mac-osx
+
+# Create a java archive (jar) file of the distribution.
+jar cmf pmdefaults/manifest.txt mac-osx/pmdefaults.jar pmdefaults/*.class portmusic_logo.png jportmidi/*.class
+
+# Clean up the temporary image file now that it is in the jar file.
+rm portmusic_logo.png
+
+echo "You now have a jar file in mac-osx"
+
diff --git a/pd/portmidi/pm_java/make.bat b/pd/portmidi/pm_java/make.bat
new file mode 100644
index 0000000000000000000000000000000000000000..b614e3f212851462fd88743072017bbac5ac2497
--- /dev/null
+++ b/pd/portmidi/pm_java/make.bat
@@ -0,0 +1,47 @@
+@echo off
+
+rem Compile the java PortMidi interface classes.
+javac jportmidi/*.java
+
+rem Compile the pmdefaults application.
+javac -classpath . pmdefaults/*.java
+
+rem Temporarily copy the portmusic_logo.png file here to add to the jar file.
+copy pmdefaults\portmusic_logo.png . > nul
+
+rem Create a directory to hold the distribution.
+mkdir win32
+
+rem Attempt to copy the interface DLL to the distribution directory.
+
+if exist "..\release\pmjni.dll"  goto have-dll
+
+echo "ERROR: pmjni.dll not found!"
+exit /b 1
+
+:have-dll
+copy "..\release\pmjni.dll" win32\pmjni.dll > nul
+
+rem Create a java archive (jar) file of the distribution.
+jar cmf pmdefaults\manifest.txt win32\pmdefaults.jar pmdefaults\*.class portmusic_logo.png jportmidi\*.class
+
+rem Clean up the temporary image file now that it is in the jar file.
+del portmusic_logo.png
+
+rem Copy the java execution code obtained from
+rem http://devwizard.free.fr/html/en/JavaExe.html to the distribution
+rem directory.  The copy also renames the file to our desired executable
+rem name.
+copy JavaExe.exe win32\pmdefaults.exe > nul
+
+rem Integrate the icon into the executable using UpdateRsrcJavaExe from
+rem http://devwizard.free.fr
+UpdateRsrcJavaExe -run -exe=win32\pmdefaults.exe -ico=pmdefaults\pmdefaults.ico
+
+rem Copy the 32-bit windows read me file to the distribution directory.
+copy pmdefaults\readme-win32.txt win32\README.txt > nul
+
+rem Copy the license file to the distribution directory.
+copy pmdefaults\pmdefaults-license.txt win32\license.txt > nul
+
+echo "You can run pmdefaults.exe in win32"
diff --git a/pd/portmidi/pm_java/pmdefaults-setup-script.iss b/pd/portmidi/pm_java/pmdefaults-setup-script.iss
new file mode 100644
index 0000000000000000000000000000000000000000..44622ba6ad7f663df841084dab55ba1eef1f611c
--- /dev/null
+++ b/pd/portmidi/pm_java/pmdefaults-setup-script.iss
@@ -0,0 +1,44 @@
+; Script generated by the Inno Setup Script Wizard.
+; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
+
+[Setup]
+; NOTE: The value of AppId uniquely identifies this application.
+; Do not use the same AppId value in installers for other applications.
+; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
+AppId={{5094958B-3CD7-4780-A883-69C9E5B95AEF}
+AppName=PmDefaults
+AppVerName=PmDefaults
+AppPublisher=Roger Dannenberg - Carnegie Mellon University
+AppPublisherURL=http://portmedia.sourceforge.net/
+AppSupportURL=http://portmedia.sourceforge.net/
+AppUpdatesURL=http://portmedia.sourceforge.net/
+DefaultDirName={pf}\PmDefaults
+DefaultGroupName=PmDefaults
+LicenseFile=C:\Users\rbd\portmedia\portmidi\pm_java\win32\license.txt
+OutputBaseFilename=setup
+SetupIconFile=C:\Users\rbd\portmedia\portmidi\pm_java\pmdefaults\pmdefaults.ico
+Compression=lzma
+SolidCompression=yes
+
+[Languages]
+Name: "english"; MessagesFile: "compiler:Default.isl"
+
+[Tasks]
+Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
+Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
+
+[Files]
+Source: "C:\Users\rbd\portmedia\portmidi\pm_java\win32\pmdefaults.exe"; DestDir: "{app}"; Flags: ignoreversion
+Source: "C:\Users\rbd\portmedia\portmidi\pm_java\win32\pmdefaults.jar"; DestDir: "{app}"; Flags: ignoreversion
+Source: "C:\Users\rbd\portmedia\portmidi\pm_java\win32\pmjni.dll"; DestDir: "{app}"; Flags: ignoreversion
+Source: "C:\Users\rbd\portmedia\portmidi\pm_java\win32\license.txt"; DestDir: "{app}"; Flags: ignoreversion
+; NOTE: Don't use "Flags: ignoreversion" on any shared system files
+
+[Icons]
+Name: "{group}\PmDefaults"; Filename: "{app}\pmdefaults.exe"
+Name: "{commondesktop}\PmDefaults"; Filename: "{app}\pmdefaults.exe"; Tasks: desktopicon
+Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\PmDefaults"; Filename: "{app}\pmdefaults.exe"; Tasks: quicklaunchicon
+
+[Run]
+Filename: "{app}\pmdefaults.exe"; Description: "{cm:LaunchProgram,PmDefaults}"; Flags: nowait postinstall skipifsilent
+
diff --git a/pd/portmidi/pm_java/pmdefaults/PmDefaults.java b/pd/portmidi/pm_java/pmdefaults/PmDefaults.java
new file mode 100644
index 0000000000000000000000000000000000000000..20708fc9b66e18d2de9baef7a04c8cbd9027b151
--- /dev/null
+++ b/pd/portmidi/pm_java/pmdefaults/PmDefaults.java
@@ -0,0 +1,11 @@
+// PmDefaults -- a small application to set PortMIDI default input/output
+
+package pmdefaults;
+
+public class PmDefaults {
+    public static void main(String[] args) {
+        System.out.println("starting main");
+        new PmDefaultsFrame("PortMIDI Setup");
+    }
+}
+
diff --git a/pd/portmidi/pm_java/pmdefaults/PmDefaultsFrame.java b/pd/portmidi/pm_java/pmdefaults/PmDefaultsFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..b38af1b0f706a2479bad5e72519917e148490013
--- /dev/null
+++ b/pd/portmidi/pm_java/pmdefaults/PmDefaultsFrame.java
@@ -0,0 +1,428 @@
+// PmDefaults -- a small application to set PortMIDI default input/output
+
+/* Implementation notes:
+
+This program uses PortMidi to enumerate input and output devices and also
+to send output messages to test output devices and 
+to receive input messages to test input devices.
+
+*/
+
+package pmdefaults;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.lang.Math.*;
+import jportmidi.*;
+import jportmidi.JPortMidiApi.*;
+import java.util.ArrayList;
+import java.util.prefs.*;
+import java.net.*;
+
+public class PmDefaultsFrame extends JFrame 
+        implements ActionListener, ComponentListener {
+
+    // This class extends JPortMidi in order to override midi input handling
+    // In this case, midi input simply blinks the activity light
+    public class JPM extends JPortMidi {
+        ActivityLight light;
+        PmDefaultsFrame frame;
+        int lightTime;
+        boolean lightState;
+        int now; // current time in ms
+        final int HALF_BLINK_PERIOD = 250; // ms
+
+        public JPM(ActivityLight al, PmDefaultsFrame df) 
+                throws JPortMidiException {
+            light = al;
+            frame = df;
+            lightTime = 0;
+            lightState = false; // meaning "off"
+            now = 0;
+        }
+        
+        public void poll(int ms) throws JPortMidiException {
+            // blink the light. lightState is initially false (off).
+            // to blink the light, set lightState to true and lightTime
+            // to now + 0.25s; turn on light
+            // now > ligntTime && lightState => set lightTime = now + 0.25s;
+            //                                  set lightState = false
+            //                                  turn off light
+            // light can be blinked again when now > lightTime && !lightState
+            now = ms;
+            if (now > lightTime && lightState) {
+                lightTime = now + HALF_BLINK_PERIOD;
+                lightState = false;
+                light.setState(false);
+            }
+            super.poll();
+        }
+
+        public void handleMidiIn(PmEvent buffer) {
+            System.out.println("midi in: now " + now + 
+                               " lightTime " + lightTime +
+                               " lightState " + lightState);
+            if (now > lightTime && !lightState) {
+                lightState = true;
+                lightTime = now + HALF_BLINK_PERIOD;
+                light.setState(true);
+            }
+        }
+    }
+
+    public class ActivityLight extends JPanel {
+        Color color;
+        final Color OFF_COLOR = Color.BLACK;
+        final Color ON_COLOR = Color.GREEN;
+
+        ActivityLight() {
+            super();
+            Dimension size = new Dimension(50, 25);
+            setMaximumSize(size);
+            setPreferredSize(size);
+            setMinimumSize(size);
+            color = OFF_COLOR;
+            System.out.println("ActivityLight " + getSize());
+        }
+
+        public void setState(boolean on) {
+            color = (on ? ON_COLOR : OFF_COLOR);
+            repaint();
+        }
+
+        public void paintComponent(Graphics g) {
+            super.paintComponent(g); // paint background
+            g.setColor(color);
+            int x = (getWidth() / 2) - 5;
+            int y = (getHeight() / 2) - 5;
+            g.fillOval(x, y, 10, 10);
+            g.setColor(OFF_COLOR);
+            g.drawOval(x, y, 10, 10);
+        }
+    }
+
+    private JLabel inputLabel;
+    private JComboBox inputSelection;
+    // inputIds maps from the index of an item in inputSelection to the
+    // device ID. Used to open the selected device.
+    private ArrayList<Integer> inputIds;
+    private ActivityLight inputActivity;
+    private JLabel outputLabel;
+    private JComboBox outputSelection;
+    // analogous to inputIds, outputIds maps selection index to device ID
+    private ArrayList<Integer> outputIds;
+    private JButton testButton;
+    private JButton refreshButton;
+    private JButton updateButton;
+    private JButton closeButton;
+    private JLabel logo;
+
+    private JPM jpm;
+    private Timer timer;
+
+    public void componentResized(ComponentEvent e) {
+        System.out.println(e);
+        if (e.getComponent() == this) {
+            Insets insets = getInsets();
+            Dimension dim = getSize();
+            layoutComponents(dim.width - insets.left - insets.right,
+                             dim.height - insets.top - insets.bottom);
+        }
+    }
+    public void componentMoved(ComponentEvent e) {
+        System.out.println(e);
+    }
+    public void componentHidden(ComponentEvent e) {
+        System.out.println(e);
+    }
+    public void componentShown(ComponentEvent e) {
+        System.out.println(e);
+    }
+
+    
+    PmDefaultsFrame(String title) {
+        super(title);
+        initComponents();
+        System.out.println("initComponents returned\n");
+        pack(); // necessary before calling getInsets();
+        // initially, only width matters to layout:
+        layoutComponents(550, 300);
+        System.out.println("after layout, pref " + getPreferredSize());
+        // now, based on layout-computed preferredSize, set the Frame size
+        Insets insets = getInsets();
+        Dimension dim = getPreferredSize();
+        dim.width += (insets.left + insets.right);
+        dim.height += (insets.top + insets.bottom);
+        setSize(dim);
+        System.out.println("size" + getPreferredSize());
+        addComponentListener(this);
+
+        timer = new Timer(50 /* ms */, this);
+        timer.addActionListener(this);
+        try {
+            jpm = new JPM(inputActivity, this);
+            jpm.setTrace(true);
+            loadDeviceChoices();
+            timer.start(); // don't start timer if there's an error
+        } catch(JPortMidiException e) {
+            System.out.println(e);
+        }
+    }
+
+    void openInputSelection() {
+        int id = inputSelection.getSelectedIndex();
+        if (id < 0) return; // nothing selected
+        id = (Integer) (inputIds.get(id)); // map to device ID
+        // openInput will close any previously open input stream
+        try {
+            jpm.openInput(id, 100); // buffer size hopes to avoid overflow
+        } catch(JPortMidiException e) {
+            System.out.println(e);
+        }
+    }
+
+    // make a string to put into preferences describing this device
+    String makePrefName(int id) {
+        String name = jpm.getDeviceName(id);
+        String interf = jpm.getDeviceInterf(id);
+        // the syntax requires comma-space separator (see portmidi.h)
+        return interf + ", " + name;
+    }
+
+
+    public void savePreferences() {
+        Preferences prefs = Preferences.userRoot().node("/PortMidi");
+        int id = outputSelection.getSelectedIndex();
+        if (id >= 0) {
+            String prefName = makePrefName(outputIds.get(id));
+            System.out.println("output pref: " + prefName);
+            prefs.put("PM_RECOMMENDED_OUTPUT_DEVICE", prefName);
+        }
+        id = inputSelection.getSelectedIndex();
+        if (id >= 0) {
+            String prefName = makePrefName(inputIds.get(id));
+            System.out.println("input pref: " + prefName);
+            prefs.put("PM_RECOMMENDED_INPUT_DEVICE", prefName);
+        }
+        try {
+            prefs.flush();
+        } catch(BackingStoreException e) {
+            System.out.println(e);
+        }
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        Object source = e.getSource();
+        try {
+            if (source == timer) {
+                jpm.poll(jpm.timeGet());
+            } else if (source == refreshButton) {
+                if (jpm.isOpenInput()) jpm.closeInput();
+                if (jpm.isOpenOutput()) jpm.closeOutput();
+                jpm.refreshDeviceLists();
+                loadDeviceChoices();
+            } else if (source == updateButton) {
+                savePreferences();
+            } else if (source == closeButton) {
+                if (jpm.isOpenInput()) jpm.closeInput();
+                if (jpm.isOpenOutput()) jpm.closeOutput();
+            } else if (source == testButton) {
+                sendTestMessages();
+            } else if (source == inputSelection) {
+                // close previous selection and open new one
+                openInputSelection();
+            } else if (source == outputSelection) {
+                jpm.closeOutput(); // remains closed until Test button reopens
+            }
+        } catch(JPortMidiException ex) {
+            System.out.println(ex);
+        }
+    };
+
+    private void layoutComponents(int width, int height) {
+        // I tried to do this with various layout managers, but failed
+        // It seems pretty straightforward to just compute locations and
+        // sizes.
+
+        int gap = 2; // pixel separation between components
+        int indent = 20;
+        int y = gap;
+
+        // inputLabel goes in upper left
+        inputLabel.setLocation(0, y);
+        inputLabel.setSize(inputLabel.getPreferredSize());
+
+        // inputSelection goes below and indented, width based on panel
+        y += inputLabel.getHeight() + gap;
+        inputSelection.setLocation(indent, y);
+        // size of inputSelection must leave room at right for inputButton
+        // (in fact, inputActivity goes there, but we'll make inputSelection
+        // and outputSelection the same size, based on leaving room for
+        // testButton, which is larger than inputActivity.)
+        Dimension dim = inputSelection.getPreferredSize();
+        Dimension dimButton = testButton.getPreferredSize();
+        // make button and selection the same height so they align
+        dim.height = dimButton.height = Math.max(dim.height, dimButton.height);
+        // make selection width as wide as possible
+        dim.width = width - indent - dimButton.width - gap;
+        inputSelection.setSize(dim);
+
+        // inputActivity goes to the right of inputSelection
+        inputActivity.setLocation(indent + dim.width + gap, y);
+        // square size to match the height of inputSelection
+        inputActivity.setSize(dim.height, dim.height);
+
+        // outputLabel goes below
+        y += dim.height + gap;
+        outputLabel.setLocation(0, y);
+        outputLabel.setSize(outputLabel.getPreferredSize());
+       
+        // outputSelection is like inputSelection
+        y += outputLabel.getHeight() + gap;
+        outputSelection.setLocation(indent, y);
+        outputSelection.setSize(dim);
+
+        // testButton is like inputActivity
+        testButton.setLocation(indent + dim.width + gap, y);
+        testButton.setSize(dimButton);
+        System.out.println("button " + dimButton + " selection " + dim);
+
+        // refreshButton is below
+        y += dim.height + gap;
+        dim = refreshButton.getPreferredSize();
+        refreshButton.setLocation(indent, y);
+        refreshButton.setSize(dim);
+
+        // updateButton to right of refreshButton
+        int x = indent + dim.width + gap;
+        updateButton.setLocation(x, y);
+        dim = updateButton.getPreferredSize();
+        updateButton.setSize(dim);
+
+        // closeButton to right of updateButton
+        x += dim.width + gap;
+        closeButton.setLocation(x, y);
+        dim = closeButton.getPreferredSize();
+        closeButton.setSize(dim);
+
+        // place logo centered at bottom
+        y += dim.height + gap;
+        logo.setLocation((width - logo.getWidth()) / 2, 
+                         height - gap - logo.getHeight());
+
+        // set overall size
+        y += logo.getHeight() + gap;
+        System.out.println("computed best size " + width + ", " + y);
+        setPreferredSize(new Dimension(width, y));
+    }
+
+    private void initComponents() {
+        Container wholePanel = getContentPane();
+        wholePanel.setLayout(null);
+        setLayout(null);
+
+        inputLabel = new JLabel();
+        inputLabel.setText("Default Input");
+        wholePanel.add(inputLabel);
+
+        inputSelection = new JComboBox();
+        inputSelection.addActionListener(this);
+        inputSelection.setLocation(20, 30);
+        inputSelection.setSize(inputSelection.getPreferredSize());
+        System.out.println("Adding inputSelection to panel");
+        wholePanel.add(inputSelection);
+        inputIds = new ArrayList<Integer>();
+
+        inputActivity = new ActivityLight();
+        wholePanel.add(inputActivity);
+
+        outputLabel = new JLabel();
+        outputLabel.setText("Default Output");
+        wholePanel.add(outputLabel);
+
+        outputSelection = new JComboBox();
+        outputSelection.addActionListener(this);
+        wholePanel.add(outputSelection);
+        testButton = new JButton();
+        testButton.setText("Test");
+        testButton.addActionListener(this);
+        wholePanel.add(testButton);
+        outputIds = new ArrayList<Integer>();
+
+        refreshButton = new JButton();
+        refreshButton.setText("Refresh Device Lists");
+        System.out.println("refresh " + refreshButton.getPreferredSize());
+        System.out.println(getLayout());
+        refreshButton.addActionListener(this);
+        wholePanel.add(refreshButton);
+
+        updateButton = new JButton();
+        updateButton.setText("Update Preferences");
+        updateButton.setSize(refreshButton.getPreferredSize());
+        updateButton.addActionListener(this);
+        wholePanel.add(updateButton);
+
+        closeButton = new JButton();
+        closeButton.setText("Close/Release Ports");
+        closeButton.setSize(refreshButton.getPreferredSize());
+        closeButton.addActionListener(this);
+        wholePanel.add(closeButton);
+
+	// load the logo from the jar file (on Linux and Windows)
+	ClassLoader cldr = this.getClass().getClassLoader();
+        ImageIcon icon;
+        URL logoURL = cldr.getResource("portmusic_logo.png");
+        if (logoURL == null) {
+            // on Mac, load from bundle
+            icon = new ImageIcon("portmusic_logo.png");
+        } else {
+            icon = new ImageIcon(logoURL);
+        }
+        logo = new JLabel(icon);
+        logo.setSize(logo.getPreferredSize());
+        wholePanel.add(logo);
+
+        setVisible(true);
+        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+    }
+
+    void loadDeviceChoices() throws JPortMidiException {
+        // initialize and load combo boxes with device descriptions
+        int n = jpm.countDevices();
+        inputSelection.removeAllItems();
+        inputIds.clear();
+        outputSelection.removeAllItems();
+        outputIds.clear();
+        for (int i = 0; i < n; i++) {
+            String interf = jpm.getDeviceInterf(i);
+            String name = jpm.getDeviceName(i);
+	    System.out.println("name " + name);
+            String selection = name + " [" + interf + "]";
+            if (jpm.getDeviceInput(i)) {
+                inputIds.add(i);
+                inputSelection.addItem(selection);
+            } else {
+                outputIds.add(i);
+                outputSelection.addItem(selection);
+            }
+        }
+    }
+
+    void sendTestMessages() {
+        try {
+            if (!jpm.isOpenOutput()) {
+                int id = outputSelection.getSelectedIndex();
+                if (id < 0) return; // nothing selected
+                id = (Integer) (outputIds.get(id));
+                System.out.println("calling openOutput");
+                jpm.openOutput(id, 10, 10);
+            }
+            jpm.midiNote(0, 67, 100); // send an A (440)
+            jpm.midiNote(0, 67, 0, jpm.timeGet() + 500);
+        } catch(JPortMidiException e) {
+            System.out.println(e);
+        }
+    }
+}
+
diff --git a/pd/portmidi/pm_java/pmdefaults/README.txt b/pd/portmidi/pm_java/pmdefaults/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..eb24f5f1d6e89b37deef56ce077b9d8b9979cf43
--- /dev/null
+++ b/pd/portmidi/pm_java/pmdefaults/README.txt
@@ -0,0 +1,21 @@
+README.txt
+Roger B. Dannenberg
+2 Jan 2009
+
+PmDefaults is a program to set default input and output devices for PortMidi
+applications. After running the PmDefaults program and choosing devices,
+identifiers for these devices will be returned by 
+Pm_GetDefaultInputDeviceID() and Pm_GetDefaultOutputDeviceID().
+
+Included in this directory are:
+
+manifest.txt -- used in pmdefaults.jar
+pmdefaults-icon.* -- various icons for applications
+pmdefaults-license.txt -- a version of portmidi/license.txt formatted for
+		       the windows installer
+portmusic_logo.png -- a logo displayed by the pmdefaults application
+readme-win32.txt -- this becomes the readme file for the pmdefaults
+		 application. It is copied to win32/README.txt by make.bat
+
+TO BUILD THE APPLICATION: see ../README.txt
+
diff --git a/pd/portmidi/pm_java/pmdefaults/manifest.txt b/pd/portmidi/pm_java/pmdefaults/manifest.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f2e3016369a74120e44efbf244fcc032bedb3355
--- /dev/null
+++ b/pd/portmidi/pm_java/pmdefaults/manifest.txt
@@ -0,0 +1 @@
+Main-Class: pmdefaults/PmDefaults
diff --git a/pd/portmidi/pm_java/pmdefaults/pmdefaults b/pd/portmidi/pm_java/pmdefaults/pmdefaults
new file mode 100755
index 0000000000000000000000000000000000000000..80162469ae0661422a460651dbb2a90add174956
--- /dev/null
+++ b/pd/portmidi/pm_java/pmdefaults/pmdefaults
@@ -0,0 +1 @@
+java -jar /usr/share/java/pmdefaults.jar > /dev/null
diff --git a/pd/portmidi/pm_java/pmdefaults/pmdefaults-icon.bmp b/pd/portmidi/pm_java/pmdefaults/pmdefaults-icon.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..b34ccd295ab850b37975edbae2fbda46dd6a443f
Binary files /dev/null and b/pd/portmidi/pm_java/pmdefaults/pmdefaults-icon.bmp differ
diff --git a/pd/portmidi/pm_java/pmdefaults/pmdefaults-icon.gif b/pd/portmidi/pm_java/pmdefaults/pmdefaults-icon.gif
new file mode 100644
index 0000000000000000000000000000000000000000..4d8866cb1dff062c0b749c9fb834106bcfa4dfac
Binary files /dev/null and b/pd/portmidi/pm_java/pmdefaults/pmdefaults-icon.gif differ
diff --git a/pd/portmidi/pm_java/pmdefaults/pmdefaults-icon.png b/pd/portmidi/pm_java/pmdefaults/pmdefaults-icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..36db120027dce0d9b3919c7b68605e8a3ae4c91d
Binary files /dev/null and b/pd/portmidi/pm_java/pmdefaults/pmdefaults-icon.png differ
diff --git a/pd/portmidi/pm_java/pmdefaults/pmdefaults-icon.xcf b/pd/portmidi/pm_java/pmdefaults/pmdefaults-icon.xcf
new file mode 100644
index 0000000000000000000000000000000000000000..7b2acec319eb1c4012bef6c4c0c370960ae92585
Binary files /dev/null and b/pd/portmidi/pm_java/pmdefaults/pmdefaults-icon.xcf differ
diff --git a/pd/portmidi/pm_java/pmdefaults/pmdefaults-license.txt b/pd/portmidi/pm_java/pmdefaults/pmdefaults-license.txt
new file mode 100644
index 0000000000000000000000000000000000000000..aa7173419299305bfe9d7849d778b7e39949013c
--- /dev/null
+++ b/pd/portmidi/pm_java/pmdefaults/pmdefaults-license.txt
@@ -0,0 +1,37 @@
+LICENSE INFORMATION
+
+PmDefaults is a small program to set default MIDI input and output
+devices for other programs using the PortMidi library.
+
+Latest version available at: http://sourceforge.net/projects/portmedia
+
+Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+Copyright (c) 2001-2009 Roger B. Dannenberg
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files
+(the "Software"), to deal in the Software without restriction,
+including without limitation the rights 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 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 text above constitutes the entire PortMidi license; however, 
+the PortMusic community also makes the following non-binding requests:
+
+Any person wishing to distribute modifications to the Software is
+requested to send the modifications to the original developer so that
+they can be incorporated into the canonical version. It is also
+requested that these non-binding requests be included along with the 
+license above.
diff --git a/pd/portmidi/pm_java/pmdefaults/pmdefaults.icns b/pd/portmidi/pm_java/pmdefaults/pmdefaults.icns
new file mode 100644
index 0000000000000000000000000000000000000000..75840850bbe8e8b69f9628f1b09cf219aeaeee1b
Binary files /dev/null and b/pd/portmidi/pm_java/pmdefaults/pmdefaults.icns differ
diff --git a/pd/portmidi/pm_java/pmdefaults/pmdefaults.ico b/pd/portmidi/pm_java/pmdefaults/pmdefaults.ico
new file mode 100644
index 0000000000000000000000000000000000000000..801a7062aa76c5ee8a3bc8090191a8f74c76f835
Binary files /dev/null and b/pd/portmidi/pm_java/pmdefaults/pmdefaults.ico differ
diff --git a/pd/portmidi/pm_java/pmdefaults/portmusic_logo.png b/pd/portmidi/pm_java/pmdefaults/portmusic_logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..17a063a6ab93ce6976acf0de8fad8c30f23e7394
Binary files /dev/null and b/pd/portmidi/pm_java/pmdefaults/portmusic_logo.png differ
diff --git a/pd/portmidi/pm_java/pmdefaults/readme-win32.txt b/pd/portmidi/pm_java/pmdefaults/readme-win32.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4aa1c60d9da33ba4eabbc64372924e279faeff31
--- /dev/null
+++ b/pd/portmidi/pm_java/pmdefaults/readme-win32.txt
@@ -0,0 +1,11 @@
+README.txt
+Roger B. Dannenberg
+1 Jan 2009
+
+This directory contains files that implement:
+
+pmdefaults -- a program to set PortMidi default input/output devices
+
+You can copy and rename this *whole directory* to move the application
+to a convenient place. The application to run is pmdefaults.exe.
+
diff --git a/pd/portmidi/pm_java/pmjni/jportmidi_JportMidiApi.h b/pd/portmidi/pm_java/pmjni/jportmidi_JportMidiApi.h
new file mode 100644
index 0000000000000000000000000000000000000000..2208be60167edf14678b083209e956eedb6b30bb
--- /dev/null
+++ b/pd/portmidi/pm_java/pmjni/jportmidi_JportMidiApi.h
@@ -0,0 +1,293 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class jportmidi_JPortMidiApi */
+
+#ifndef _Included_jportmidi_JPortMidiApi
+#define _Included_jportmidi_JPortMidiApi
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef jportmidi_JPortMidiApi_PM_FILT_ACTIVE
+#define jportmidi_JPortMidiApi_PM_FILT_ACTIVE 16384L
+#undef jportmidi_JPortMidiApi_PM_FILT_SYSEX
+#define jportmidi_JPortMidiApi_PM_FILT_SYSEX 1L
+#undef jportmidi_JPortMidiApi_PM_FILT_CLOCK
+#define jportmidi_JPortMidiApi_PM_FILT_CLOCK 256L
+#undef jportmidi_JPortMidiApi_PM_FILT_PLAY
+#define jportmidi_JPortMidiApi_PM_FILT_PLAY 7168L
+#undef jportmidi_JPortMidiApi_PM_FILT_TICK
+#define jportmidi_JPortMidiApi_PM_FILT_TICK 512L
+#undef jportmidi_JPortMidiApi_PM_FILT_FD
+#define jportmidi_JPortMidiApi_PM_FILT_FD 8192L
+#undef jportmidi_JPortMidiApi_PM_FILT_UNDEFINED
+#define jportmidi_JPortMidiApi_PM_FILT_UNDEFINED 8192L
+#undef jportmidi_JPortMidiApi_PM_FILT_RESET
+#define jportmidi_JPortMidiApi_PM_FILT_RESET 32768L
+#undef jportmidi_JPortMidiApi_PM_FILT_REALTIME
+#define jportmidi_JPortMidiApi_PM_FILT_REALTIME 16641L
+#undef jportmidi_JPortMidiApi_PM_FILT_NOTE
+#define jportmidi_JPortMidiApi_PM_FILT_NOTE 50331648L
+#undef jportmidi_JPortMidiApi_PM_FILT_CHANNEL_AFTERTOUCH
+#define jportmidi_JPortMidiApi_PM_FILT_CHANNEL_AFTERTOUCH 536870912L
+#undef jportmidi_JPortMidiApi_PM_FILT_POLY_AFTERTOUCH
+#define jportmidi_JPortMidiApi_PM_FILT_POLY_AFTERTOUCH 67108864L
+#undef jportmidi_JPortMidiApi_PM_FILT_AFTERTOUCH
+#define jportmidi_JPortMidiApi_PM_FILT_AFTERTOUCH 603979776L
+#undef jportmidi_JPortMidiApi_PM_FILT_PROGRAM
+#define jportmidi_JPortMidiApi_PM_FILT_PROGRAM 268435456L
+#undef jportmidi_JPortMidiApi_PM_FILT_CONTROL
+#define jportmidi_JPortMidiApi_PM_FILT_CONTROL 134217728L
+#undef jportmidi_JPortMidiApi_PM_FILT_PITCHBEND
+#define jportmidi_JPortMidiApi_PM_FILT_PITCHBEND 1073741824L
+#undef jportmidi_JPortMidiApi_PM_FILT_MTC
+#define jportmidi_JPortMidiApi_PM_FILT_MTC 2L
+#undef jportmidi_JPortMidiApi_PM_FILT_SONG_POSITION
+#define jportmidi_JPortMidiApi_PM_FILT_SONG_POSITION 4L
+#undef jportmidi_JPortMidiApi_PM_FILT_SONG_SELECT
+#define jportmidi_JPortMidiApi_PM_FILT_SONG_SELECT 8L
+#undef jportmidi_JPortMidiApi_PM_FILT_TUNE
+#define jportmidi_JPortMidiApi_PM_FILT_TUNE 64L
+#undef jportmidi_JPortMidiApi_PM_FILT_SYSTEMCOMMON
+#define jportmidi_JPortMidiApi_PM_FILT_SYSTEMCOMMON 78L
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_Initialize
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Initialize
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_Terminate
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Terminate
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_HasHostError
+ * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1HasHostError
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_GetErrorText
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetErrorText
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_GetHostErrorText
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetHostErrorText
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_CountDevices
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1CountDevices
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_GetDefaultInputDeviceID
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultInputDeviceID
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_GetDefaultOutputDeviceID
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultOutputDeviceID
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_GetDeviceInterf
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInterf
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_GetDeviceName
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceName
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_GetDeviceInput
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInput
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_GetDeviceOutput
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceOutput
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_OpenInput
+ * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;ILjava/lang/String;I)I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenInput
+  (JNIEnv *, jclass, jobject, jint, jstring, jint);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_OpenOutput
+ * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;ILjava/lang/String;II)I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenOutput
+  (JNIEnv *, jclass, jobject, jint, jstring, jint, jint);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_SetFilter
+ * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;I)I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetFilter
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_SetChannelMask
+ * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;I)I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetChannelMask
+  (JNIEnv *, jclass, jobject, jint);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_Abort
+ * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Abort
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_Close
+ * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Close
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_Read
+ * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;Ljportmidi/JPortMidiApi/PmEvent;)I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Read
+  (JNIEnv *, jclass, jobject, jobject);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_Poll
+ * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Poll
+  (JNIEnv *, jclass, jobject);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_Write
+ * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;Ljportmidi/JPortMidiApi/PmEvent;)I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Write
+  (JNIEnv *, jclass, jobject, jobject);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_WriteShort
+ * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;II)I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteShort
+  (JNIEnv *, jclass, jobject, jint, jint);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pm_WriteSysEx
+ * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;I[B)I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteSysEx
+  (JNIEnv *, jclass, jobject, jint, jbyteArray);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pt_TimeStart
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStart
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pt_TimeStop
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStop
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pt_Time
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1Time
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     jportmidi_JPortMidiApi
+ * Method:    Pt_TimeStarted
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStarted
+  (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class jportmidi_JPortMidiApi_PmEvent */
+
+#ifndef _Included_jportmidi_JPortMidiApi_PmEvent
+#define _Included_jportmidi_JPortMidiApi_PmEvent
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class jportmidi_JPortMidiApi_PortMidiStream */
+
+#ifndef _Included_jportmidi_JPortMidiApi_PortMidiStream
+#define _Included_jportmidi_JPortMidiApi_PortMidiStream
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/pd/portmidi/pm_java/pmjni/pmjni-VC8.vcproj b/pd/portmidi/pm_java/pmjni/pmjni-VC8.vcproj
new file mode 100644
index 0000000000000000000000000000000000000000..b7b2e2db3735323ab152e421fb9123dfde200eda
--- /dev/null
+++ b/pd/portmidi/pm_java/pmjni/pmjni-VC8.vcproj
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="pmjni"
+	ProjectGUID="{7AA255C8-48BF-40AC-97BA-F7E7BA4DDAA8}"
+	RootNamespace="pmjni"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(SolutionDir)\pm_common&quot;;&quot;$(SolutionDir)\porttime&quot;;&quot;$(ProjectDir)&quot;;&quot;E:\Program Files\Java\jdk1.5.0_14\include&quot;;&quot;E:\Program Files\Java\jdk1.5.0_14\include\win32&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PMJNI_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="winmm.lib"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(SolutionDir)\pm_common&quot;;&quot;$(SolutionDir)\porttime&quot;;&quot;$(ProjectDir)&quot;;&quot;E:\Program Files\Java\jdk1.5.0_14\include&quot;;&quot;E:\Program Files\Java\jdk1.5.0_14\include\win32&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;PMJNI_EXPORTS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="winmm.lib"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\pmjni.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\pm_common\pmutil.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\pm_win\pmwin.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\pm_win\pmwinmm.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\pm_common\portmidi.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\porttime\porttime.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\porttime\ptwinmm.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_java/pmjni/pmjni.c b/pd/portmidi/pm_java/pmjni/pmjni.c
new file mode 100644
index 0000000000000000000000000000000000000000..95e51dda4c5f32248189bf509fc4c3b9d0ff7f12
--- /dev/null
+++ b/pd/portmidi/pm_java/pmjni/pmjni.c
@@ -0,0 +1,354 @@
+#include "portmidi.h"
+#include "porttime.h"
+#include "jportmidi_JportMidiApi.h"
+#include <stdio.h>
+
+// these macros assume JNIEnv *env is declared and valid:
+//
+#define CLASS(c, obj) jclass c = (*env)->GetObjectClass(env, obj)
+#define ADDRESS_FID(fid, c) \
+    jfieldID fid = (*env)->GetFieldID(env, c, "address", "J")
+// Uses Java Long (64-bit) to make sure there is room to store a 
+// pointer. Cast this to a C long (either 32 or 64 bit) to match
+// the size of a pointer. Finally cast int to pointer. All this
+// is supposed to avoid C compiler warnings and (worse) losing
+// address bits.
+#define PMSTREAM(obj, fid) ((PmStream *) (long) (*env)->GetLongField(env, obj, fid))
+// Cast stream to long to convert integer to pointer, then expand
+// integer to 64-bit jlong. This avoids compiler warnings.
+#define SET_PMSTREAM(obj, fid, stream) \
+    (*env)->SetLongField(env, obj, fid, (jlong) (long) stream)
+
+
+/*
+ * Method:    Pm_Initialize
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Initialize
+  (JNIEnv *env, jclass cl)
+{
+    return Pm_Initialize();
+}
+
+
+/*
+ * Method:    Pm_Terminate
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Terminate
+  (JNIEnv *env, jclass cl)
+{
+    return Pm_Terminate();
+}
+
+
+/*
+ * Method:    Pm_HasHostError
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1HasHostError
+  (JNIEnv *env, jclass cl, jobject jstream)
+{
+    CLASS(c, jstream);
+    ADDRESS_FID(fid, c);
+    return Pm_HasHostError(PMSTREAM(jstream, fid));
+}
+
+
+/*
+ * Method:    Pm_GetErrorText
+ */
+JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetErrorText
+  (JNIEnv *env, jclass cl, jint i)
+{
+    return (*env)->NewStringUTF(env, Pm_GetErrorText(i));
+}
+
+
+/*
+ * Method:    Pm_GetHostErrorText
+ */
+JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetHostErrorText
+  (JNIEnv *env, jclass cl)
+{
+    char msg[PM_HOST_ERROR_MSG_LEN];
+    Pm_GetHostErrorText(msg, PM_HOST_ERROR_MSG_LEN);
+    return (*env)->NewStringUTF(env, msg);
+}
+
+
+/*
+ * Method:    Pm_CountDevices
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1CountDevices
+  (JNIEnv *env, jclass cl)
+{
+    return Pm_CountDevices();
+}
+
+
+/*
+ * Method:    Pm_GetDefaultInputDeviceID
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultInputDeviceID
+  (JNIEnv *env, jclass cl)
+{
+    return Pm_GetDefaultInputDeviceID();
+}
+
+
+/*
+ * Method:    Pm_GetDefaultOutputDeviceID
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultOutputDeviceID
+  (JNIEnv *env, jclass cl)
+{
+    return Pm_GetDefaultOutputDeviceID();
+}
+
+
+/*
+ * Method:    Pm_GetDeviceInterf
+ */
+JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInterf
+  (JNIEnv *env, jclass cl, jint i)
+{
+    const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+    if (!info) return NULL;
+    return (*env)->NewStringUTF(env, info->interf);
+}
+
+
+/*
+ * Method:    Pm_GetDeviceName
+ */
+JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceName
+  (JNIEnv *env, jclass cl, jint i)
+{
+    const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+    if (!info) return NULL;
+    return (*env)->NewStringUTF(env, info->name);
+}
+
+
+/*
+ * Method:    Pm_GetDeviceInput
+ */
+JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInput
+  (JNIEnv *env, jclass cl, jint i)
+{
+    const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+    if (!info) return (jboolean) 0;
+    return (jboolean) info->input;
+}
+
+
+/*
+ * Method:    Pm_GetDeviceOutput
+ */
+JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceOutput
+  (JNIEnv *env, jclass cl, jint i)
+{
+    const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+    if (!info) return (jboolean) 0;
+    return (jboolean) info->output;
+}
+
+
+/*
+ * Method:    Pm_OpenInput
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenInput
+  (JNIEnv *env, jclass cl, 
+   jobject jstream, jint index, jstring extras, jint bufsiz)
+{
+    PmError rslt;
+    PortMidiStream *stream;
+    CLASS(c, jstream);
+    ADDRESS_FID(fid, c);
+    rslt = Pm_OpenInput(&stream, index, NULL, bufsiz, NULL, NULL);
+    SET_PMSTREAM(jstream, fid, stream);
+    return rslt;
+}
+
+
+/*
+ * Method:    Pm_OpenOutput
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenOutput
+  (JNIEnv *env, jclass cl, jobject jstream, jint index, jstring extras,
+   jint bufsiz, jint latency)
+{
+    PmError rslt;
+    PortMidiStream *stream;
+    CLASS(c, jstream);
+    ADDRESS_FID(fid, c);
+    rslt = Pm_OpenOutput(&stream, index, NULL, bufsiz, NULL, NULL, latency);
+    SET_PMSTREAM(jstream, fid, stream);
+    return rslt;
+}
+
+
+/*
+ * Method:    Pm_SetFilter
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetFilter
+  (JNIEnv *env, jclass cl, jobject jstream, jint filters)
+{
+    CLASS(c, jstream);
+    ADDRESS_FID(fid, c);
+    return Pm_SetFilter(PMSTREAM(jstream, fid), filters);
+}
+
+
+/*
+ * Method:    Pm_SetChannelMask
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetChannelMask
+  (JNIEnv *env, jclass cl, jobject jstream, jint mask)
+{
+    CLASS(c, jstream);
+    ADDRESS_FID(fid, c);
+    return Pm_SetChannelMask(PMSTREAM(jstream, fid), mask);
+}
+
+
+/*
+ * Method:    Pm_Abort
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Abort
+  (JNIEnv *env, jclass cl, jobject jstream)
+{
+    CLASS(c, jstream);
+    ADDRESS_FID(fid, c);
+    return Pm_Abort(PMSTREAM(jstream, fid));
+}
+
+
+/*
+ * Method:    Pm_Close
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Close
+  (JNIEnv *env, jclass cl, jobject jstream)
+{
+    CLASS(c, jstream);
+    ADDRESS_FID(fid, c);
+    return Pm_Close(PMSTREAM(jstream, fid));
+}
+
+
+/*
+ * Method:    Pm_Read
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Read
+  (JNIEnv *env, jclass cl, jobject jstream, jobject jpmevent)
+{
+    CLASS(jstream_class, jstream);
+    ADDRESS_FID(address_fid, jstream_class);
+    jclass jpmevent_class = (*env)->GetObjectClass(env, jpmevent);
+    jfieldID message_fid = 
+            (*env)->GetFieldID(env, jpmevent_class, "message", "I");
+    jfieldID timestamp_fid = 
+            (*env)->GetFieldID(env, jpmevent_class, "timestamp", "I");
+    PmEvent buffer;
+    PmError rslt = Pm_Read(PMSTREAM(jstream, address_fid), &buffer, 1);
+    (*env)->SetIntField(env, jpmevent, message_fid, buffer.message);
+    (*env)->SetIntField(env, jpmevent, timestamp_fid, buffer.timestamp);
+    return rslt;
+}
+
+
+/*
+ * Method:    Pm_Poll
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Poll
+        (JNIEnv *env, jclass cl, jobject jstream)
+{
+    CLASS(c, jstream);
+    ADDRESS_FID(fid, c);
+    return Pm_Poll(PMSTREAM(jstream, fid));
+}
+
+
+/*
+ * Method:    Pm_Write
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Write
+        (JNIEnv *env, jclass cl, jobject jstream, jobject jpmevent)
+{
+    CLASS(jstream_class, jstream);
+    ADDRESS_FID(address_fid, jstream_class);
+    jclass jpmevent_class = (*env)->GetObjectClass(env, jpmevent);
+    jfieldID message_fid = 
+            (*env)->GetFieldID(env, jpmevent_class, "message", "I");
+    jfieldID timestamp_fid = 
+            (*env)->GetFieldID(env, jpmevent_class, "timestamp", "I");
+    // note that we call WriteShort because it's simpler than constructing
+    // a buffer and passing it to Pm_Write
+    return Pm_WriteShort(PMSTREAM(jstream, address_fid),
+            (*env)->GetIntField(env, jpmevent, timestamp_fid),
+            (*env)->GetIntField(env, jpmevent, message_fid));
+}
+
+
+/*
+ * Method:    Pm_WriteShort
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteShort
+  (JNIEnv *env, jclass cl, jobject jstream, jint when, jint msg)
+{
+    CLASS(c, jstream);
+    ADDRESS_FID(fid, c);
+    return Pm_WriteShort(PMSTREAM(jstream, fid), when, msg);
+}
+
+
+/*
+ * Method:    Pm_WriteSysEx
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteSysEx
+  (JNIEnv *env, jclass cl, jobject jstream, jint when, jbyteArray jmsg)
+{
+    CLASS(c, jstream);
+    ADDRESS_FID(fid, c);
+    jbyte *bytes = (*env)->GetByteArrayElements(env, jmsg, 0);
+    PmError rslt = Pm_WriteSysEx(PMSTREAM(jstream, fid), when, 
+                                 (unsigned char *) bytes);
+    (*env)->ReleaseByteArrayElements(env, jmsg, bytes, 0);
+    return rslt;
+}
+
+/*
+ * Method:    Pt_TimeStart
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStart
+        (JNIEnv *env, jclass c, jint resolution)
+{
+    return Pt_Start(resolution, NULL, NULL);
+}
+
+/*
+ * Method:    Pt_TimeStop
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStop
+        (JNIEnv *env, jclass c)
+ {
+     return Pt_Stop();
+ }
+
+/*
+ * Method:    Pt_Time
+ */
+JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1Time
+        (JNIEnv *env, jclass c)
+ {
+     return Pt_Time();
+ }
+
+/*
+ * Method:    Pt_TimeStarted
+ */
+JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStarted
+        (JNIEnv *env, jclass c)
+{
+    return Pt_Started();
+}
+
+
diff --git a/pd/portmidi/pm_java/pmjni/pmjni.rc b/pd/portmidi/pm_java/pmjni/pmjni.rc
new file mode 100644
index 0000000000000000000000000000000000000000..1b7522b7a4aebff051d91569aaaca2ea811a8681
--- /dev/null
+++ b/pd/portmidi/pm_java/pmjni/pmjni.rc
@@ -0,0 +1,63 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/pd/portmidi/pm_java/setup/pmdefaults-setup.exe b/pd/portmidi/pm_java/setup/pmdefaults-setup.exe
new file mode 100644
index 0000000000000000000000000000000000000000..78ef52c3e440708affcc7e8908cb51f8a9ad5faf
Binary files /dev/null and b/pd/portmidi/pm_java/setup/pmdefaults-setup.exe differ
diff --git a/pd/portmidi/pm_linux/README_LINUX.txt b/pd/portmidi/pm_linux/README_LINUX.txt
old mode 100644
new mode 100755
index d3adf5a9bb19b3c1511360063e2de9151613fa07..754f41a2d5d11b260b053dff9470b4907cf003db
--- a/pd/portmidi/pm_linux/README_LINUX.txt
+++ b/pd/portmidi/pm_linux/README_LINUX.txt
@@ -1,31 +1,101 @@
 README_LINUX.txt for PortMidi
 Roger Dannenberg
-29 Aug 2006
+14 Oct 2009
 
-To make PortMidi and PortTime, go back up to the portmidi
-directory and type 
+To make PortMidi, you need cmake and the Java SDK.
+Go back up to the portmidi directory and type:
 
-make -f pm_linux/Makefile
+ccmake .
 
-(You can also copy pm_linux/Makefile to the portmidi
-directory and just type "make".)
+Type 'c' (configure) and then 'g' (generate). You may have
+to manually set JAVA_INCLUDE_PATH and JAVA_JVM_LIBRARY
+by typing 't' (toggle to advanced mode) and using the 
+editor to change the fields. You can find possible values
+for JAVA_INCLUDE_PATH by typing "locate jni.h", and for
+JAVA_JVM_LIBRARY by typing locate libjvm".
+
+You also need JAVA_INCLUDE_PATH2, but this will normally
+be set automatically after you set JAVA_INCLUDE_PATH and
+run "configure" (type "c" to ccmake). Normally,
+JAVA_INCLUDE_PATH2 is the linux subdirectory within
+JAVA_INCLUDE_PATH.
+
+Notice that the CMAKE_BUILD_TYPE can be Debug or Release.
+Stick with Release if you are not debugging.
+
+After successfully generating make files with ccmake, you
+can run make:
+
+make
 
 The Makefile will build all test programs and the portmidi
-library. You may want to modify the Makefile to remove the
-PM_CHECK_ERRORS definition. For experimental software,
+library. For experimental software,
 especially programs running from the command line, we 
-recommend using PM_CHECK_ERRORS -- it will terminate your
+recommend using the Debug version -- it will terminate your
 program and print a helpful message if any PortMidi 
-function returns an error code.
+function returns an error code. (Released software should
+check for error codes and handle them, but for quick,
+non-critical projects, the automatic "print and die" 
+handling can save some work.)
+
+THE pmdefaults PROGRAM
+
+You should install pmdefaults. It provides a graphical interface
+for selecting default MIDI IN and OUT devices so that you don't
+have to build device selection interfaces into all your programs
+and so users have a single place to set a preference.
+
+Follow the instructions above to run ccmake, making sure that
+CMAKE_BUILD_TYPE is Release. Run make as described above. Then:
+
+sudo make install
+
+This will install PortMidi libraries and the pmdefault program.
+You must alos have the environment variable LD_LIBRARY_PATH set
+to include /usr/local/lib (where libpmjni.so is installed).
+
+Now, you can run pmdefault.
+
 
-If you do not compile with PM_CHECK_ERRORS, you should 
-check for errors yourself.
+SETTING LD_LIBRARY_PATH
 
-This code has not been carefully tested; however, 
-all test programs in pm_test seem to run properly.
+pmdefaults will not work unless LD_LIBRARY_PATH includes a 
+directory (normally /usr/local/lib) containing libpmjni.so,
+installed as described above.
+
+To set LD_LIBRARY_PATH, you might want to add this to your
+~/.profile (if you use the bash shell):
+
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
+export LD_LIBRARY_PATH
+
+
+A NOTE ABOUT AMD64:
+
+When compiling portmidi under linux on an AMD64, I had to add the -fPIC
+flag to the gcc flags.
+
+Reason: when trying to build John Harrison's pyPortMidi gcc bailed out
+with this error:
+
+./linux/libportmidi.a(pmlinux.o): relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC
+./linux/libportmidi.a: could not read symbols: Bad value
+collect2: ld returned 1 exit status
+error: command 'gcc' failed with exit status 1
+
+What they said:
+http://www.gentoo.org/proj/en/base/amd64/howtos/index.xml?part=1&chap=3
+On certain architectures (AMD64 amongst them), shared libraries *must* 
+be "PIC-enabled".
 
 CHANGELOG
 
+22-jan-2010 Roger B. Dannenberg
+   Updated instructions about Java paths
+
+14-oct-2009 Roger B. Dannenberg
+   Using CMake now for building and configuration
+
 29-aug-2006 Roger B. Dannenberg
    Fixed PortTime to join with time thread for clean exit.    
 
diff --git a/pd/portmidi/pm_linux/finddefault.c b/pd/portmidi/pm_linux/finddefault.c
new file mode 100644
index 0000000000000000000000000000000000000000..6340316896416d421b02b3f4af78e0e2533983f6
--- /dev/null
+++ b/pd/portmidi/pm_linux/finddefault.c
@@ -0,0 +1,92 @@
+/* finddefault.c -- find_default_device() implementation
+   Roger Dannenberg, Jan 2009
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "portmidi.h"
+
+#define STRING_MAX 256
+
+/* skip over spaces, return first non-space */
+void skip_spaces(FILE *inf)
+{
+    char c;
+    while (isspace(c = getc(inf))) ;
+    ungetc(c, inf);
+}
+
+/* trim leading spaces and match a string */
+int match_string(FILE *inf, char *s)
+{
+    skip_spaces(inf);
+    while (*s && *s == getc(inf)) s++;
+    return (*s == 0);
+} 
+
+
+/* 
+/* Parse preference files, find default device, search devices --
+ */
+PmDeviceID find_default_device(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_2 = "/.java/.userPrefs/";
+    static char *pref_3 = "prefs.xml";
+    char *pref_1 = getenv("HOME");
+    char *full_name, *path_ptr;
+    FILE *inf;
+    int c, i;
+    if (!pref_1) goto nopref; // cannot find preference file
+    // full_name will be larger than necessary
+    full_name  = malloc(strlen(pref_1) + strlen(pref_2) + strlen(pref_3) +
+                        strlen(path) + 2);
+    strcpy(full_name, pref_1); 
+    strcat(full_name, pref_2);
+    // copy all but last path segment to full_name
+    if (*path == '/') path++; // skip initial slash in path
+    path_ptr = strrchr(path, '/'); 
+    if (path_ptr) { // copy up to slash after full_name
+        path_ptr++;
+        int offset = strlen(full_name);
+        memcpy(full_name + offset, path, path_ptr - path);
+        full_name[offset + path_ptr - path] = 0; // end of string
+    } else {
+        path_ptr = path;
+    }
+    strcat(full_name, pref_3);
+    inf = fopen(full_name, "r");
+    if (!inf) goto nopref; // cannot open preference file
+    // We're not going to build or link in a full XML parser.
+    // Instead, find the path string and quoute. Then, look for
+    // "value", "=", quote. Then get string up to quote.
+    while ((c = getc(inf)) != EOF) {
+        char pref_str[STRING_MAX];
+        if (c != '"') continue; // scan up to quote
+        // look for quote string quote
+        if (!match_string(inf, path_ptr)) continue; // path not found
+        if (getc(inf) != '"') continue; // path not found, keep scanning
+        if (!match_string(inf, "value")) goto nopref; // value not found
+        if (!match_string(inf, "=")) goto nopref; // = not found
+        if (!match_string(inf, "\"")) goto nopref; // quote not found
+        // now read the value up to the close quote
+        for (i = 0; i < STRING_MAX; i++) {
+            if ((c = getc(inf)) == '"') break;
+            pref_str[i] = c;
+        }
+        if (i == STRING_MAX) continue; // value too long, ignore
+        pref_str[i] == 0;
+        i = pm_find_default_device(pref_str, input);
+        if (i != pmNoDevice) {
+            id = i;
+	}
+        break;
+    }
+ nopref:
+    return id;
+}
diff --git a/pd/portmidi/pm_linux/pmlinux.c b/pd/portmidi/pm_linux/pmlinux.c
old mode 100644
new mode 100755
index dcb2b8b25643ec12ba2588cb28affb3128492c9d..49e266d7805964e8b945e06a5d726e5e80fdea10
--- a/pd/portmidi/pm_linux/pmlinux.c
+++ b/pd/portmidi/pm_linux/pmlinux.c
@@ -12,6 +12,9 @@
 
 #include "stdlib.h"
 #include "portmidi.h"
+#include "pmutil.h"
+#include "pminternal.h"
+
 #ifdef PMALSA
   #include "pmlinuxalsa.h"
 #endif
@@ -20,7 +23,10 @@
   #include "pmlinuxnull.h"
 #endif
 
-PmError pm_init()
+PmDeviceID pm_default_input_device_id = -1;
+PmDeviceID pm_default_output_device_id = -1;
+
+void pm_init()
 {
     /* Note: it is not an error for PMALSA to fail to initialize. 
      * It may be a design error that the client cannot query what subsystems
@@ -33,7 +39,15 @@ PmError pm_init()
     #ifdef PMNULL
         pm_linuxnull_init();
     #endif
-    return pmNoError;
+    // this is set when we return to Pm_Initialize, but we need it
+    // now in order to (successfully) call Pm_CountDevices()
+    pm_initialized = TRUE;      
+    pm_default_input_device_id = find_default_device(
+        "/PortMidi/PM_RECOMMENDED_INPUT_DEVICE", TRUE,
+        pm_default_input_device_id);
+    pm_default_output_device_id = find_default_device(
+        "/PortMidi/PM_RECOMMENDED_OUTPUT_DEVICE", FALSE,
+        pm_default_output_device_id);
 }
 
 void pm_term(void)
@@ -43,14 +57,13 @@ void pm_term(void)
     #endif
 }
 
-PmDeviceID pm_default_input_device_id = -1;
-PmDeviceID pm_default_output_device_id = -1;
-
 PmDeviceID Pm_GetDefaultInputDeviceID() { 
+    Pm_Initialize();
     return pm_default_input_device_id; 
 }
 
 PmDeviceID Pm_GetDefaultOutputDeviceID() { 
+    Pm_Initialize();
     return pm_default_output_device_id; 
 }
 
diff --git a/pd/portmidi/pm_linux/pmlinux.h b/pd/portmidi/pm_linux/pmlinux.h
old mode 100644
new mode 100755
diff --git a/pd/portmidi/pm_linux/pmlinuxalsa.c b/pd/portmidi/pm_linux/pmlinuxalsa.c
old mode 100644
new mode 100755
index 6132e0906bee85b71d9868a9b4313064df6962a0..a86adfb6d4865d5b0cac9e93d4fea05459e20429
--- a/pd/portmidi/pm_linux/pmlinuxalsa.c
+++ b/pd/portmidi/pm_linux/pmlinuxalsa.c
@@ -9,9 +9,7 @@
 
 #include "stdlib.h"
 #include "portmidi.h"
-#ifdef NEWBUFFER
 #include "pmutil.h"
-#endif
 #include "pminternal.h"
 #include "pmlinuxalsa.h"
 #include "string.h"
@@ -39,7 +37,6 @@
 #define GET_DESCRIPTOR_PORT(info) (((int)(info)) & 0xff)
 
 #define BYTE unsigned char
-#define UINT unsigned long
 
 extern pm_fns_node pm_linuxalsa_in_dictionary;
 extern pm_fns_node pm_linuxalsa_out_dictionary;
@@ -385,12 +382,12 @@ static PmError alsa_abort(PmInternal *midi)
 
 #ifdef GARBAGE
 This is old code here temporarily for reference
-static PmError alsa_write(PmInternal *midi, PmEvent *buffer, long length)
+static PmError alsa_write(PmInternal *midi, PmEvent *buffer, int32_t length)
 {
     alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor;
     int i, bytes;
     unsigned char byte;
-    long msg;
+    PmMessage msg;
 
     desc->error = 0;
     for (; length > 0; length--, buffer++) {
@@ -423,7 +420,7 @@ static PmError alsa_write(PmInternal *midi, PmEvent *buffer, long length)
     }
     if (desc->error < 0) return pmHostError;
 
-    VERBOSE printf("snd_seq_drain_output: 0x%x\n", seq);
+    VERBOSE printf("snd_seq_drain_output: 0x%x\n", (unsigned int) seq);
     desc->error = snd_seq_drain_output(seq);
     if (desc->error < 0) return pmHostError;
 
@@ -448,7 +445,7 @@ static PmError alsa_write_flush(PmInternal *midi, PmTimestamp timestamp)
 static PmError alsa_write_short(PmInternal *midi, PmEvent *event)
 {
     int bytes = midi_message_length(event->message);
-    long msg = event->message;
+    PmMessage msg = event->message;
     int i;
     alsa_descriptor_type desc = (alsa_descriptor_type) midi->descriptor;
     for (i = 0; i < bytes; i++) {
diff --git a/pd/portmidi/pm_linux/pmlinuxalsa.h b/pd/portmidi/pm_linux/pmlinuxalsa.h
old mode 100644
new mode 100755
diff --git a/pd/portmidi/pm_mac/Makefile.osx b/pd/portmidi/pm_mac/Makefile.osx
new file mode 100755
index 0000000000000000000000000000000000000000..383255481242a0ca46005b155f2d71d7e8cd2d48
--- /dev/null
+++ b/pd/portmidi/pm_mac/Makefile.osx
@@ -0,0 +1,129 @@
+# MAKEFILE FOR PORTMIDI
+
+# Roger B. Dannenberg
+# Sep 2009
+
+# NOTE: you can use
+#     make -f pm_osx/Makefile.osx configuration=Release
+# to override the default Debug configuration
+configuration=Release
+
+PF=/usr/local
+
+# For debugging, define PM_CHECK_ERRORS
+ifeq ($(configuration),Release)
+    CONFIG = Release
+else
+    CONFIG = Debug
+endif
+
+current: all
+
+all: $(CONFIG)/CMakeCache.txt
+	cd $(CONFIG); make
+
+$(CONFIG)/CMakeCache.txt:
+	rm -f 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'
+
+help:
+	echo $$'\n\n\
+This is help for portmidi/pm_mac/Makefile.osx\n\n\
+Installation path for dylib is $(PF)\n\
+To build Release version libraries and test applications,\n        \
+make -f pm_mac/Makefile.osx\n\
+To build Debug version libraries and test applications,\n        \
+make -f pm_mac/Makefile.osx configuration=Debug\n\
+To install universal dynamic library,\n        \
+sudo make -f pm_mac/Makefile.osx install\n\
+To install universal dynamic library with xcode,\n        \
+make -f pm_mac/Makefile.osx install-with-xcode\n\
+To make PmDefaults Java application,\n        \
+make -f pm_mac/Makefile.osx pmdefaults\n\n        \
+configuration = $(configuration)\n'
+
+
+clean:
+	rm -f *.o *~ core* */*.o */*/*.o */*~ */core* pm_test/*/pm_dll.dll 
+	rm -f *.opt *.ncb *.plg pm_win/Debug/pm_dll.lib pm_win/Release/pm_dll.lib
+	rm -f pm_test/*.opt pm_test/*.ncb
+	rm -f pm_java/pmjni/*.o pm_java/pmjni/*~ pm_java/*.h
+	rm -rf Release/CMakeFiles Debug/CMakeFiles
+	rm -rf pm_mac/pmdefaults/lib pm_mac/pmdefaults/src
+
+cleaner: clean
+	rm -rf pm_mac/build
+	rm -rf pm_mac/Debug pm_mac/Release pm_test/Debug pm_test/Release
+	rm -f Debug/*.dylib Release/*.dylib
+	rm -f pm_java/pmjni/Debug/*.jnilib
+	rm -f pm_java/pmjni/Release/*.jnilib
+
+cleanest: cleaner
+	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
+	rm -f pm_test/Debug/qtest pm_test/Debug/mm
+	rm -f pm_test/Release/test pm_test/Release/sysex pm_test/Release/midithread
+	rm -f pm_test/Release/latency pm_test/Release/midithru
+	rm -f pm_test/Release/qtest pm_test/Release/mm
+	rm -f pm_java/*/*.class
+	rm -f pm_java/pmjni/jportmidi_JPortMidiApi_PortMidiStream.h
+
+backup: cleanest
+	cd ..; zip -r portmidi.zip portmidi
+
+install: porttime/porttime.h pm_common/portmidi.h \
+	   $(CONFIG)/libportmidi.dylib
+	install porttime/porttime.h  $(PF)/include/
+	install pm_common/portmidi.h $(PF)/include
+	install $(CONFIG)/libportmidi.dylib $(PF)/lib/
+
+# note - this uses xcode to build and install portmidi universal binaries
+install-with-xcode:
+	sudo xcodebuild -project pm_mac/pm_mac.xcodeproj \
+		-configuration Release install DSTROOT=/
+
+##### build pmdefault ######
+
+pm_java/pmjni/jportmidi_JPortMidiApi.h: pm_java/jportmidi/JPortMidiApi.class
+	cd pm_java; javah jportmidi.JPortMidiApi
+	mv pm_java/jportmidi_JportMidiApi.h pm_java/pmjni
+
+JAVASRC = pmdefaults/PmDefaultsFrame.java \
+	    pmdefaults/PmDefaults.java \
+	    jportmidi/JPortMidiApi.java jportmidi/JPortMidi.java \
+	    jportmidi/JPortMidiException.java
+
+# this compiles ALL of the java code
+pm_java/jportmidi/JPortMidiApi.class: $(JAVASRC:%=pm_java/%)
+	cd pm_java; javac $(JAVASRC)
+
+$(CONFIG)/libpmjni.dylib:
+	mkdir -p $(CONFIG)
+	cd $(CONFIG); make -f ../pm_mac/$(MAKEFILE)
+
+pmdefaults: $(CONFIG)/libpmjni.dylib pm_java/jportmidi/JPortMidiApi.class
+ifeq ($(CONFIG),Debug)
+	echo "Error: you cannot build pmdefaults in a Debug configuration \n\
+    You should use configuration=Release in the Makefile command line. "
+	@exit 2
+endif
+	xcodebuild -project pm_mac/pm_mac.xcodeproj \
+            -configuration Release -target PmDefaults
+	echo "pmdefaults java application is made"
+
+###### test plist reader #######
+PLHDR = pm_mac/readbinaryplist.h
+PLSRC = pm_mac/plisttest.c pm_mac/readbinaryplist.c
+pm_mac/plisttest: $(PLHDR) $(PLSRC)
+	cc $(VFLAGS) -Ipm_mac \
+	    -I/Developer/Headers/FlatCarbon \
+	    -I/System/Library/Frameworks/CoreFoundation.framework/Headers \
+	    -I/System/Library/Frameworks/CoreServices.framework/Headers \
+	    $(PLSRC) -o pm_mac/$(CONFIG)/plisttest \
+	    -framework CoreFoundation -framework CoreServices
+
diff --git a/pd/portmidi/pm_mac/README_MAC.txt b/pd/portmidi/pm_mac/README_MAC.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6fa69384029083b189dff1605a780093ec80d425
--- /dev/null
+++ b/pd/portmidi/pm_mac/README_MAC.txt
@@ -0,0 +1,163 @@
+README_MAC.txt for PortMidi
+Roger Dannenberg
+20 nov 2009
+revised 20 Sep 2010 for Xcode 3.2.4 and CMake 8.2-2
+
+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/pd/portmidi/pm_mac/finddefault.c b/pd/portmidi/pm_mac/finddefault.c
new file mode 100644
index 0000000000000000000000000000000000000000..59e02a10be58faf4ae3e0429196bb868f856a7a2
--- /dev/null
+++ b/pd/portmidi/pm_mac/finddefault.c
@@ -0,0 +1,57 @@
+/* finddefault.c -- find_default_device() implementation
+   Roger Dannenberg, June 2008
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "portmidi.h"
+#include "pmutil.h"
+#include "pminternal.h"
+#include "pmmacosxcm.h"
+#include "readbinaryplist.h"
+
+/* Parse preference files, find default device, search devices --
+   This parses the preference file(s) once for input and once for
+   output, which is inefficient but much simpler to manage. Note
+   that using the readbinaryplist.c module, you cannot keep two
+   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)
+/* 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 = "com.apple.java.util.prefs.plist";
+    char *pref_str = NULL;
+    // read device preferences
+    value_ptr prefs = bplist_read_user_pref(pref_file);
+    if (prefs) {
+        value_ptr pref_val = value_dict_lookup_using_path(prefs, path);
+        if (pref_val) {
+            pref_str = value_get_asciistring(pref_val);
+        }
+    }
+    if (!pref_str) {
+        bplist_free_data(); /* look elsewhere */
+        prefs = bplist_read_system_pref(pref_file);
+        if (prefs) {
+            value_ptr pref_val = value_dict_lookup_using_path(prefs, path);
+            if (pref_val) {
+                pref_str = value_get_asciistring(pref_val);
+            }
+        }
+    }
+    if (pref_str) { /* search devices for match */
+        int i = pm_find_default_device(pref_str, input);
+        if (i != pmNoDevice) {
+            id = i;
+	}
+    }
+    if (prefs) {
+        bplist_free_data();
+    }
+    return id;
+}
diff --git a/pd/portmidi/pm_mac/pm_mac.xcodeproj/project.pbxproj b/pd/portmidi/pm_mac/pm_mac.xcodeproj/project.pbxproj
new file mode 100755
index 0000000000000000000000000000000000000000..0d06e565eae3f5ca4ce0e7529de4e973c6c37f56
--- /dev/null
+++ b/pd/portmidi/pm_mac/pm_mac.xcodeproj/project.pbxproj
@@ -0,0 +1,594 @@
+// !$*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/pd/portmidi/pm_mac/pmdefaults/make/build.xml b/pd/portmidi/pm_mac/pmdefaults/make/build.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bd08c6820821faec79b02ac05109e5d23cba1c34
--- /dev/null
+++ b/pd/portmidi/pm_mac/pmdefaults/make/build.xml
@@ -0,0 +1,87 @@
+<?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/pd/portmidi/pm_mac/pmdefaults/make/find-classrefs.sh b/pd/portmidi/pm_mac/pmdefaults/make/find-classrefs.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2217580d0d3795000a0ef206b98ba6d953def8ff
--- /dev/null
+++ b/pd/portmidi/pm_mac/pmdefaults/make/find-classrefs.sh
@@ -0,0 +1,31 @@
+#!/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/pd/portmidi/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf b/pd/portmidi/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf
new file mode 100644
index 0000000000000000000000000000000000000000..18f83781e7bdaa213d07cfbb3bdb831ad0e61a2a
--- /dev/null
+++ b/pd/portmidi/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf
@@ -0,0 +1,14 @@
+{\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/pd/portmidi/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings b/pd/portmidi/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings
new file mode 100644
index 0000000000000000000000000000000000000000..c7e5600f98a243b56851ce705e364d2712c690f9
Binary files /dev/null and b/pd/portmidi/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings differ
diff --git a/pd/portmidi/pm_mac/pmdefaults/resources/Info.plist b/pd/portmidi/pm_mac/pmdefaults/resources/Info.plist
new file mode 100644
index 0000000000000000000000000000000000000000..58bedb450137a4fc8b7fdecb0abd17f63d6d445b
--- /dev/null
+++ b/pd/portmidi/pm_mac/pmdefaults/resources/Info.plist
@@ -0,0 +1,40 @@
+<?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/pd/portmidi/pm_mac/pmdefaults/resources/Manifest b/pd/portmidi/pm_mac/pmdefaults/resources/Manifest
new file mode 100644
index 0000000000000000000000000000000000000000..5dee9b0dc13b15709ffcdc2dada46449a38f7097
--- /dev/null
+++ b/pd/portmidi/pm_mac/pmdefaults/resources/Manifest
@@ -0,0 +1 @@
+Main-Class: pmdefaults/PmDefaults
diff --git a/pd/portmidi/pm_mac/pmmac.c b/pd/portmidi/pm_mac/pmmac.c
old mode 100644
new mode 100755
index fbf31c83de2e0aa87b7012f0aa179eea2b818ed6..13ac68300441e582ac52e08c37c555a054b46260
--- a/pd/portmidi/pm_mac/pmmac.c
+++ b/pd/portmidi/pm_mac/pmmac.c
@@ -11,27 +11,44 @@ non-CoreMIDI devices.
 
 #include "stdlib.h"
 #include "portmidi.h"
+#include "pmutil.h"
+#include "pminternal.h"
 #include "pmmacosxcm.h"
 
-PmError pm_init()
+PmDeviceID pm_default_input_device_id = -1;
+PmDeviceID pm_default_output_device_id = -1;
+
+void pm_init()
 {
-    return pm_macosxcm_init();
+    PmError err = pm_macosxcm_init();
+    // this is set when we return to Pm_Initialize, but we need it
+    // now in order to (successfully) call Pm_CountDevices()
+    pm_initialized = TRUE;
+    if (!err) {
+        pm_default_input_device_id = find_default_device(
+                "/PortMidi/PM_RECOMMENDED_INPUT_DEVICE", TRUE, 
+                pm_default_input_device_id);
+        pm_default_output_device_id = find_default_device(
+                "/PortMidi/PM_RECOMMENDED_OUTPUT_DEVICE", FALSE, 
+                pm_default_output_device_id);
+    }
 }
 
+
 void pm_term(void)
 {
     pm_macosxcm_term();
 }
 
-PmDeviceID pm_default_input_device_id = -1;
-PmDeviceID pm_default_output_device_id = -1;
 
 PmDeviceID Pm_GetDefaultInputDeviceID()
 {
+    Pm_Initialize();
     return pm_default_input_device_id;
 }
 
 PmDeviceID Pm_GetDefaultOutputDeviceID() {
+    Pm_Initialize();
     return pm_default_output_device_id;
 }
 
diff --git a/pd/portmidi/pm_mac/pmmac.h b/pd/portmidi/pm_mac/pmmac.h
old mode 100644
new mode 100755
diff --git a/pd/portmidi/pm_mac/pmmacosxcm.c b/pd/portmidi/pm_mac/pmmacosxcm.c
old mode 100644
new mode 100755
index 4971da1b6c338e55a493484b74a1295564361c79..78513573d46831beccd47c7447894a166c563232
--- a/pd/portmidi/pm_mac/pmmacosxcm.c
+++ b/pd/portmidi/pm_mac/pmmacosxcm.c
@@ -26,9 +26,7 @@
 //#define CM_DEBUG 1
 
 #include "portmidi.h"
-#ifdef NEWBUFFER
 #include "pmutil.h"
-#endif
 #include "pminternal.h"
 #include "porttime.h"
 #include "pmmac.h"
@@ -40,17 +38,34 @@
 #include <CoreServices/CoreServices.h>
 #include <CoreMIDI/MIDIServices.h>
 #include <CoreAudio/HostTime.h>
+#include <unistd.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
 
-/* this is very strange: if I put in a reasonable 
-   number here, e.g. 128, which would allow sysex data
-   to be sent 128 bytes at a time, then I lose sysex
-   data in my loopback test. With a buffer size of 4,
-   we put at most 4 bytes in a packet (but maybe many
-   packets in a packetList), and everything works fine.
+     This is the minimum timestamp allowed in the next packet. 
+
+     Note that this distorts accurate timestamps somewhat.
  */
-#define SYSEX_BUFFER_SIZE 4
+#define LIMIT_RATE 1
+
+#define SYSEX_BUFFER_SIZE 128
 
 #define VERBOSE_ON 1
 #define VERBOSE if (VERBOSE_ON)
@@ -59,21 +74,29 @@
 #define MIDI_EOX        0xf7
 #define MIDI_STATUS_MASK 0x80
 
-static MIDIClientRef	client = NULL;	/* Client handle to the MIDI server */
-static MIDIPortRef	portIn = NULL;	/* Input port handle */
-static MIDIPortRef	portOut = NULL;	/* Output port handle */
+// "Ref"s are pointers on 32-bit machines and ints on 64 bit machines
+// NULL_REF is our representation of either 0 or NULL
+#ifdef __LP64__
+#define NULL_REF 0
+#else
+#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 */
 
 extern pm_fns_node pm_macosx_in_dictionary;
 extern pm_fns_node pm_macosx_out_dictionary;
 
 typedef struct midi_macosxcm_struct {
-    unsigned long sync_time; /* when did we last determine delta? */
+    PmTimestamp sync_time; /* when did we last determine delta? */
     UInt64 delta;	/* difference between stream time and real time in ns */
-    UInt64 last_time;	/* last output time */
+    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 */
-    unsigned long sysex_word; /* accumulate data when receiving sysex */
-    unsigned int sysex_byte_count; /* count how many received */
+    uint32_t sysex_word; /* accumulate data when receiving sysex */
+    uint32_t sysex_byte_count; /* count how many received */
     char error[PM_HOST_ERROR_MSG_LEN];
     char callback_error[PM_HOST_ERROR_MSG_LEN];
     Byte packetBuffer[PACKET_BUFFER_SIZE];
@@ -83,7 +106,12 @@ typedef struct midi_macosxcm_struct {
     MIDITimeStamp sysex_timestamp; /* timestamp to use with sysex data */
     /* allow for running status (is running status possible here? -rbd): -cpr */
     unsigned char last_command; 
-    long last_msg_length;
+    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? */
+    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;
 
 /* private function declarations */
@@ -94,7 +122,7 @@ char* cm_get_full_endpoint_name(MIDIEndpointRef endpoint);
 
 
 static int
-midi_length(long msg)
+midi_length(int32_t msg)
 {
     int status, high, low;
     static int high_lengths[] = {
@@ -102,7 +130,7 @@ midi_length(long msg)
         3, 3, 3, 3, 2, 2, 3, 1          /* 0x80 through 0xf0 */
     };
     static int low_lengths[] = {
-        1, 1, 3, 2, 1, 1, 1, 1,         /* 0xf0 through 0xf8 */
+        1, 2, 3, 2, 1, 1, 1, 1,         /* 0xf0 through 0xf8 */
         1, 1, 1, 1, 1, 1, 1, 1          /* 0xf9 through 0xff */
     };
 
@@ -110,7 +138,7 @@ midi_length(long msg)
     high = status >> 4;
     low = status & 15;
 
-    return (high != 0xF0) ? high_lengths[high] : low_lengths[low];
+    return (high != 0xF) ? high_lengths[high] : low_lengths[low];
 }
 
 static PmTimestamp midi_synchronize(PmInternal *midi)
@@ -237,7 +265,7 @@ readProc(const MIDIPacketList *newPackets, void *refCon, void *connRefCon)
     PmEvent event;
     MIDIPacket *packet;
     unsigned int packetIndex;
-    unsigned long now;
+    uint32_t now;
     unsigned int status;
     
 #ifdef CM_DEBUG
@@ -262,9 +290,9 @@ readProc(const MIDIPacketList *newPackets, void *refCon, void *connRefCon)
                packet->length); */
     for (packetIndex = 0; packetIndex < newPackets->numPackets; packetIndex++) {
         /* Set the timestamp and dispatch this message */
-        event.timestamp = 
+        event.timestamp = (PmTimestamp) /* explicit conversion */ (
                 (AudioConvertHostTimeToNanos(packet->timeStamp) - m->delta) / 
-                (UInt64) 1000000;
+                (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 */
@@ -305,9 +333,8 @@ midi_in_open(PmInternal *midi, void *driverInfo)
         /* time_get does not take a parameter, so coerce */
         midi->time_proc = (PmTimeProcPtr) Pt_Time;
     }
-    
-    endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
-    if (endpoint == NULL) {
+    endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
+    if (endpoint == NULL_REF) {
         return pmInvalidDeviceId;
     }
 
@@ -335,7 +362,7 @@ midi_in_open(PmInternal *midi, void *driverInfo)
         pm_hosterror = macHostError;
         sprintf(pm_hosterror_text, 
                 "Host error %ld: MIDIPortConnectSource() in midi_in_open()",
-                macHostError);
+                (long) macHostError);
         midi->descriptor = NULL;
         pm_free(m);
         return pmHostError;
@@ -355,8 +382,8 @@ midi_in_close(PmInternal *midi)
     
     if (!m) return pmBadPtr;
 
-    endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
-    if (endpoint == NULL) {
+    endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
+    if (endpoint == NULL_REF) {
         pm_hosterror = pmBadPtr;
     }
     
@@ -366,7 +393,7 @@ midi_in_close(PmInternal *midi)
         pm_hosterror = macHostError;
         sprintf(pm_hosterror_text, 
                 "Host error %ld: MIDIPortDisconnectSource() in midi_in_close()",
-                macHostError);
+                (long) macHostError);
         err = pmHostError;
     }
     
@@ -400,7 +427,11 @@ midi_out_open(PmInternal *midi, void *driverInfo)
     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;
 }
 
@@ -420,7 +451,18 @@ midi_out_close(PmInternal *midi)
 static PmError
 midi_abort(PmInternal *midi)
 {
-    return pmNoError;
+    PmError err = pmNoError;
+    OSStatus macHostError;
+    MIDIEndpointRef endpoint =
+            (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
+    macHostError = MIDIFlushOutput(endpoint);
+    if (macHostError != noErr) {
+        pm_hosterror = macHostError;
+        sprintf(pm_hosterror_text,
+                "Host error %ld: MIDIFlushOutput()", (long) macHostError);
+        err = pmHostError;
+    }
+    return err;
 }
 
 
@@ -430,13 +472,22 @@ midi_write_flush(PmInternal *midi, PmTimestamp timestamp)
     OSStatus macHostError;
     midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
     MIDIEndpointRef endpoint = 
-            (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
+            (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
     assert(m);
     assert(endpoint);
     if (m->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));
+        }
         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;
     }
     return pmNoError;
@@ -445,7 +496,7 @@ send_packet_error:
     pm_hosterror = macHostError;
     sprintf(pm_hosterror_text, 
             "Host error %ld: MIDISend() in midi_write()",
-            macHostError);
+            (long) macHostError);
     return pmHostError;
 
 }
@@ -459,15 +510,21 @@ send_packet(PmInternal *midi, Byte *message, unsigned int messageLength,
     midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
     assert(m);
     
-    /* printf("add %d to packet %lx len %d\n", message[0], m->packet, messageLength); */
+    /* 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) {
         /* 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; 
-        if ((err = midi_write_flush(midi, timestamp)) != pmNoError) return err;
+        /* 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),
@@ -482,8 +539,8 @@ send_packet(PmInternal *midi, Byte *message, unsigned int messageLength,
 static PmError
 midi_write_short(PmInternal *midi, PmEvent *event)
 {
-    long when = event->timestamp;
-    long what = event->message;
+    PmTimestamp when = event->timestamp;
+    PmMessage what = event->message;
     MIDITimeStamp timestamp;
     UInt64 when_ns;
     midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
@@ -502,9 +559,6 @@ midi_write_short(PmInternal *midi, PmEvent *event)
     /* 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;
-    /* make sure we don't go backward in time */
-    if (when_ns < m->last_time) when_ns = m->last_time;
-    m->last_time = when_ns;
     timestamp = (MIDITimeStamp) AudioConvertNanosToHostTime(when_ns);
 
     message[0] = Pm_MessageStatus(what);
@@ -512,6 +566,15 @@ midi_write_short(PmInternal *midi, PmEvent *event)
     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
+
     /* Add this message to the packet list */
     return send_packet(midi, message, messageLength, timestamp);
 }
@@ -549,16 +612,18 @@ midi_end_sysex(PmInternal *midi, PmTimestamp when)
     midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
     assert(m);
     
-    /* make sure we don't go backward in time */
-    if (m->sysex_timestamp < m->last_time) m->sysex_timestamp = m->last_time;
+    /* 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 flush has been called in the meantime, packet list is NULL */
-    if (m->packet == NULL) {
-        m->packet = MIDIPacketListInit(m->packetList);
-        assert(m->packet);
-    }
-
-        /* now send what's in the buffer */
+    /* 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;
@@ -656,9 +721,9 @@ CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal)
     CFRelease(str);
   }
   
-  MIDIEntityRef entity = NULL;
+  MIDIEntityRef entity = NULL_REF;
   MIDIEndpointGetEntity(endpoint, &entity);
-  if (entity == NULL)
+  if (entity == NULL_REF)
     // probably virtual
     return result;
   
@@ -672,13 +737,17 @@ CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal)
     }
   }
   // now consider the device's name
-  MIDIDeviceRef device = NULL;
+  MIDIDeviceRef device = NULL_REF;
   MIDIEntityGetDevice(entity, &device);
-  if (device == NULL)
+  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
@@ -686,6 +755,10 @@ CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal)
       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
@@ -703,6 +776,7 @@ CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal)
   return result;
 }
 
+
 // Obtain the name of an endpoint, following connections.
 // The result should be released by the caller.
 static CFStringRef ConnectedEndpointName(MIDIEndpointRef endpoint)
@@ -710,17 +784,17 @@ static CFStringRef ConnectedEndpointName(MIDIEndpointRef endpoint)
   CFMutableStringRef result = CFStringCreateMutable(NULL, 0);
   CFStringRef str;
   OSStatus err;
-  int i;
+  long i;
   
   // Does the endpoint have connections?
   CFDataRef connections = NULL;
-  int nConnected = 0;
+  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) / sizeof(MIDIUniqueID);
+    nConnected = CFDataGetLength(connections) / (int32_t) sizeof(MIDIUniqueID);
     if (nConnected) {
       const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections));
       for (i = 0; i < nConnected; ++i, ++pid) {
@@ -889,7 +963,7 @@ PmError pm_macosxcm_init(void)
     /* Iterate over the MIDI input devices */
     for (i = 0; i < numInputs; i++) {
         endpoint = MIDIGetSource(i);
-        if (endpoint == NULL) {
+        if (endpoint == NULL_REF) {
             continue;
         }
 
@@ -899,13 +973,13 @@ PmError pm_macosxcm_init(void)
         
         /* Register this device with PortMidi */
         pm_add_device("CoreMIDI", cm_get_full_endpoint_name(endpoint),
-                      TRUE, (void*)endpoint, &pm_macosx_in_dictionary);
+                      TRUE, (void *) (long) endpoint, &pm_macosx_in_dictionary);
     }
 
     /* Iterate over the MIDI output devices */
     for (i = 0; i < numOutputs; i++) {
         endpoint = MIDIGetDestination(i);
-        if (endpoint == NULL) {
+        if (endpoint == NULL_REF) {
             continue;
         }
 
@@ -915,20 +989,22 @@ PmError pm_macosxcm_init(void)
 
         /* Register this device with PortMidi */
         pm_add_device("CoreMIDI", cm_get_full_endpoint_name(endpoint),
-                      FALSE, (void*)endpoint, &pm_macosx_out_dictionary);
+                      FALSE, (void *) (long) endpoint,
+                      &pm_macosx_out_dictionary);
     }
     return pmNoError;
     
 error_return:
     pm_hosterror = macHostError;
-    sprintf(pm_hosterror_text, "Host error %ld: %s\n", macHostError, error_text);
+    sprintf(pm_hosterror_text, "Host error %ld: %s\n", (long) macHostError, 
+            error_text);
     pm_macosxcm_term(); /* clear out any opened ports */
     return pmHostError;
 }
 
 void pm_macosxcm_term(void)
 {
-    if (client != NULL)	 MIDIClientDispose(client);
-    if (portIn != NULL)	 MIDIPortDispose(portIn);
-    if (portOut != NULL) MIDIPortDispose(portOut);
+    if (client != NULL_REF) MIDIClientDispose(client);
+    if (portIn != NULL_REF) MIDIPortDispose(portIn);
+    if (portOut != NULL_REF) MIDIPortDispose(portOut);
 }
diff --git a/pd/portmidi/pm_mac/pmmacosxcm.h b/pd/portmidi/pm_mac/pmmacosxcm.h
old mode 100644
new mode 100755
index 1725935954b95092f0ee7d4953c9e879c3e16b01..97235b5dd203ac55c1a1293760d7bc1c4f6af73d
--- a/pd/portmidi/pm_mac/pmmacosxcm.h
+++ b/pd/portmidi/pm_mac/pmmacosxcm.h
@@ -1,4 +1,6 @@
 /* system-specific definitions */
 
 PmError pm_macosxcm_init(void);
-void pm_macosxcm_term(void);
\ No newline at end of file
+void pm_macosxcm_term(void);
+
+PmDeviceID find_default_device(char *path, int input, PmDeviceID id);
diff --git a/pd/portmidi/pm_mac/readbinaryplist.c b/pd/portmidi/pm_mac/readbinaryplist.c
new file mode 100644
index 0000000000000000000000000000000000000000..bccd09518310cace8b6fbba688d133639181ef39
--- /dev/null
+++ b/pd/portmidi/pm_mac/readbinaryplist.c
@@ -0,0 +1,1115 @@
+/*
+
+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.
+
+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.
+
+Copyright (C) 2007 Jens Ayton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+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 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.
+
+*/
+
+/* A note about memory management:
+Strings and possibly other values are unique and because the values
+associated with IDs are cached, you end up with a directed graph rather
+than a tree. It is tricky to free the data because if you do a simple
+depth-first search to free nodes, you will free nodes twice. I decided
+to allocate memory from blocks of 1024 bytes and keep the blocks in a
+list associated with but private to this module. So the user should
+access this module by calling:
+    bplist_read_file() or bplist_read_user_pref() or 
+    bplist_read_system_pref()
+which returns a value. When you are done with the value, call
+    bplist_free_data()
+This will of course free the value_ptr returned by bplist_read_*()
+
+To deal with memory exhaustion (what happens when malloc returns
+NULL?), use setjmp/longjmp -- a single setjmp protects the whole
+parser, and allocate uses longjmp to abort. After abort, memory
+is freed and NULL is returned to caller. There is not much here
+in the way of error reporting.
+
+Memory is obtained by calling allocate which either returns the
+memory requested or calls longjmp, so callers don't have to check.
+
+*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include "readbinaryplist.h"
+#include <Carbon/Carbon.h>
+
+#define NO 0
+#define YES 1
+#define BOOL int
+
+#define MAXPATHLEN 256
+
+/* there are 2 levels of error logging/printing:
+ *   BPLIST_LOG and BPLIST_LOG_VERBOSE
+ * either or both can be set to non-zero to turn on
+ * If BPLIST_LOG_VERBOSE is true, then BPLIST_LOG 
+ * is also true.
+ * 
+ * In the code, logging is done by calling either
+ * bplist_log() or bplist_log_verbose(), which take
+ * parameters like printf but might be a no-op.
+ */
+ 
+/* #define BPLIST_LOG_VERBOSE 1 */
+
+#if BPLIST_LOG_VERBOSE
+    #ifndef BPLIST_LOG
+        #define BPLIST_LOG 1
+    #endif
+#endif
+
+#if BPLIST_LOG
+    #define bplist_log printf
+#else
+    #define bplist_log(...)
+#endif
+
+#if BPLIST_LOG_VERBOSE
+    #define bplist_log_verbose bplist_log
+#else
+    #define bplist_log_verbose(...)
+#endif
+
+
+/********* MEMORY MANAGEMENT ********/
+#define BLOCK_SIZE 1024
+// memory is aligned to multiples of this; assume malloc automatically
+// aligns to this number and assume this number is > sizeof(void *)
+#define ALIGNMENT 8
+static void *block_list = NULL;
+static char *free_ptr = NULL;
+static char *end_ptr = NULL;
+static jmp_buf abort_parsing;
+
+static void *allocate(size_t size)
+{
+    void *result;
+    if (free_ptr + size > end_ptr) {
+        size_t how_much = BLOCK_SIZE;
+        // align everything to 8 bytes
+        if (size > BLOCK_SIZE - ALIGNMENT) {
+            how_much = size + ALIGNMENT;
+        }
+        result = malloc(how_much);
+        if (result == NULL) {
+            /* serious problem */
+            longjmp(abort_parsing, 1);
+        }
+        *((void **)result) = block_list;
+        block_list = result;
+        free_ptr = ((char *) result) + ALIGNMENT;
+        end_ptr = ((char *) result) + how_much;
+    }
+    // now, there is enough rooom at free_ptr
+    result = free_ptr;
+    free_ptr += size;
+    return result;
+}
+
+void bplist_free_data()
+{
+    while (block_list) {
+        void *next = *(void **)block_list;
+        free(block_list);
+        block_list = next;
+    }
+    free_ptr = NULL;
+    end_ptr = NULL;
+}
+
+// layout of trailer -- last 32 bytes in plist data
+    uint8_t unused[6];
+    uint8_t offset_int_size;
+    uint8_t object_ref_size;
+    uint64_t object_count;
+    uint64_t top_level_object;
+    uint64_t offset_table_offset;
+
+
+enum
+{
+    kHEADER_SIZE = 8,
+    kTRAILER_SIZE = 32, //sizeof(bplist_trailer_node),
+    kMINIMUM_SANE_SIZE = kHEADER_SIZE + kTRAILER_SIZE
+};
+
+
+static const char kHEADER_BYTES[kHEADER_SIZE] = "bplist00";
+
+// map from UID key to previously parsed value
+typedef struct cache_struct {
+    uint64_t key;
+    value_ptr value;
+    struct cache_struct *next;
+} cache_node, *cache_ptr;
+
+
+typedef struct bplist_info
+{
+    uint64_t object_count;
+    const uint8_t *data_bytes;
+    uint64_t length;
+    uint64_t offset_table_offset;
+    uint8_t offset_int_size;
+    uint8_t object_ref_size;
+    cache_ptr cache;
+} bplist_info_node, *bplist_info_ptr;
+
+
+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 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 value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef);
+static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_int(bplist_info_ptr bplist, uint64_t offset);
+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_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);
+
+
+value_ptr value_create()
+{
+    value_ptr value = (value_ptr) allocate(sizeof(value_node));
+    return value;
+}
+
+
+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);
+    memcpy(v->string, s, 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);
+    memcpy(v->string, s, len);
+    v->string[len] = 0;
+}
+
+void value_set_uid(value_ptr v, uint64_t uid)
+{
+    v->tag = kTAG_UID; v->uinteger = uid;
+}
+
+// v->data points to a pldata that points to the actual bytes
+// the bytes are copied, so caller must free byte source (*data)
+void value_set_data(value_ptr v, const uint8_t *data, size_t len) {
+    v->tag = kTAG_DATA;
+    pldata_ptr pldata = (pldata_ptr) allocate(sizeof(pldata_node));
+    pldata->data = (uint8_t *) allocate(len);
+    memcpy(pldata->data, data, len);
+    pldata->len = len;
+    v->data = pldata;
+    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) {
+    array_ptr a = (array_ptr) allocate(sizeof(array_node));
+    a->array = array;
+    a->length = length;
+    v->tag = kTAG_ARRAY;
+    v->array = a;
+}
+
+// caller releases ownership of dict to value_ptr v
+void value_set_dict(value_ptr v, dict_ptr dict) {
+    v->tag = kTAG_DICTIONARY;
+    v->dict = dict;
+}
+
+
+// look up an objectref in the cache, a ref->value_ptr mapping
+value_ptr cache_lookup(cache_ptr cache, uint64_t ref)
+{
+    while (cache) {
+        if (cache->key == ref) {
+            return cache->value;
+        }
+        cache = cache->next;
+    }
+    return NULL;
+}
+
+
+// insert an objectref and value in the cache
+void cache_insert(cache_ptr *cache, uint64_t ref, value_ptr value)
+{
+    cache_ptr c = (cache_ptr) allocate(sizeof(cache_node));
+    c->key = ref;
+    c->value = value;
+    c->next = *cache;
+    *cache = c;
+}
+
+
+// insert an objectref and value in a dictionary
+void dict_insert(dict_ptr *dict, value_ptr key, value_ptr value)
+{
+    dict_ptr d = (dict_ptr) allocate(sizeof(dict_node));
+    d->key = key;
+    d->value = value;
+    d->next = *dict;
+    *dict = d;
+}
+
+
+BOOL is_binary_plist(pldata_ptr data)
+{
+    if (data->len < kMINIMUM_SANE_SIZE)  return NO;
+    return memcmp(data->data, kHEADER_BYTES, kHEADER_SIZE) == 0;
+}
+
+
+value_ptr bplist_read_file(char *filename)
+{
+    struct stat stbuf;
+    pldata_node pldata;
+    FILE *file;
+    size_t n;
+    value_ptr value;
+    int rslt = stat(filename, &stbuf);
+    if (rslt) {
+        #if BPLIST_LOG
+            perror("in stat");
+        #endif
+        bplist_log("Could not stat %s, error %d\n", filename, rslt);
+        return NULL;
+    }
+    // if file is >100MB, assume it is not a preferences file and give up
+    if (stbuf.st_size > 100000000) {
+        bplist_log("Large file %s encountered (%llu bytes) -- not read\n",
+                   filename, stbuf.st_size);
+        return NULL;
+    }
+    pldata.len = (size_t) stbuf.st_size;
+    // note: this is supposed to be malloc, not allocate. It is separate
+    // from the graph structure, large, and easy to free right after
+    // parsing.
+    pldata.data = (uint8_t *) malloc(pldata.len);
+    if (!pldata.data) {
+        bplist_log("Could not allocate %lu bytes for %s\n",
+                   (unsigned long) pldata.len, filename);
+        return NULL;
+    }
+    file = fopen(filename, "rb");
+    if (!file) {
+        bplist_log("Could not open %s\n", filename);
+        return NULL;
+    }
+    n = fread(pldata.data, 1, pldata.len, file);
+    if (n != pldata.len) {
+        bplist_log("Error reading from %s\n", filename);
+        return NULL;
+    }
+    value = bplist_read_pldata(&pldata);
+    free(pldata.data);
+    return value;
+}
+
+
+value_ptr bplist_read_pref(char *filename, OSType folder_type)
+{
+    FSRef prefdir;
+    char cstr[MAXPATHLEN];
+
+    OSErr err = FSFindFolder(kOnAppropriateDisk, folder_type,
+                             FALSE, &prefdir);
+    if (err) {
+        bplist_log("Error finding preferences folder: %d\n", err);
+        return NULL;
+    }
+    err = FSRefMakePath(&prefdir, (UInt8 *) cstr, (UInt32) (MAXPATHLEN - 1));
+    if (err) {
+        bplist_log("Error making path name for preferences folder: %d\n", err);
+        return NULL;
+    }
+    strlcat(cstr, "/", MAXPATHLEN);
+    strlcat(cstr, filename, MAXPATHLEN);
+    return bplist_read_file(cstr);
+}
+
+
+value_ptr bplist_read_system_pref(char *filename) {
+    return bplist_read_pref(filename, kSystemPreferencesFolderType);
+}
+
+
+value_ptr bplist_read_user_pref(char *filename) {
+    return bplist_read_pref(filename, kPreferencesFolderType);
+}
+
+
+// data is stored with high-order bytes first.
+// read from plist data in a machine-independent fashion
+//
+uint64_t convert_uint64(uint8_t *ptr)
+{
+    uint64_t rslt = 0;
+    int i;
+    // shift in bytes, high-order first
+    for (i = 0; i < sizeof(uint64_t); i++) {
+        rslt <<= 8;
+        rslt += ptr[i];
+    }
+    return rslt;
+}
+
+
+value_ptr bplist_read_pldata(pldata_ptr data)
+{
+    value_ptr result = NULL;
+    bplist_info_node bplist;
+    uint8_t *ptr;
+    uint64_t top_level_object;
+    int i;
+
+    if (data == NULL)  return NULL;
+    if (!is_binary_plist(data)) {
+        bplist_log("Bad binary plist: too short or invalid header.\n");
+        return NULL;
+    }
+        
+    // read trailer
+    ptr = (uint8_t *) (data->data + data->len - kTRAILER_SIZE);
+    bplist.offset_int_size = ptr[6];
+    bplist.object_ref_size = ptr[7];
+    bplist.object_count = convert_uint64(ptr + 8);
+    top_level_object = convert_uint64(ptr + 16);
+    bplist.offset_table_offset = convert_uint64(ptr + 24);
+        
+    // Basic sanity checks
+    if (bplist.offset_int_size < 1 || bplist.offset_int_size > 8 ||
+        bplist.object_ref_size < 1 || bplist.object_ref_size > 8 ||
+        bplist.offset_table_offset < kHEADER_SIZE) {
+        bplist_log("Bad binary plist: trailer declared insane.\n");
+        return NULL;                
+    }
+        
+    // Ensure offset table is inside file
+    uint64_t offsetTableSize = bplist.offset_int_size * bplist.object_count;
+    if (offsetTableSize + bplist.offset_table_offset + kTRAILER_SIZE > 
+        data->len) {
+        bplist_log("Bad binary plist: offset table overlaps end of container.\n");
+        return NULL;
+    }
+        
+    bplist.data_bytes = data->data;
+    bplist.length = data->len;
+    bplist.cache = NULL; /* dictionary is empty */
+
+    bplist_log_verbose("Got a sane bplist with %llu items, offset_int_size: %u, object_ref_size: %u\n", 
+                      bplist.object_count, bplist.offset_int_size, 
+                      bplist.object_ref_size);
+    /* at this point, we are ready to do some parsing which allocates
+        memory for the result data structure. If memory allocation (using
+        allocate fails, a longjmp will return to here and we simply give up
+     */
+    i = setjmp(abort_parsing);
+    if (i == 0) {
+        result = extract_object(&bplist, top_level_object);
+    } else {
+        bplist_log("allocate() failed to allocate memory. Giving up.\n");
+        result = NULL;
+    }
+    if (!result) {
+        bplist_free_data();
+    }
+    return result;
+}
+
+
+static value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef)
+{
+    uint64_t offset;
+    value_ptr result = NULL;
+    uint8_t objectTag;
+    
+    if (objectRef >= bplist->object_count) {
+        // Out-of-range object reference.
+        bplist_log("Bad binary plist: object index is out of range.\n");
+        return NULL;
+    }
+        
+    // Use cached object if it exists
+    result = cache_lookup(bplist->cache, objectRef);
+    if (result != NULL)  return result;
+        
+    // Otherwise, find object in file.
+    offset = read_offset(bplist, objectRef);
+    if (offset > bplist->length) {
+        // Out-of-range offset.
+        bplist_log("Bad binary plist: object outside container.\n");
+        return NULL;
+    }
+    objectTag = *(bplist->data_bytes + offset);
+    switch (objectTag & 0xF0) {
+    case kTAG_SIMPLE:
+        result = extract_simple(bplist, offset);
+        break;
+                
+    case kTAG_INT:
+        result = extract_int(bplist, offset);
+        break;
+                        
+    case kTAG_REAL:
+        result = extract_real(bplist, offset);
+        break;
+                        
+    case kTAG_DATE:
+        result = extract_date(bplist, offset);
+        break;
+                        
+    case kTAG_DATA:
+        result = extract_data(bplist, offset);
+        break;
+                        
+    case kTAG_ASCIISTRING:
+        result = extract_ascii_string(bplist, offset);
+        break;
+                        
+    case kTAG_UNICODESTRING:
+        result = extract_unicode_string(bplist, offset);
+        break;
+        
+    case kTAG_UID:
+        result = extract_uid(bplist, offset);
+        break;
+        
+    case kTAG_ARRAY:
+        result = extract_array(bplist, offset);
+        break;
+        
+    case kTAG_DICTIONARY:
+        result = extract_dictionary(bplist, offset);
+        break;
+        
+    default:
+        // Unknown tag.
+        bplist_log("Bad binary plist: unknown tag 0x%X.\n", 
+                   (objectTag & 0x0F) >> 4);
+        result = NULL;
+    }
+    
+    // Cache and return result.
+    if (result != NULL)  
+        cache_insert(&bplist->cache, objectRef, result);
+    return result;
+}
+
+
+static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset, 
+                               uint8_t size)
+{
+    assert(bplist->data_bytes != NULL && size >= 1 && size <= 8 && 
+           offset + size <= bplist->length);
+        
+    uint64_t result = 0;
+    const uint8_t *byte = bplist->data_bytes + offset;
+        
+    do {
+        // note that ints seem to be high-order first
+        result = (result << 8) | *byte++;
+    } while (--size);
+        
+    return result;
+}
+
+
+static uint64_t read_offset(bplist_info_ptr bplist, uint64_t index)
+{
+    assert(index < bplist->object_count);
+        
+    return read_sized_int(bplist, 
+            bplist->offset_table_offset + bplist->offset_int_size * index, 
+            bplist->offset_int_size);
+}
+
+
+static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset, 
+                             uint64_t *outValue, size_t *outSize)
+{
+    uint32_t size;
+    int64_t value;
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+    size = 1 << (bplist->data_bytes[offset] & 0x0F);
+    if (size > 8) {
+        // Maximum allowable size in this implementation is 1<<3 = 8 bytes.
+        // This also happens to be the biggest we can handle.
+        return NO;
+    }
+        
+    if (offset + 1 + size > bplist->length) {
+        // Out of range.
+        return NO;
+    }
+        
+    value = read_sized_int(bplist, offset + 1, size);
+    
+    if (outValue != NULL) *outValue = value;
+    if (outSize != NULL) *outSize = size + 1; // +1 for tag byte.
+    return YES;
+}
+
+
+static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset)
+{
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+    value_ptr value = value_create();
+        
+    switch (bplist->data_bytes[offset]) {
+    case kVALUE_NULL:
+        value->tag = kVALUE_NULL;
+        return value;
+        
+    case kVALUE_TRUE:
+        value->tag = kVALUE_TRUE;
+        return value;
+                        
+    case kVALUE_FALSE:
+        value->tag = kVALUE_FALSE;
+        return value;
+    }
+        
+    // Note: kVALUE_FILLER is treated as invalid, because it, er, is.
+    bplist_log("Bad binary plist: invalid atom.\n");
+    free(value);
+    return NULL;
+}
+
+
+static value_ptr extract_int(bplist_info_ptr bplist, uint64_t offset)
+{
+    value_ptr value = value_create();
+    value->tag = kTAG_INT;
+
+    if (!read_self_sized_int(bplist, offset, &value->uinteger, NULL)) {
+        bplist_log("Bad binary plist: invalid integer object.\n");
+    }
+        
+    /* NOTE: originally, I sign-extended here. This was the wrong thing; it
+       turns out that negative ints are always stored as 64-bit, and smaller
+       ints are unsigned.
+    */
+    return value;
+}
+
+
+static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset)
+{
+    value_ptr value = value_create();
+    uint32_t size;
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+    
+    size = 1 << (bplist->data_bytes[offset] & 0x0F);
+        
+    // FIXME: what to do if faced with other sizes for float/double?
+    assert (sizeof (float) == sizeof (uint32_t) && 
+            sizeof (double) == sizeof (uint64_t));
+        
+    if (offset + 1 + size > bplist->length) {
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                  "floating-point number");
+        free(value);
+        return NULL;
+    }
+        
+    if (size == sizeof (float)) {
+        // cast is ok because we know size is 4 bytes
+        uint32_t i = (uint32_t) read_sized_int(bplist, offset + 1, size); 
+        // Note that this handles byte swapping.
+        value_set_real(value, *(float *)&i);
+        return value;
+    } else if (size == sizeof (double)) {
+        uint64_t i = read_sized_int(bplist, offset + 1, size);
+        // Note that this handles byte swapping.
+        value_set_real(value, *(double *)&i);
+        return value;
+    } else {
+        // Can't handle floats of other sizes.
+        bplist_log("Bad binary plist: can't handle %u-byte float.\n", size);
+        free(value);
+        return NULL;
+    }
+}
+
+
+static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset)
+{
+    value_ptr value;
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+    // Data has size code like int and real, but only 3 (meaning 8 bytes) is valid.
+    if (bplist->data_bytes[offset] != kVALUE_FULLDATETAG) {
+        bplist_log("Bad binary plist: invalid size for date object.\n");
+        return NULL;
+    }
+        
+    if (offset + 1 + sizeof (double) > bplist->length) {
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                  "date");
+        return NULL;
+    }
+        
+    // FIXME: what to do if faced with other sizes for double?
+    assert (sizeof (double) == sizeof (uint64_t));
+        
+    uint64_t date = read_sized_int(bplist, offset + 1, sizeof(double));
+    // Note that this handles byte swapping.
+    value = value_create();
+    value_set_date(value, *(double *)&date);
+    return value;
+}
+
+
+uint64_t bplist_get_a_size(bplist_info_ptr bplist, 
+                           uint64_t *offset_ptr, char *msg)
+{
+    uint64_t size = bplist->data_bytes[*offset_ptr] & 0x0F;
+    (*offset_ptr)++;
+    if (size == 0x0F) {
+        // 0x0F means separate int size follows. 
+        // Smaller values are used for short data.
+        size_t extra; // the length of the data size we are about to read
+        if ((bplist->data_bytes[*offset_ptr] & 0xF0) != kTAG_INT) {
+            // Bad data, mistagged size int
+            bplist_log("Bad binary plist: %s object size is not tagged as int.\n",
+                       msg);
+            return UINT64_MAX; // error
+        }
+                
+        // read integer data as size, extra tells how many bytes to skip
+        if (!read_self_sized_int(bplist, *offset_ptr, &size, &extra)) {
+            bplist_log("Bad binary plist: invalid %s object size tag.\n", 
+                      "data");
+            return UINT64_MAX; // error
+        }
+        (*offset_ptr) += extra;
+    }
+
+    if (*offset_ptr + size > bplist->length) {
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                  "data");
+        return UINT64_MAX; // error
+    }
+    return size;
+}
+
+
+static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset)
+{
+    uint64_t size;
+    value_ptr value;
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+    if ((size = bplist_get_a_size(bplist, &offset, "data")) == UINT64_MAX) 
+        return NULL;
+        
+    value = value_create();
+    // cast is ok because we only allow files up to 100MB:
+    value_set_data(value, bplist->data_bytes + (size_t) offset, (size_t) size);
+    return value;
+}
+
+
+static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset)
+{
+    uint64_t size;
+    value_ptr value; // return value
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+    if ((size = bplist_get_a_size(bplist, &offset, "ascii string")) ==
+        UINT64_MAX) 
+        return NULL;
+
+    value = value_create();
+    // cast is ok because we only allow 100MB files
+    value_set_ascii_string(value, bplist->data_bytes + (size_t) offset, 
+                           (size_t) size);
+    return value;
+}
+
+
+static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset)
+{
+    uint64_t size;
+    value_ptr value;
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+    if ((size = bplist_get_a_size(bplist, &offset, "unicode string")) == 
+        UINT64_MAX)
+        return NULL;
+        
+    value = value_create();
+    // cast is ok because we only allow 100MB files
+    value_set_unicode_string(value, bplist->data_bytes + (size_t) offset, 
+                             (size_t) size);
+    return value;
+}
+
+
+static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset)
+{
+    /* UIDs are used by Cocoa's key-value coder.
+       When writing other plist formats, they are expanded to dictionaries of
+       the form <dict><key>CF$UID</key><integer>value</integer></dict>, so we
+       do the same here on reading. This results in plists identical to what
+       running plutil -convert xml1 gives us. However, this is not the same
+       result as [Core]Foundation's plist parser, which extracts them as un-
+       introspectable CF objects. In fact, it even seems to convert the CF$UID
+       dictionaries from XML plists on the fly.
+    */
+        
+    value_ptr value;
+    uint64_t uid;
+        
+    if (!read_self_sized_int(bplist, offset, &uid, NULL)) {
+        bplist_log("Bad binary plist: invalid UID object.\n");
+        return NULL;
+    }
+        
+    // assert(NO); // original code suggests using a string for a key
+    // but our dictionaries all use big ints for keys, so I don't know
+    // what to do here
+    
+    // In practice, I believe this code is never executed by PortMidi.
+    // I changed it to do something and not raise compiler warnings, but
+    // not sure what the code should do.
+
+    value = value_create();
+    value_set_uid(value, uid);
+    // return [NSDictionary dictionaryWithObject:
+    //         [NSNumber numberWithUnsignedLongLong:value] 
+    //         forKey:"CF$UID"];
+    return value;
+}
+
+
+static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset)
+{
+    uint64_t i, count;
+    uint64_t size;
+    uint64_t elementID;
+    value_ptr element = NULL;
+    value_ptr *array = NULL;
+    value_ptr value = NULL;
+    BOOL ok = YES;
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+    if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX)
+        return NULL;
+        
+    if (count > UINT64_MAX / bplist->object_ref_size - offset) {
+        // Offset overflow.
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                   "array");
+        return NULL;
+    }
+        
+    size = bplist->object_ref_size * count;
+    if (size + offset > bplist->length) {
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                   "array");
+        return NULL;
+    }
+        
+    // got count, the number of array elements
+
+    value = value_create();
+    assert(value);
+
+    if (count == 0) {
+        // count must be size_t or smaller because max file size is 100MB
+        value_set_array(value, array, (size_t) count);
+        return value;
+    }
+        
+    array = allocate(sizeof(value_ptr) * (size_t) count);
+        
+    for (i = 0; i != count; ++i) {
+        bplist_log_verbose("[%u]\n", i);
+        elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size, 
+                                 bplist->object_ref_size);
+        element = extract_object(bplist, elementID);
+        if (element != NULL) {
+            array[i] = element;
+        } else {
+            ok = NO;
+            break;
+        }
+    }
+    if (ok) { // count is smaller than size_t max because of 100MB file limit
+        value_set_array(value, array, (size_t) count);
+    }
+
+    return value;
+}
+
+
+static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset)
+{
+    uint64_t i, count;
+    uint64_t size;
+    uint64_t elementID;
+    value_ptr value = NULL;
+    dict_ptr dict = NULL;
+    BOOL ok = YES;
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+        
+    if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX)
+        return NULL;
+
+    if (count > UINT64_MAX / (bplist->object_ref_size * 2) - offset) {
+        // Offset overflow.
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                   "dictionary");
+        return NULL;
+    }
+    
+    size = bplist->object_ref_size * count * 2;
+    if (size + offset > bplist->length) {
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                   "dictionary");
+        return NULL;
+    }
+    
+    value = value_create();
+    if (count == 0) {
+        value_set_dict(value, NULL);
+        return value;
+    }
+
+    for (i = 0; i != count; ++i) {
+        value_ptr key;
+        value_ptr val;
+        elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size, 
+                                 bplist->object_ref_size);
+        key = extract_object(bplist, elementID);
+        if (key != NULL) {
+            bplist_log_verbose("key: %p\n", key);
+        } else {
+            ok = NO;
+            break;
+        }
+                    
+        elementID = read_sized_int(bplist, 
+                            offset + (i + count) * bplist->object_ref_size, 
+                            bplist->object_ref_size);
+        val = extract_object(bplist, elementID);
+        if (val != NULL) {
+            dict_insert(&dict, key, val);
+        } else {
+            ok = NO;
+            break;
+        }
+    }
+    if (ok) {
+        value_set_dict(value, dict);
+    }
+    
+    return value;
+}
+
+/*************** functions for accessing values ****************/
+
+
+char *value_get_asciistring(value_ptr v)
+{
+    if (v->tag != kTAG_ASCIISTRING) return NULL;
+    return v->string;
+}
+
+
+value_ptr value_dict_lookup_using_string(value_ptr v, char *key)
+{
+    dict_ptr dict;
+    if (v->tag != kTAG_DICTIONARY) return NULL; // not a dictionary
+    dict = v->dict;
+    /* search for key */
+    while (dict) {
+        if (dict->key && dict->key->tag == kTAG_ASCIISTRING &&
+            strcmp(key, dict->key->string) == 0) { // found it
+            return dict->value;
+        }
+        dict = dict->next;
+    }
+    return NULL; /* not found */
+}
+
+value_ptr value_dict_lookup_using_path(value_ptr v, char *path)
+{
+    char key[MAX_KEY_SIZE];
+    while (*path) { /* more to the path */
+        int i = 0;
+        while (i < MAX_KEY_SIZE - 1) {
+            key[i] = *path++;
+            if (key[i] == '/') { /* end of entry in path */
+                key[i + 1] = 0;
+                break;
+            }
+            if (!key[i]) {
+                path--; /* back up to end of string char */
+                break;  /* this will cause outer loop to exit */
+            }
+            i++;
+        }
+        if (!v || v->tag != kTAG_DICTIONARY) return NULL;
+        /* now, look up the key to get next value */
+        v = value_dict_lookup_using_string(v, key);
+        if (v == NULL) return NULL;
+    }
+    return v;
+}
+                
+
+/*************** functions for debugging ***************/
+
+void plist_print(value_ptr v)
+{
+    size_t i;
+    int comma_needed;
+    dict_ptr dict;
+    if (!v) {
+        printf("NULL");
+        return;
+    }
+    switch (v->tag & 0xF0) {
+    case kTAG_SIMPLE:
+        switch (v->tag) {
+        case kVALUE_NULL: 
+            printf("NULL@%p", v); break;
+        case kVALUE_FALSE: 
+            printf("FALSE@%p", v); break;
+        case kVALUE_TRUE:
+            printf("TRUE@%p", v); break;
+        default:
+            printf("UNKNOWN tag=%x@%p", v->tag, v); break;
+        }
+        break;
+    case kTAG_INT:
+        printf("%lld@%p", v->integer, v); break;
+    case kTAG_REAL:
+        printf("%g@%p", v->real, v); break;
+    case kTAG_DATE:
+        printf("date:%g@%p", v->real, v); break;
+    case kTAG_DATA:
+        printf("data@%p->%p:[%p:", v, v->data, v->data->data);
+        for (i = 0; i < v->data->len; i++) {
+            printf(" %2x", v->data->data[i]);
+        }
+        printf("]"); break;
+    case kTAG_ASCIISTRING:
+        printf("%p:\"%s\"@%p", v->string, v->string, v); break;
+    case kTAG_UNICODESTRING:
+        printf("unicode:%p:\"%s\"@%p", v->string, v->string, v); break;
+    case kTAG_UID:
+        printf("UID:%llu@%p", v->uinteger, v); break;
+    case kTAG_ARRAY:
+        comma_needed = FALSE;
+        printf("%p->%p:[%p:", v, v->array, v->array->array);
+        for (i = 0; i < v->array->length; i++) {
+            if (comma_needed) printf(", ");
+            plist_print(v->array->array[i]);
+            comma_needed = TRUE;
+        }
+        printf("]"); break;
+    case kTAG_DICTIONARY:
+        comma_needed = FALSE;
+        printf("%p:[", v);
+        dict = v->dict;
+        while (dict) {
+            if (comma_needed) printf(", ");
+            printf("%p:", dict);
+            plist_print(dict->key);
+            printf("->");
+            plist_print(dict->value);
+            comma_needed = TRUE;
+            dict = dict->next;
+        }
+        printf("]"); break;
+    default:
+        printf("UNKNOWN tag=%x", v->tag);
+        break;
+    }
+}
+
+            
diff --git a/pd/portmidi/pm_mac/readbinaryplist.h b/pd/portmidi/pm_mac/readbinaryplist.h
new file mode 100644
index 0000000000000000000000000000000000000000..577865996b25a142636dbca538e72be11ff09de3
--- /dev/null
+++ b/pd/portmidi/pm_mac/readbinaryplist.h
@@ -0,0 +1,88 @@
+/* readbinaryplist.h -- header to read preference files
+
+   Roger B. Dannenberg, Jun 2008
+*/
+
+#include <stdint.h> /* for uint8_t ... */
+
+#ifndef TRUE
+    #define TRUE 1
+    #define FALSE 0
+#endif
+
+#define MAX_KEY_SIZE 256
+
+enum
+{
+    // Object tags (high nybble)
+    kTAG_SIMPLE = 0x00,        // Null, true, false, filler, or invalid
+    kTAG_INT = 0x10,
+    kTAG_REAL = 0x20,
+    kTAG_DATE = 0x30,
+    kTAG_DATA = 0x40,
+    kTAG_ASCIISTRING = 0x50,
+    kTAG_UNICODESTRING = 0x60,
+    kTAG_UID = 0x80,
+    kTAG_ARRAY = 0xA0,
+    kTAG_DICTIONARY = 0xD0,
+    
+    // "simple" object values
+    kVALUE_NULL = 0x00,
+    kVALUE_FALSE = 0x08,
+    kVALUE_TRUE = 0x09,
+    kVALUE_FILLER = 0x0F,
+    
+    kVALUE_FULLDATETAG = 0x33        // Dates are tagged with a whole byte.
+};
+
+
+typedef struct pldata_struct {
+    uint8_t *data;
+    size_t len;
+} pldata_node, *pldata_ptr;
+
+
+typedef struct array_struct {
+    struct value_struct **array;
+    uint64_t length;
+} array_node, *array_ptr;
+
+
+// a dict_node is a list of <key, value> pairs
+typedef struct dict_struct {
+    struct value_struct *key;
+    struct value_struct *value;
+    struct dict_struct *next;
+} dict_node, *dict_ptr;
+
+
+// an value_node is a value with a tag telling the type
+typedef struct value_struct {
+    int tag;
+    union {
+        int64_t integer;
+        uint64_t uinteger;
+        double real;
+        char *string;
+        pldata_ptr data;
+        array_ptr array;
+        struct dict_struct *dict;
+    };
+} 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);
+void bplist_free_data();
+
+/*************** 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);
+
+/*************** functions for debugging ***************/
+
+void plist_print(value_ptr v);
+
diff --git a/pd/portmidi/pm_mingw/README-MINGW.txt b/pd/portmidi/pm_mingw/README-MINGW.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e01a7fed441b4245d1328537e5eafa6d4e811a83
--- /dev/null
+++ b/pd/portmidi/pm_mingw/README-MINGW.txt
@@ -0,0 +1,11 @@
+README-MINGW.txt -- note on MinGW and PortMidi
+
+Roger Dannenberg
+20 Sep 2010
+
+Fabian Rutte writes that CMake can build files for Code::Blocks
+under MinGW.
+
+I would guess that a simple Unix Makefile output from CMake would
+also work, but I haven't tested it.
+
diff --git a/pd/portmidi/pm_mingw/eclipse/README.txt b/pd/portmidi/pm_mingw/eclipse/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2b58e13ab1739546262040837ce3ee45b2029d54
--- /dev/null
+++ b/pd/portmidi/pm_mingw/eclipse/README.txt
@@ -0,0 +1,23 @@
+These files, dot-cproject and dot-project, come from Philip Martin
+(posted on Media_api mailing list on September 3, 2008).
+He writes: "I do not have a makefile. I used Eclipse + CDT to build
+PortMidi using MinGw. ... The two files .project and .cproject I 
+believe must be in the root of the portmidi tree to work with Eclipse.
+... I have only compiled the relevant sources into one .dll here."
+
+The .project and .cproject files have been renamed to dot-project and
+dot-cproject here to make them more visible. To use them, you will
+need to rename them to .project and .cproject, and probably move them
+to the portmidi tree root.
+
+At this time, no one is actively maintaining Eclipse or MinGw versions
+of PortMidi, so these files may be out-of-date or have other problems.
+Feel free to submit updates or discuss the possibility of maintaining
+these or some equivalent files for MinGw.
+
+Update, 20 Sep 2010: CMake supports Code::Blocks in conjunction with
+MinGW.
+
+Roger Dannenberg
+18-Oct-2008
+
diff --git a/pd/portmidi/pm_mingw/eclipse/dot-cproject b/pd/portmidi/pm_mingw/eclipse/dot-cproject
new file mode 100644
index 0000000000000000000000000000000000000000..d99bff8bca51c80927e09f60af1451e01872e5ad
--- /dev/null
+++ b/pd/portmidi/pm_mingw/eclipse/dot-cproject
@@ -0,0 +1,710 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?>
+
+<cproject>
+<storageModule moduleId="org.eclipse.cdt.core.settings">
+<cconfiguration id="cdt.managedbuild.config.gnu.mingw.so.debug.1580321004">
+<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.mingw.so.debug.1580321004" moduleId="org.eclipse.cdt.core.settings" name="Debug">
+<externalSettings>
+<externalSetting>
+<entry flags="VALUE_WORKSPACE_PATH" kind="includePath" name="/PortMidi"/>
+<entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/PortMidi/Debug"/>
+</externalSetting>
+</externalSettings>
+<extensions>
+<extension id="org.eclipse.cdt.core.PE" point="org.eclipse.cdt.core.BinaryParser"/>
+<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+</extensions>
+</storageModule>
+<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+<configuration artifactExtension="dll" artifactName="PortMidi" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.sharedLib" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.sharedLib" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.mingw.so.debug.1580321004" name="Debug" parent="cdt.managedbuild.config.gnu.mingw.so.debug">
+<folderInfo id="cdt.managedbuild.config.gnu.mingw.so.debug.1580321004." name="/" resourcePath="">
+<toolChain id="cdt.managedbuild.toolchain.gnu.mingw.so.debug.1545417885" name="MinGW GCC" superClass="cdt.managedbuild.toolchain.gnu.mingw.so.debug">
+<targetPlatform id="cdt.managedbuild.target.gnu.platform.mingw.so.debug.415542300" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.mingw.so.debug"/>
+<builder buildPath="${workspace_loc:/PortMidi/Debug}" id="cdt.managedbuild.tool.gnu.builder.mingw.base.592172807" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="CDT Internal Builder" superClass="cdt.managedbuild.tool.gnu.builder.mingw.base"/>
+<tool id="cdt.managedbuild.tool.gnu.assembler.mingw.so.debug.1889129808" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.mingw.so.debug">
+<option id="gnu.both.asm.option.flags.1498736889" name="Assembler flags" superClass="gnu.both.asm.option.flags"/>
+<option id="gnu.both.asm.option.include.paths.1734867019" name="Include paths (-I)" superClass="gnu.both.asm.option.include.paths" valueType="includePath">
+<listOptionValue builtIn="false" value="&quot;${workspace_loc:/PortMidi/pm_common}&quot;"/>
+<listOptionValue builtIn="false" value="&quot;${workspace_loc:/PortMidi/pm_win}&quot;"/>
+<listOptionValue builtIn="false" value="&quot;${workspace_loc:/PortMidi/porttime}&quot;"/>
+</option>
+<option id="gnu.both.asm.option.warnings.nowarn.1657300607" name="Suppress warnings (-W)" superClass="gnu.both.asm.option.warnings.nowarn"/>
+<option id="gnu.both.asm.option.version.1995252368" name="Announce version (-v)" superClass="gnu.both.asm.option.version"/>
+<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1250436110" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.archiver.mingw.base.1211487028" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.mingw.base"/>
+<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.debug.81091790" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.debug">
+<option id="gnu.cpp.compiler.mingw.so.debug.option.optimization.level.1750954034" name="Optimization Level" superClass="gnu.cpp.compiler.mingw.so.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
+<option id="gnu.cpp.compiler.mingw.so.debug.option.debugging.level.1357163228" name="Debug Level" superClass="gnu.cpp.compiler.mingw.so.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.c.compiler.mingw.so.debug.428547337" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.mingw.so.debug">
+<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.mingw.so.debug.option.optimization.level.1361318269" name="Optimization Level" superClass="gnu.c.compiler.mingw.so.debug.option.optimization.level" valueType="enumerated"/>
+<option id="gnu.c.compiler.mingw.so.debug.option.debugging.level.798971050" name="Debug Level" superClass="gnu.c.compiler.mingw.so.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/>
+<option id="gnu.c.compiler.option.preprocessor.nostdinc.635731758" name="Do not search system directories (-nostdinc)" superClass="gnu.c.compiler.option.preprocessor.nostdinc"/>
+<option id="gnu.c.compiler.option.preprocessor.preprocess.1129104455" name="Preprocess only (-E)" superClass="gnu.c.compiler.option.preprocessor.preprocess"/>
+<option id="gnu.c.compiler.option.preprocessor.def.symbols.924940285" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols"/>
+<option id="gnu.c.compiler.option.preprocessor.undef.symbol.1996330931" name="Undefined symbols (-U)" superClass="gnu.c.compiler.option.preprocessor.undef.symbol" valueType="undefDefinedSymbols">
+<listOptionValue builtIn="false" value="_STDCALL_SUPPORTED"/>
+</option>
+<option id="gnu.c.compiler.option.include.paths.276080219" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" valueType="includePath">
+<listOptionValue builtIn="false" value="&quot;${workspace_loc:/PortMidi/pm_common}&quot;"/>
+<listOptionValue builtIn="false" value="&quot;${workspace_loc:/PortMidi/pm_win}&quot;"/>
+<listOptionValue builtIn="false" value="&quot;${workspace_loc:/PortMidi/porttime}&quot;"/>
+</option>
+<option id="gnu.c.compiler.option.optimization.flags.1032442929" name="Other optimization flags" superClass="gnu.c.compiler.option.optimization.flags"/>
+<option id="gnu.c.compiler.option.debugging.other.509079500" name="Other debugging flags" superClass="gnu.c.compiler.option.debugging.other"/>
+<option id="gnu.c.compiler.option.debugging.gprof.708510440" name="Generate gprof information (-pg)" superClass="gnu.c.compiler.option.debugging.gprof"/>
+<option id="gnu.c.compiler.option.debugging.prof.1379528770" name="Generate prof information (-p)" superClass="gnu.c.compiler.option.debugging.prof"/>
+<option id="gnu.c.compiler.option.warnings.syntax.76950723" name="Check syntax only (-fsyntax-only)" superClass="gnu.c.compiler.option.warnings.syntax"/>
+<option id="gnu.c.compiler.option.warnings.pedantic.503180272" name="Pedantic (-pedantic)" superClass="gnu.c.compiler.option.warnings.pedantic"/>
+<option id="gnu.c.compiler.option.warnings.pedantic.error.332437973" name="Pedantic warnings as errors (-pedantic-errors)" superClass="gnu.c.compiler.option.warnings.pedantic.error"/>
+<option id="gnu.c.compiler.option.warnings.nowarn.1830350073" name="Inhibit all warnings (-w)" superClass="gnu.c.compiler.option.warnings.nowarn"/>
+<option id="gnu.c.compiler.option.warnings.allwarn.77655170" name="All warnings (-Wall)" superClass="gnu.c.compiler.option.warnings.allwarn"/>
+<option id="gnu.c.compiler.option.warnings.toerrors.1707691615" name="Warnings as errors (-Werror)" superClass="gnu.c.compiler.option.warnings.toerrors"/>
+<option id="gnu.c.compiler.option.misc.other.1929071594" name="Other flags" superClass="gnu.c.compiler.option.misc.other"/>
+<option id="gnu.c.compiler.option.misc.verbose.1368165423" name="Verbose (-v)" superClass="gnu.c.compiler.option.misc.verbose"/>
+<option id="gnu.c.compiler.option.misc.ansi.1130235771" name="Support ANSI programs (-ansi)" superClass="gnu.c.compiler.option.misc.ansi"/>
+<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.532732416" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.c.linker.mingw.so.debug.2093989251" name="MinGW C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.mingw.so.debug">
+<option defaultValue="true" id="gnu.c.link.mingw.so.debug.option.shared.210833175" name="Shared (-shared)" superClass="gnu.c.link.mingw.so.debug.option.shared" valueType="boolean"/>
+<option id="gnu.c.link.option.nostart.1109377759" name="Do not use standard start files (-nostartfiles)" superClass="gnu.c.link.option.nostart"/>
+<option id="gnu.c.link.option.nodeflibs.1969639513" name="Do not use default libraries (-nodefaultlibs)" superClass="gnu.c.link.option.nodeflibs"/>
+<option id="gnu.c.link.option.nostdlibs.1939458836" name="No startup or default libs (-nostdlib)" superClass="gnu.c.link.option.nostdlibs"/>
+<option id="gnu.c.link.option.strip.1926939147" name="Omit all symbol information (-s)" superClass="gnu.c.link.option.strip"/>
+<option id="gnu.c.link.option.noshared.1390204753" name="No shared libraries (-static)" superClass="gnu.c.link.option.noshared"/>
+<option id="gnu.c.link.option.libs.2043660134" name="Libraries (-l)" superClass="gnu.c.link.option.libs" valueType="libs">
+<listOptionValue builtIn="false" value="winmm"/>
+</option>
+<option id="gnu.c.link.option.paths.1702926265" name="Library search path (-L)" superClass="gnu.c.link.option.paths"/>
+<option id="gnu.c.link.option.ldflags.1184725311" name="Linker flags" superClass="gnu.c.link.option.ldflags" value="-mwindows" valueType="string"/>
+<option id="gnu.c.link.option.other.2085141015" name="Other options (-Xlinker [option])" superClass="gnu.c.link.option.other"/>
+<option id="gnu.c.link.option.userobjs.1490648701" name="Other objects" superClass="gnu.c.link.option.userobjs"/>
+<option id="gnu.c.link.option.soname.437120219" name="Shared object name (-Wl,-soname=)" superClass="gnu.c.link.option.soname" value="PortMidi.dll" valueType="string"/>
+<option id="gnu.c.link.option.implname.205634723" name="Import Library name (-Wl,--out-implib=)" superClass="gnu.c.link.option.implname" value="libPortMidi_dll.a" valueType="string"/>
+<option id="gnu.c.link.option.defname.571020719" name="DEF file name (-Wl,--output-def=)" superClass="gnu.c.link.option.defname" value="PortMidi_dll.def" valueType="string"/>
+<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.916986463" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
+<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+</inputType>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.debug.1822206806" name="MinGW C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.debug">
+<option defaultValue="true" id="gnu.cpp.link.mingw.so.debug.option.shared.408251443" name="Shared (-shared)" superClass="gnu.cpp.link.mingw.so.debug.option.shared" valueType="boolean"/>
+</tool>
+</toolChain>
+</folderInfo>
+<sourceEntries>
+<entry excluding="pm_cl/|pm_linux/|pm_mac/|pm_test/|porttime/ptlinux.c|porttime/ptmacosx_cf.c|porttime/ptmacosx_mach.c" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
+</sourceEntries>
+</configuration>
+</storageModule>
+<storageModule moduleId="scannerConfiguration">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.release.413200248;cdt.managedbuild.config.gnu.mingw.so.release.413200248.;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.release.343495978;cdt.managedbuild.tool.gnu.c.compiler.input.611335297">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+</scannerConfigBuildInfo>
+<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.debug.1580321004;cdt.managedbuild.config.gnu.mingw.so.debug.1580321004.;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.debug.428547337;cdt.managedbuild.tool.gnu.c.compiler.input.532732416">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+</scannerConfigBuildInfo>
+</storageModule>
+<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
+</cconfiguration>
+<cconfiguration id="cdt.managedbuild.config.gnu.mingw.so.release.413200248">
+<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.mingw.so.release.413200248" moduleId="org.eclipse.cdt.core.settings" name="Release">
+<externalSettings>
+<externalSetting>
+<entry flags="VALUE_WORKSPACE_PATH" kind="includePath" name="/PortMidi"/>
+<entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/PortMidi/Release"/>
+</externalSetting>
+</externalSettings>
+<extensions>
+<extension id="org.eclipse.cdt.core.PE" point="org.eclipse.cdt.core.BinaryParser"/>
+<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+</extensions>
+</storageModule>
+<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+<configuration artifactExtension="dll" artifactName="PortMidi" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.sharedLib" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.sharedLib" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.mingw.so.release.413200248" name="Release" parent="cdt.managedbuild.config.gnu.mingw.so.release">
+<folderInfo id="cdt.managedbuild.config.gnu.mingw.so.release.413200248." name="/" resourcePath="">
+<toolChain id="cdt.managedbuild.toolchain.gnu.mingw.so.release.965704931" name="MinGW GCC" superClass="cdt.managedbuild.toolchain.gnu.mingw.so.release">
+<targetPlatform id="cdt.managedbuild.target.gnu.platform.mingw.so.release.1343771960" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.mingw.so.release"/>
+<builder buildPath="${workspace_loc:/PortMidi/Release}" id="cdt.managedbuild.tool.gnu.builder.mingw.base.1650720234" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="CDT Internal Builder" superClass="cdt.managedbuild.tool.gnu.builder.mingw.base"/>
+<tool id="cdt.managedbuild.tool.gnu.assembler.mingw.so.release.1392864745" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.mingw.so.release">
+<option id="gnu.both.asm.option.include.paths.591264871" name="Include paths (-I)" superClass="gnu.both.asm.option.include.paths" valueType="includePath">
+<listOptionValue builtIn="false" value="&quot;${workspace_loc:/PortMidi/pm_common}&quot;"/>
+<listOptionValue builtIn="false" value="&quot;${workspace_loc:/PortMidi/pm_win}&quot;"/>
+<listOptionValue builtIn="false" value="&quot;${workspace_loc:/PortMidi/porttime}&quot;"/>
+</option>
+<option id="gnu.both.asm.option.flags.1143807089" superClass="gnu.both.asm.option.flags"/>
+<option id="gnu.both.asm.option.warnings.nowarn.1142377463" superClass="gnu.both.asm.option.warnings.nowarn"/>
+<option id="gnu.both.asm.option.version.1007025248" superClass="gnu.both.asm.option.version"/>
+<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1754592443" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.archiver.mingw.base.503109969" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.mingw.base"/>
+<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.release.1693369280" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.so.release">
+<option id="gnu.cpp.compiler.mingw.so.release.option.optimization.level.1169326010" name="Optimization Level" superClass="gnu.cpp.compiler.mingw.so.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
+<option id="gnu.cpp.compiler.mingw.so.release.option.debugging.level.1197288488" name="Debug Level" superClass="gnu.cpp.compiler.mingw.so.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.c.compiler.mingw.so.release.343495978" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.mingw.so.release">
+<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.mingw.so.release.option.optimization.level.79718900" name="Optimization Level" superClass="gnu.c.compiler.mingw.so.release.option.optimization.level" valueType="enumerated"/>
+<option id="gnu.c.compiler.mingw.so.release.option.debugging.level.778378875" name="Debug Level" superClass="gnu.c.compiler.mingw.so.release.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/>
+<option id="gnu.c.compiler.option.include.paths.140256948" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" valueType="includePath">
+<listOptionValue builtIn="false" value="&quot;${workspace_loc:/PortMidi/pm_common}&quot;"/>
+<listOptionValue builtIn="false" value="&quot;${workspace_loc:/PortMidi/pm_win}&quot;"/>
+<listOptionValue builtIn="false" value="&quot;${workspace_loc:/PortMidi/porttime}&quot;"/>
+</option>
+<option id="gnu.c.compiler.option.preprocessor.def.symbols.960115196" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols"/>
+<option id="gnu.c.compiler.option.preprocessor.undef.symbol.1891593123" name="Undefined symbols (-U)" superClass="gnu.c.compiler.option.preprocessor.undef.symbol" valueType="undefDefinedSymbols">
+<listOptionValue builtIn="false" value="_STDCALL_SUPPORTED"/>
+</option>
+<option id="gnu.c.compiler.option.preprocessor.nostdinc.824573539" name="Do not search system directories (-nostdinc)" superClass="gnu.c.compiler.option.preprocessor.nostdinc"/>
+<option id="gnu.c.compiler.option.preprocessor.preprocess.2045908914" name="Preprocess only (-E)" superClass="gnu.c.compiler.option.preprocessor.preprocess"/>
+<option id="gnu.c.compiler.option.optimization.flags.1668114371" name="Other optimization flags" superClass="gnu.c.compiler.option.optimization.flags"/>
+<option id="gnu.c.compiler.option.debugging.other.26702882" name="Other debugging flags" superClass="gnu.c.compiler.option.debugging.other"/>
+<option id="gnu.c.compiler.option.debugging.gprof.1849481872" name="Generate gprof information (-pg)" superClass="gnu.c.compiler.option.debugging.gprof"/>
+<option id="gnu.c.compiler.option.debugging.prof.370891777" name="Generate prof information (-p)" superClass="gnu.c.compiler.option.debugging.prof"/>
+<option id="gnu.c.compiler.option.warnings.syntax.814238128" name="Check syntax only (-fsyntax-only)" superClass="gnu.c.compiler.option.warnings.syntax"/>
+<option id="gnu.c.compiler.option.warnings.pedantic.1130364543" name="Pedantic (-pedantic)" superClass="gnu.c.compiler.option.warnings.pedantic"/>
+<option id="gnu.c.compiler.option.warnings.pedantic.error.1833423377" name="Pedantic warnings as errors (-pedantic-errors)" superClass="gnu.c.compiler.option.warnings.pedantic.error"/>
+<option id="gnu.c.compiler.option.warnings.nowarn.842847161" name="Inhibit all warnings (-w)" superClass="gnu.c.compiler.option.warnings.nowarn"/>
+<option id="gnu.c.compiler.option.warnings.allwarn.1245259653" name="All warnings (-Wall)" superClass="gnu.c.compiler.option.warnings.allwarn"/>
+<option id="gnu.c.compiler.option.warnings.toerrors.329299856" name="Warnings as errors (-Werror)" superClass="gnu.c.compiler.option.warnings.toerrors"/>
+<option id="gnu.c.compiler.option.misc.other.1436833008" name="Other flags" superClass="gnu.c.compiler.option.misc.other"/>
+<option id="gnu.c.compiler.option.misc.verbose.1418051288" name="Verbose (-v)" superClass="gnu.c.compiler.option.misc.verbose"/>
+<option id="gnu.c.compiler.option.misc.ansi.592723919" name="Support ANSI programs (-ansi)" superClass="gnu.c.compiler.option.misc.ansi"/>
+<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.611335297" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.c.linker.mingw.so.release.556134685" name="MinGW C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.mingw.so.release">
+<option defaultValue="true" id="gnu.c.link.mingw.so.release.option.shared.1619560956" name="Shared (-shared)" superClass="gnu.c.link.mingw.so.release.option.shared" valueType="boolean"/>
+<option id="gnu.c.link.option.ldflags.1804407715" name="Linker flags" superClass="gnu.c.link.option.ldflags" value="-mwindows" valueType="string"/>
+<option id="gnu.c.link.option.soname.621315524" name="Shared object name (-Wl,-soname=)" superClass="gnu.c.link.option.soname" value="PortMidi.dll" valueType="string"/>
+<option id="gnu.c.link.option.implname.236027258" name="Import Library name (-Wl,--out-implib=)" superClass="gnu.c.link.option.implname" value="libPortMidi_dll.a" valueType="string"/>
+<option id="gnu.c.link.option.defname.1144978768" name="DEF file name (-Wl,--output-def=)" superClass="gnu.c.link.option.defname" value="PortMidi_dll.def" valueType="string"/>
+<option id="gnu.c.link.option.nostart.623404099" name="Do not use standard start files (-nostartfiles)" superClass="gnu.c.link.option.nostart"/>
+<option id="gnu.c.link.option.nodeflibs.51119036" name="Do not use default libraries (-nodefaultlibs)" superClass="gnu.c.link.option.nodeflibs"/>
+<option id="gnu.c.link.option.nostdlibs.2099774502" name="No startup or default libs (-nostdlib)" superClass="gnu.c.link.option.nostdlibs"/>
+<option id="gnu.c.link.option.strip.1270839234" name="Omit all symbol information (-s)" superClass="gnu.c.link.option.strip"/>
+<option id="gnu.c.link.option.noshared.715377715" name="No shared libraries (-static)" superClass="gnu.c.link.option.noshared"/>
+<option id="gnu.c.link.option.libs.246748928" name="Libraries (-l)" superClass="gnu.c.link.option.libs" valueType="libs">
+<listOptionValue builtIn="false" value="winmm"/>
+</option>
+<option id="gnu.c.link.option.paths.1166408208" name="Library search path (-L)" superClass="gnu.c.link.option.paths"/>
+<option id="gnu.c.link.option.other.1932058041" name="Other options (-Xlinker [option])" superClass="gnu.c.link.option.other"/>
+<option id="gnu.c.link.option.userobjs.1397357824" name="Other objects" superClass="gnu.c.link.option.userobjs"/>
+<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.363448189" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
+<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+</inputType>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release.1088983873" name="MinGW C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.mingw.so.release">
+<option defaultValue="true" id="gnu.cpp.link.mingw.so.release.option.shared.2023092585" name="Shared (-shared)" superClass="gnu.cpp.link.mingw.so.release.option.shared" valueType="boolean"/>
+</tool>
+</toolChain>
+</folderInfo>
+<sourceEntries>
+<entry excluding="pm_cl/|pm_linux/|pm_mac/|pm_test/|porttime/ptlinux.c|porttime/ptmacosx_cf.c|porttime/ptmacosx_mach.c" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
+</sourceEntries>
+</configuration>
+</storageModule>
+<storageModule moduleId="scannerConfiguration">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.release.413200248;cdt.managedbuild.config.gnu.mingw.so.release.413200248.;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.release.343495978;cdt.managedbuild.tool.gnu.c.compiler.input.611335297">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+</scannerConfigBuildInfo>
+<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.so.debug.1580321004;cdt.managedbuild.config.gnu.mingw.so.debug.1580321004.;cdt.managedbuild.tool.gnu.c.compiler.mingw.so.debug.428547337;cdt.managedbuild.tool.gnu.c.compiler.input.532732416">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+</scannerConfigBuildInfo>
+</storageModule>
+<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
+</cconfiguration>
+</storageModule>
+<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+<project id="PortMidi.cdt.managedbuild.target.gnu.mingw.so.812075522" name="Shared Library" projectType="cdt.managedbuild.target.gnu.mingw.so"/>
+</storageModule>
+</cproject>
diff --git a/pd/portmidi/pm_mingw/eclipse/dot-project b/pd/portmidi/pm_mingw/eclipse/dot-project
new file mode 100644
index 0000000000000000000000000000000000000000..6a3994f6feef5f95fa94ab0b195ca9bcf277f772
--- /dev/null
+++ b/pd/portmidi/pm_mingw/eclipse/dot-project
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>PortMidi</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+			<triggers>clean,full,incremental,</triggers>
+			<arguments>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.contents</key>
+					<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildLocation</key>
+					<value>${workspace_loc:/PortMidi/Debug}</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableFullBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
+					<value>false</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.append_environment</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>?name?</key>
+					<value></value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.stopOnError</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildArguments</key>
+					<value></value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildCommand</key>
+					<value>make</value>
+				</dictionary>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+		<nature>org.eclipse.cdt.core.cnature</nature>
+	</natures>
+</projectDescription>
diff --git a/pd/portmidi/pm_mingw/msys/README-MSYS.txt b/pd/portmidi/pm_mingw/msys/README-MSYS.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6f3cd69daa73b7da56ed7346279fb46bb0f7c510
--- /dev/null
+++ b/pd/portmidi/pm_mingw/msys/README-MSYS.txt
@@ -0,0 +1,8 @@
+Old code was removed from this directory because CMake provides an
+up-to-date way to use MinGW. See portmidi/pm_mingw/README-MINGW.txt.
+
+Roger Dannenberg
+20-Sep-2010
+
+
+
diff --git a/pd/portmidi/pm_python/README_PYTHON.txt b/pd/portmidi/pm_python/README_PYTHON.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3030dd2d68912c9b33a94e2115c2f517ae18ce52
--- /dev/null
+++ b/pd/portmidi/pm_python/README_PYTHON.txt
@@ -0,0 +1,34 @@
+PyPortMidi v0.03 03/15/05
+Python wrappings for PortMidi
+John Harrison
+harrison@media.mit.edu
+
+Modified by Roger B. Dannenberg, Nov 2009
+
+PyPortMidi
+----------
+
+PyPortMidi is a Python wrapper for PortMidi. PortMidi is a cross-platform
+C library for realtime MIDI control. Using PyPortMidi, you can send and
+receive MIDI data in realtime from Python.
+
+Besides using PyPortMidi to communicate to synthesizers and the
+like, it is possible to use PyPortMidi as a way to send MIDI messages
+between software packages on the same computer. For example, Using
+PyPortMidi and MIDI-YOKE on a Windows machine, it is possible to send
+realtime MIDI messages between programs on the same computer using
+loopback virtual MIDI ports. (At this time, MIDI-YOKE does not appear
+to run on Windows Vista.)
+
+PyPortMidi is cross-platform, but it will require some small
+changes in the setup.py file for it to install correctly on Linux
+machines. The changes should be pretty straightforward, and I am
+anxious to work with a Linux user on the port.
+
+PyPortMidi works with Python 2.6 and Python 3.1, although the ports
+are mostly separate because of various language incompatibilities.
+
+Please see README26.txt for information about the Python 2.6 version.
+
+See README31.txt for information about the Python 3.1 version.
+
diff --git a/pd/portmidi/pm_python/pyportmidi/__init__.py b/pd/portmidi/pm_python/pyportmidi/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..0f3fc4b44cdfbff3cdb288bd60fe921a2cde7b02
--- /dev/null
+++ b/pd/portmidi/pm_python/pyportmidi/__init__.py
@@ -0,0 +1,3 @@
+
+from .midi import *
+
diff --git a/pd/portmidi/pm_python/pyportmidi/_pyportmidi.c b/pd/portmidi/pm_python/pyportmidi/_pyportmidi.c
new file mode 100644
index 0000000000000000000000000000000000000000..7d700349e1840e4b56152722a33eed2377beba9d
--- /dev/null
+++ b/pd/portmidi/pm_python/pyportmidi/_pyportmidi.c
@@ -0,0 +1,5663 @@
+/* Generated by Cython 0.12.1 on Sun Sep 26 13:30:09 2010 */
+
+#define PY_SSIZE_T_CLEAN
+#include "Python.h"
+#include "structmember.h"
+#ifndef Py_PYTHON_H
+    #error Python headers needed to compile C extensions, please install development version of Python.
+#else
+
+#ifndef PY_LONG_LONG
+  #define PY_LONG_LONG LONG_LONG
+#endif
+#ifndef DL_EXPORT
+  #define DL_EXPORT(t) t
+#endif
+#if PY_VERSION_HEX < 0x02040000
+  #define METH_COEXIST 0
+  #define PyDict_CheckExact(op) (Py_TYPE(op) == &PyDict_Type)
+  #define PyDict_Contains(d,o)   PySequence_Contains(d,o)
+#endif
+
+#if PY_VERSION_HEX < 0x02050000
+  typedef int Py_ssize_t;
+  #define PY_SSIZE_T_MAX INT_MAX
+  #define PY_SSIZE_T_MIN INT_MIN
+  #define PY_FORMAT_SIZE_T ""
+  #define PyInt_FromSsize_t(z) PyInt_FromLong(z)
+  #define PyInt_AsSsize_t(o)   PyInt_AsLong(o)
+  #define PyNumber_Index(o)    PyNumber_Int(o)
+  #define PyIndex_Check(o)     PyNumber_Check(o)
+  #define PyErr_WarnEx(category, message, stacklevel) PyErr_Warn(category, message)
+#endif
+
+#if PY_VERSION_HEX < 0x02060000
+  #define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt)
+  #define Py_TYPE(ob)   (((PyObject*)(ob))->ob_type)
+  #define Py_SIZE(ob)   (((PyVarObject*)(ob))->ob_size)
+  #define PyVarObject_HEAD_INIT(type, size) \
+          PyObject_HEAD_INIT(type) size,
+  #define PyType_Modified(t)
+
+  typedef struct {
+     void *buf;
+     PyObject *obj;
+     Py_ssize_t len;
+     Py_ssize_t itemsize;
+     int readonly;
+     int ndim;
+     char *format;
+     Py_ssize_t *shape;
+     Py_ssize_t *strides;
+     Py_ssize_t *suboffsets;
+     void *internal;
+  } Py_buffer;
+
+  #define PyBUF_SIMPLE 0
+  #define PyBUF_WRITABLE 0x0001
+  #define PyBUF_FORMAT 0x0004
+  #define PyBUF_ND 0x0008
+  #define PyBUF_STRIDES (0x0010 | PyBUF_ND)
+  #define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES)
+  #define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES)
+  #define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES)
+  #define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES)
+
+#endif
+
+#if PY_MAJOR_VERSION < 3
+  #define __Pyx_BUILTIN_MODULE_NAME "__builtin__"
+#else
+  #define __Pyx_BUILTIN_MODULE_NAME "builtins"
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+  #define Py_TPFLAGS_CHECKTYPES 0
+  #define Py_TPFLAGS_HAVE_INDEX 0
+#endif
+
+#if (PY_VERSION_HEX < 0x02060000) || (PY_MAJOR_VERSION >= 3)
+  #define Py_TPFLAGS_HAVE_NEWBUFFER 0
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+  #define PyBaseString_Type            PyUnicode_Type
+  #define PyString_Type                PyUnicode_Type
+  #define PyString_CheckExact          PyUnicode_CheckExact
+#else
+  #define PyBytes_Type                 PyString_Type
+  #define PyBytes_CheckExact           PyString_CheckExact
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+  #define PyInt_Type                   PyLong_Type
+  #define PyInt_Check(op)              PyLong_Check(op)
+  #define PyInt_CheckExact(op)         PyLong_CheckExact(op)
+  #define PyInt_FromString             PyLong_FromString
+  #define PyInt_FromUnicode            PyLong_FromUnicode
+  #define PyInt_FromLong               PyLong_FromLong
+  #define PyInt_FromSize_t             PyLong_FromSize_t
+  #define PyInt_FromSsize_t            PyLong_FromSsize_t
+  #define PyInt_AsLong                 PyLong_AsLong
+  #define PyInt_AS_LONG                PyLong_AS_LONG
+  #define PyInt_AsSsize_t              PyLong_AsSsize_t
+  #define PyInt_AsUnsignedLongMask     PyLong_AsUnsignedLongMask
+  #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask
+  #define __Pyx_PyNumber_Divide(x,y)         PyNumber_TrueDivide(x,y)
+  #define __Pyx_PyNumber_InPlaceDivide(x,y)  PyNumber_InPlaceTrueDivide(x,y)
+#else
+  #define __Pyx_PyNumber_Divide(x,y)         PyNumber_Divide(x,y)
+  #define __Pyx_PyNumber_InPlaceDivide(x,y)  PyNumber_InPlaceDivide(x,y)
+
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+  #define PyMethod_New(func, self, klass) PyInstanceMethod_New(func)
+#endif
+
+#if !defined(WIN32) && !defined(MS_WINDOWS)
+  #ifndef __stdcall
+    #define __stdcall
+  #endif
+  #ifndef __cdecl
+    #define __cdecl
+  #endif
+  #ifndef __fastcall
+    #define __fastcall
+  #endif
+#else
+  #define _USE_MATH_DEFINES
+#endif
+
+#if PY_VERSION_HEX < 0x02050000
+  #define __Pyx_GetAttrString(o,n)   PyObject_GetAttrString((o),((char *)(n)))
+  #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),((char *)(n)),(a))
+  #define __Pyx_DelAttrString(o,n)   PyObject_DelAttrString((o),((char *)(n)))
+#else
+  #define __Pyx_GetAttrString(o,n)   PyObject_GetAttrString((o),(n))
+  #define __Pyx_SetAttrString(o,n,a) PyObject_SetAttrString((o),(n),(a))
+  #define __Pyx_DelAttrString(o,n)   PyObject_DelAttrString((o),(n))
+#endif
+
+#if PY_VERSION_HEX < 0x02050000
+  #define __Pyx_NAMESTR(n) ((char *)(n))
+  #define __Pyx_DOCSTR(n)  ((char *)(n))
+#else
+  #define __Pyx_NAMESTR(n) (n)
+  #define __Pyx_DOCSTR(n)  (n)
+#endif
+#ifdef __cplusplus
+#define __PYX_EXTERN_C extern "C"
+#else
+#define __PYX_EXTERN_C extern
+#endif
+#include <math.h>
+#define __PYX_HAVE_API___pyportmidi
+#include "portmidi.h"
+#include "porttime.h"
+
+#ifndef CYTHON_INLINE
+  #if defined(__GNUC__)
+    #define CYTHON_INLINE __inline__
+  #elif defined(_MSC_VER)
+    #define CYTHON_INLINE __inline
+  #else
+    #define CYTHON_INLINE 
+  #endif
+#endif
+
+typedef struct {PyObject **p; char *s; const long n; const char* encoding; const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; /*proto*/
+
+
+/* Type Conversion Predeclarations */
+
+#if PY_MAJOR_VERSION < 3
+#define __Pyx_PyBytes_FromString          PyString_FromString
+#define __Pyx_PyBytes_FromStringAndSize   PyString_FromStringAndSize
+#define __Pyx_PyBytes_AsString            PyString_AsString
+#else
+#define __Pyx_PyBytes_FromString          PyBytes_FromString
+#define __Pyx_PyBytes_FromStringAndSize   PyBytes_FromStringAndSize
+#define __Pyx_PyBytes_AsString            PyBytes_AsString
+#endif
+
+#define __Pyx_PyBytes_FromUString(s)      __Pyx_PyBytes_FromString((char*)s)
+#define __Pyx_PyBytes_AsUString(s)        ((unsigned char*) __Pyx_PyBytes_AsString(s))
+
+#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
+static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
+static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x);
+
+#if !defined(T_PYSSIZET)
+#if PY_VERSION_HEX < 0x02050000
+#define T_PYSSIZET T_INT
+#elif !defined(T_LONGLONG)
+#define T_PYSSIZET \
+        ((sizeof(Py_ssize_t) == sizeof(int))  ? T_INT  : \
+        ((sizeof(Py_ssize_t) == sizeof(long)) ? T_LONG : -1))
+#else
+#define T_PYSSIZET \
+        ((sizeof(Py_ssize_t) == sizeof(int))          ? T_INT      : \
+        ((sizeof(Py_ssize_t) == sizeof(long))         ? T_LONG     : \
+        ((sizeof(Py_ssize_t) == sizeof(PY_LONG_LONG)) ? T_LONGLONG : -1)))
+#endif
+#endif
+
+
+#if !defined(T_ULONGLONG)
+#define __Pyx_T_UNSIGNED_INT(x) \
+        ((sizeof(x) == sizeof(unsigned char))  ? T_UBYTE : \
+        ((sizeof(x) == sizeof(unsigned short)) ? T_USHORT : \
+        ((sizeof(x) == sizeof(unsigned int))   ? T_UINT : \
+        ((sizeof(x) == sizeof(unsigned long))  ? T_ULONG : -1))))
+#else
+#define __Pyx_T_UNSIGNED_INT(x) \
+        ((sizeof(x) == sizeof(unsigned char))  ? T_UBYTE : \
+        ((sizeof(x) == sizeof(unsigned short)) ? T_USHORT : \
+        ((sizeof(x) == sizeof(unsigned int))   ? T_UINT : \
+        ((sizeof(x) == sizeof(unsigned long))  ? T_ULONG : \
+        ((sizeof(x) == sizeof(unsigned PY_LONG_LONG)) ? T_ULONGLONG : -1)))))
+#endif
+#if !defined(T_LONGLONG)
+#define __Pyx_T_SIGNED_INT(x) \
+        ((sizeof(x) == sizeof(char))  ? T_BYTE : \
+        ((sizeof(x) == sizeof(short)) ? T_SHORT : \
+        ((sizeof(x) == sizeof(int))   ? T_INT : \
+        ((sizeof(x) == sizeof(long))  ? T_LONG : -1))))
+#else
+#define __Pyx_T_SIGNED_INT(x) \
+        ((sizeof(x) == sizeof(char))  ? T_BYTE : \
+        ((sizeof(x) == sizeof(short)) ? T_SHORT : \
+        ((sizeof(x) == sizeof(int))   ? T_INT : \
+        ((sizeof(x) == sizeof(long))  ? T_LONG : \
+        ((sizeof(x) == sizeof(PY_LONG_LONG))   ? T_LONGLONG : -1)))))
+#endif
+
+#define __Pyx_T_FLOATING(x) \
+        ((sizeof(x) == sizeof(float)) ? T_FLOAT : \
+        ((sizeof(x) == sizeof(double)) ? T_DOUBLE : -1))
+
+#if !defined(T_SIZET)
+#if !defined(T_ULONGLONG)
+#define T_SIZET \
+        ((sizeof(size_t) == sizeof(unsigned int))  ? T_UINT  : \
+        ((sizeof(size_t) == sizeof(unsigned long)) ? T_ULONG : -1))
+#else
+#define T_SIZET \
+        ((sizeof(size_t) == sizeof(unsigned int))          ? T_UINT      : \
+        ((sizeof(size_t) == sizeof(unsigned long))         ? T_ULONG     : \
+        ((sizeof(size_t) == sizeof(unsigned PY_LONG_LONG)) ? T_ULONGLONG : -1)))
+#endif
+#endif
+
+static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*);
+static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t);
+static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject*);
+
+#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x))
+
+
+#ifdef __GNUC__
+/* Test for GCC > 2.95 */
+#if __GNUC__ > 2 ||               (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)) 
+#define likely(x)   __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#else /* __GNUC__ > 2 ... */
+#define likely(x)   (x)
+#define unlikely(x) (x)
+#endif /* __GNUC__ > 2 ... */
+#else /* __GNUC__ */
+#define likely(x)   (x)
+#define unlikely(x) (x)
+#endif /* __GNUC__ */
+    
+static PyObject *__pyx_m;
+static PyObject *__pyx_b;
+static PyObject *__pyx_empty_tuple;
+static PyObject *__pyx_empty_bytes;
+static int __pyx_lineno;
+static int __pyx_clineno = 0;
+static const char * __pyx_cfilenm= __FILE__;
+static const char *__pyx_filename;
+static const char **__pyx_f;
+
+
+/* Type declarations */
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":394
+ * 
+ * 
+ * cdef class Input:             # <<<<<<<<<<<<<<
+ *     """
+ * class Input:
+ */
+
+struct __pyx_obj_11_pyportmidi_Input {
+  PyObject_HEAD
+  PmStream *midi;
+  int debug;
+  int i;
+};
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":201
+ *     return Pm_Channel(chan-1)
+ * 
+ * cdef class Output:             # <<<<<<<<<<<<<<
+ *     """
+ * class Output:
+ */
+
+struct __pyx_obj_11_pyportmidi_Output {
+  PyObject_HEAD
+  int i;
+  PmStream *midi;
+  int debug;
+  int _aborted;
+};
+
+#ifndef CYTHON_REFNANNY
+  #define CYTHON_REFNANNY 0
+#endif
+
+#if CYTHON_REFNANNY
+  typedef struct {
+    void (*INCREF)(void*, PyObject*, int);
+    void (*DECREF)(void*, PyObject*, int);
+    void (*GOTREF)(void*, PyObject*, int);
+    void (*GIVEREF)(void*, PyObject*, int);
+    void* (*SetupContext)(const char*, int, const char*);
+    void (*FinishContext)(void**);
+  } __Pyx_RefNannyAPIStruct;
+  static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL;
+  static __Pyx_RefNannyAPIStruct * __Pyx_RefNannyImportAPI(const char *modname) {
+    PyObject *m = NULL, *p = NULL;
+    void *r = NULL;
+    m = PyImport_ImportModule((char *)modname);
+    if (!m) goto end;
+    p = PyObject_GetAttrString(m, (char *)"RefNannyAPI");
+    if (!p) goto end;
+    r = PyLong_AsVoidPtr(p);
+  end:
+    Py_XDECREF(p);
+    Py_XDECREF(m);
+    return (__Pyx_RefNannyAPIStruct *)r;
+  }
+  #define __Pyx_RefNannySetupContext(name)           void *__pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__)
+  #define __Pyx_RefNannyFinishContext()           __Pyx_RefNanny->FinishContext(&__pyx_refnanny)
+  #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
+  #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
+  #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
+  #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
+  #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r);} } while(0)
+#else
+  #define __Pyx_RefNannySetupContext(name)
+  #define __Pyx_RefNannyFinishContext()
+  #define __Pyx_INCREF(r) Py_INCREF(r)
+  #define __Pyx_DECREF(r) Py_DECREF(r)
+  #define __Pyx_GOTREF(r)
+  #define __Pyx_GIVEREF(r)
+  #define __Pyx_XDECREF(r) Py_XDECREF(r)
+#endif /* CYTHON_REFNANNY */
+#define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);} } while(0)
+#define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r);} } while(0)
+
+static void __Pyx_RaiseDoubleKeywordsError(
+    const char* func_name, PyObject* kw_name); /*proto*/
+
+static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
+    Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); /*proto*/
+
+static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],     PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,     const char* function_name); /*proto*/
+
+
+static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
+    PyObject *r;
+    if (!j) return NULL;
+    r = PyObject_GetItem(o, j);
+    Py_DECREF(j);
+    return r;
+}
+
+
+#define __Pyx_GetItemInt_List(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \
+                                                    __Pyx_GetItemInt_List_Fast(o, i, size <= sizeof(long)) : \
+                                                    __Pyx_GetItemInt_Generic(o, to_py_func(i)))
+
+static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, int fits_long) {
+    if (likely(o != Py_None)) {
+        if (likely((0 <= i) & (i < PyList_GET_SIZE(o)))) {
+            PyObject *r = PyList_GET_ITEM(o, i);
+            Py_INCREF(r);
+            return r;
+        }
+        else if ((-PyList_GET_SIZE(o) <= i) & (i < 0)) {
+            PyObject *r = PyList_GET_ITEM(o, PyList_GET_SIZE(o) + i);
+            Py_INCREF(r);
+            return r;
+        }
+    }
+    return __Pyx_GetItemInt_Generic(o, fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i));
+}
+
+#define __Pyx_GetItemInt_Tuple(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \
+                                                    __Pyx_GetItemInt_Tuple_Fast(o, i, size <= sizeof(long)) : \
+                                                    __Pyx_GetItemInt_Generic(o, to_py_func(i)))
+
+static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, int fits_long) {
+    if (likely(o != Py_None)) {
+        if (likely((0 <= i) & (i < PyTuple_GET_SIZE(o)))) {
+            PyObject *r = PyTuple_GET_ITEM(o, i);
+            Py_INCREF(r);
+            return r;
+        }
+        else if ((-PyTuple_GET_SIZE(o) <= i) & (i < 0)) {
+            PyObject *r = PyTuple_GET_ITEM(o, PyTuple_GET_SIZE(o) + i);
+            Py_INCREF(r);
+            return r;
+        }
+    }
+    return __Pyx_GetItemInt_Generic(o, fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i));
+}
+
+
+#define __Pyx_GetItemInt(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \
+                                                    __Pyx_GetItemInt_Fast(o, i, size <= sizeof(long)) : \
+                                                    __Pyx_GetItemInt_Generic(o, to_py_func(i)))
+
+static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int fits_long) {
+    PyObject *r;
+    if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) {
+        r = PyList_GET_ITEM(o, i);
+        Py_INCREF(r);
+    }
+    else if (PyTuple_CheckExact(o) && ((0 <= i) & (i < PyTuple_GET_SIZE(o)))) {
+        r = PyTuple_GET_ITEM(o, i);
+        Py_INCREF(r);
+    }
+    else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_item && (likely(i >= 0))) {
+        r = PySequence_GetItem(o, i);
+    }
+    else {
+        r = __Pyx_GetItemInt_Generic(o, fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i));
+    }
+    return r;
+}
+
+static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
+    if (likely(PyList_CheckExact(L))) {
+        if (PyList_Append(L, x) < 0) return NULL;
+        Py_INCREF(Py_None);
+        return Py_None; /* this is just to have an accurate signature */
+    }
+    else {
+        PyObject *r, *m;
+        m = __Pyx_GetAttrString(L, "append");
+        if (!m) return NULL;
+        r = PyObject_CallFunctionObjArgs(m, x, NULL);
+        Py_DECREF(m);
+        return r;
+    }
+}
+
+static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/
+
+static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PmDeviceID(PmDeviceID);
+
+static CYTHON_INLINE PmDeviceID __Pyx_PyInt_from_py_PmDeviceID(PyObject *);
+
+static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PtTimestamp(PtTimestamp);
+
+static int __Pyx_Print(PyObject *, int); /*proto*/
+#if PY_MAJOR_VERSION >= 3
+static PyObject* __pyx_print = 0;
+static PyObject* __pyx_print_kwargs = 0;
+#endif
+
+static int __Pyx_PrintOne(PyObject *o); /*proto*/
+
+static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/
+
+static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
+static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
+
+static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
+
+static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PmMessage(PmMessage);
+
+static CYTHON_INLINE PmMessage __Pyx_PyInt_from_py_PmMessage(PyObject *);
+
+static CYTHON_INLINE PmTimestamp __Pyx_PyInt_from_py_PmTimestamp(PyObject *);
+
+static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PmTimestamp(PmTimestamp);
+
+static CYTHON_INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject *);
+
+static CYTHON_INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject *);
+
+static CYTHON_INLINE unsigned int __Pyx_PyInt_AsUnsignedInt(PyObject *);
+
+static CYTHON_INLINE char __Pyx_PyInt_AsChar(PyObject *);
+
+static CYTHON_INLINE short __Pyx_PyInt_AsShort(PyObject *);
+
+static CYTHON_INLINE int __Pyx_PyInt_AsInt(PyObject *);
+
+static CYTHON_INLINE signed char __Pyx_PyInt_AsSignedChar(PyObject *);
+
+static CYTHON_INLINE signed short __Pyx_PyInt_AsSignedShort(PyObject *);
+
+static CYTHON_INLINE signed int __Pyx_PyInt_AsSignedInt(PyObject *);
+
+static CYTHON_INLINE unsigned long __Pyx_PyInt_AsUnsignedLong(PyObject *);
+
+static CYTHON_INLINE unsigned PY_LONG_LONG __Pyx_PyInt_AsUnsignedLongLong(PyObject *);
+
+static CYTHON_INLINE long __Pyx_PyInt_AsLong(PyObject *);
+
+static CYTHON_INLINE PY_LONG_LONG __Pyx_PyInt_AsLongLong(PyObject *);
+
+static CYTHON_INLINE signed long __Pyx_PyInt_AsSignedLong(PyObject *);
+
+static CYTHON_INLINE signed PY_LONG_LONG __Pyx_PyInt_AsSignedLongLong(PyObject *);
+
+static void __Pyx_AddTraceback(const char *funcname); /*proto*/
+
+static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
+/* Module declarations from _pyportmidi */
+
+static PyTypeObject *__pyx_ptype_11_pyportmidi_Output = 0;
+static PyTypeObject *__pyx_ptype_11_pyportmidi_Input = 0;
+#define __Pyx_MODULE_NAME "_pyportmidi"
+int __pyx_module_is_main__pyportmidi = 0;
+
+/* Implementation of _pyportmidi */
+static PyObject *__pyx_builtin_Exception;
+static PyObject *__pyx_builtin_IndexError;
+static PyObject *__pyx_builtin_range;
+static char __pyx_k_1[] = "Opening Midi Output";
+static char __pyx_k_2[] = "Unable to open Midi OutputDevice=";
+static char __pyx_k_3[] = " err=";
+static char __pyx_k_4[] = "Closing MIDI output stream and destroying instance";
+static char __pyx_k_5[] = "midi Output not open.";
+static char __pyx_k_6[] = "midi Output aborted.  Need to call Close after Abort.";
+static char __pyx_k_7[] = "maximum list length is 1024";
+static char __pyx_k_8[] = " arguments in event list";
+static char __pyx_k_9[] = " : ";
+static char __pyx_k_10[] = "writing to midi buffer";
+static char __pyx_k_11[] = "Writing to MIDI buffer";
+static char __pyx_k_12[] = "MIDI input opened.";
+static char __pyx_k_13[] = "Closing MIDI input stream and destroying instance";
+static char __pyx_k_14[] = "midi Input not open.";
+static char __pyx_k_15[] = "maximum buffer length is 1024";
+static char __pyx_k_16[] = "minimum buffer length is 1";
+static char __pyx_k_17[] = "0.07";
+static char __pyx_k_18[] = "FILT_CHANNEL_AFTERTOUCH";
+static char __pyx_k_19[] = "FILT_POLY_AFTERTOUCH";
+static char __pyx_k_20[] = "Initialize (line 132)";
+static char __pyx_k_21[] = "Terminate (line 139)";
+static char __pyx_k_22[] = "GetDeviceInfo (line 156)";
+static char __pyx_k_23[] = "Time (line 173)";
+static char __pyx_k_24[] = "GetErrorText (line 180)";
+static char __pyx_k_25[] = "Channel (line 187)";
+static char __pyx_k_26[] = "Output._check_open (line 248)";
+static char __pyx_k_27[] = "Output.Close (line 258)";
+static char __pyx_k_28[] = "Output.Abort (line 274)";
+static char __pyx_k_29[] = "Output.Write (line 293)";
+static char __pyx_k_30[] = "Output.WriteShort (line 333)";
+static char __pyx_k_31[] = "Output.WriteSysEx (line 356)";
+static char __pyx_k_32[] = "Input._check_open (line 422)";
+static char __pyx_k_33[] = "Input.Close (line 430)";
+static char __pyx_k_34[] = "Input.SetFilter (line 447)";
+static char __pyx_k_35[] = "Input.SetChannelMask (line 481)";
+static char __pyx_k_36[] = "Input.Poll (line 502)";
+static char __pyx_k_37[] = "Input.Read (line 514)";
+static char __pyx_k__B[] = "B";
+static char __pyx_k__i[] = "i";
+static char __pyx_k__msg[] = "msg";
+static char __pyx_k__Poll[] = "Poll";
+static char __pyx_k__Read[] = "Read";
+static char __pyx_k__TRUE[] = "TRUE";
+static char __pyx_k__Time[] = "Time";
+static char __pyx_k__midi[] = "midi";
+static char __pyx_k__name[] = "name";
+static char __pyx_k__when[] = "when";
+static char __pyx_k__Abort[] = "Abort";
+static char __pyx_k__Close[] = "Close";
+static char __pyx_k__FALSE[] = "FALSE";
+static char __pyx_k__Input[] = "Input";
+static char __pyx_k__Write[] = "Write";
+static char __pyx_k__array[] = "array";
+static char __pyx_k__data1[] = "data1";
+static char __pyx_k__data2[] = "data2";
+static char __pyx_k__debug[] = "debug";
+static char __pyx_k__input[] = "input";
+static char __pyx_k__range[] = "range";
+static char __pyx_k__Output[] = "Output";
+static char __pyx_k__interf[] = "interf";
+static char __pyx_k__opened[] = "opened";
+static char __pyx_k__output[] = "output";
+static char __pyx_k__status[] = "status";
+static char __pyx_k__Channel[] = "Channel";
+static char __pyx_k__FILT_F9[] = "FILT_F9";
+static char __pyx_k__FILT_FD[] = "FILT_FD";
+static char __pyx_k__latency[] = "latency";
+static char __pyx_k__message[] = "message";
+static char __pyx_k__FILT_MTC[] = "FILT_MTC";
+static char __pyx_k____main__[] = "__main__";
+static char __pyx_k____test__[] = "__test__";
+static char __pyx_k___aborted[] = "_aborted";
+static char __pyx_k__tostring[] = "tostring";
+static char __pyx_k__Exception[] = "Exception";
+static char __pyx_k__FILT_NOTE[] = "FILT_NOTE";
+static char __pyx_k__FILT_PLAY[] = "FILT_PLAY";
+static char __pyx_k__FILT_TICK[] = "FILT_TICK";
+static char __pyx_k__FILT_TUNE[] = "FILT_TUNE";
+static char __pyx_k__SetFilter[] = "SetFilter";
+static char __pyx_k__Terminate[] = "Terminate";
+static char __pyx_k__timestamp[] = "timestamp";
+static char __pyx_k__FILT_CLOCK[] = "FILT_CLOCK";
+static char __pyx_k__FILT_RESET[] = "FILT_RESET";
+static char __pyx_k__FILT_SYSEX[] = "FILT_SYSEX";
+static char __pyx_k__IndexError[] = "IndexError";
+static char __pyx_k__Initialize[] = "Initialize";
+static char __pyx_k__WriteShort[] = "WriteShort";
+static char __pyx_k__WriteSysEx[] = "WriteSysEx";
+static char __pyx_k__buffersize[] = "buffersize";
+static char __pyx_k__FILT_ACTIVE[] = "FILT_ACTIVE";
+static char __pyx_k__InputDevice[] = "InputDevice";
+static char __pyx_k____version__[] = "__version__";
+static char __pyx_k___check_open[] = "_check_open";
+static char __pyx_k__FILT_CONTROL[] = "FILT_CONTROL";
+static char __pyx_k__FILT_PROGRAM[] = "FILT_PROGRAM";
+static char __pyx_k__GetErrorText[] = "GetErrorText";
+static char __pyx_k__OutputDevice[] = "OutputDevice";
+static char __pyx_k__FILT_REALTIME[] = "FILT_REALTIME";
+static char __pyx_k__GetDeviceInfo[] = "GetDeviceInfo";
+static char __pyx_k__FILT_PITCHBEND[] = "FILT_PITCHBEND";
+static char __pyx_k__FILT_UNDEFINED[] = "FILT_UNDEFINED";
+static char __pyx_k__SetChannelMask[] = "SetChannelMask";
+static char __pyx_k__FILT_AFTERTOUCH[] = "FILT_AFTERTOUCH";
+static char __pyx_k__FILT_SONG_SELECT[] = "FILT_SONG_SELECT";
+static char __pyx_k__FILT_SONG_POSITION[] = "FILT_SONG_POSITION";
+static PyObject *__pyx_kp_s_1;
+static PyObject *__pyx_kp_s_10;
+static PyObject *__pyx_kp_s_11;
+static PyObject *__pyx_kp_s_12;
+static PyObject *__pyx_kp_s_13;
+static PyObject *__pyx_kp_s_14;
+static PyObject *__pyx_kp_s_15;
+static PyObject *__pyx_kp_s_16;
+static PyObject *__pyx_kp_s_17;
+static PyObject *__pyx_n_s_18;
+static PyObject *__pyx_n_s_19;
+static PyObject *__pyx_kp_s_2;
+static PyObject *__pyx_kp_u_20;
+static PyObject *__pyx_kp_u_21;
+static PyObject *__pyx_kp_u_22;
+static PyObject *__pyx_kp_u_23;
+static PyObject *__pyx_kp_u_24;
+static PyObject *__pyx_kp_u_25;
+static PyObject *__pyx_kp_u_26;
+static PyObject *__pyx_kp_u_27;
+static PyObject *__pyx_kp_u_28;
+static PyObject *__pyx_kp_u_29;
+static PyObject *__pyx_kp_s_3;
+static PyObject *__pyx_kp_u_30;
+static PyObject *__pyx_kp_u_31;
+static PyObject *__pyx_kp_u_32;
+static PyObject *__pyx_kp_u_33;
+static PyObject *__pyx_kp_u_34;
+static PyObject *__pyx_kp_u_35;
+static PyObject *__pyx_kp_u_36;
+static PyObject *__pyx_kp_u_37;
+static PyObject *__pyx_kp_s_4;
+static PyObject *__pyx_kp_s_5;
+static PyObject *__pyx_kp_s_6;
+static PyObject *__pyx_kp_s_7;
+static PyObject *__pyx_kp_s_8;
+static PyObject *__pyx_kp_s_9;
+static PyObject *__pyx_n_s__Abort;
+static PyObject *__pyx_n_s__B;
+static PyObject *__pyx_n_s__Channel;
+static PyObject *__pyx_n_s__Close;
+static PyObject *__pyx_n_s__Exception;
+static PyObject *__pyx_n_s__FALSE;
+static PyObject *__pyx_n_s__FILT_ACTIVE;
+static PyObject *__pyx_n_s__FILT_AFTERTOUCH;
+static PyObject *__pyx_n_s__FILT_CLOCK;
+static PyObject *__pyx_n_s__FILT_CONTROL;
+static PyObject *__pyx_n_s__FILT_F9;
+static PyObject *__pyx_n_s__FILT_FD;
+static PyObject *__pyx_n_s__FILT_MTC;
+static PyObject *__pyx_n_s__FILT_NOTE;
+static PyObject *__pyx_n_s__FILT_PITCHBEND;
+static PyObject *__pyx_n_s__FILT_PLAY;
+static PyObject *__pyx_n_s__FILT_PROGRAM;
+static PyObject *__pyx_n_s__FILT_REALTIME;
+static PyObject *__pyx_n_s__FILT_RESET;
+static PyObject *__pyx_n_s__FILT_SONG_POSITION;
+static PyObject *__pyx_n_s__FILT_SONG_SELECT;
+static PyObject *__pyx_n_s__FILT_SYSEX;
+static PyObject *__pyx_n_s__FILT_TICK;
+static PyObject *__pyx_n_s__FILT_TUNE;
+static PyObject *__pyx_n_s__FILT_UNDEFINED;
+static PyObject *__pyx_n_s__GetDeviceInfo;
+static PyObject *__pyx_n_s__GetErrorText;
+static PyObject *__pyx_n_s__IndexError;
+static PyObject *__pyx_n_s__Initialize;
+static PyObject *__pyx_n_s__Input;
+static PyObject *__pyx_n_s__InputDevice;
+static PyObject *__pyx_n_s__Output;
+static PyObject *__pyx_n_s__OutputDevice;
+static PyObject *__pyx_n_s__Poll;
+static PyObject *__pyx_n_s__Read;
+static PyObject *__pyx_n_s__SetChannelMask;
+static PyObject *__pyx_n_s__SetFilter;
+static PyObject *__pyx_n_s__TRUE;
+static PyObject *__pyx_n_s__Terminate;
+static PyObject *__pyx_n_s__Time;
+static PyObject *__pyx_n_s__Write;
+static PyObject *__pyx_n_s__WriteShort;
+static PyObject *__pyx_n_s__WriteSysEx;
+static PyObject *__pyx_n_s____main__;
+static PyObject *__pyx_n_s____test__;
+static PyObject *__pyx_n_s____version__;
+static PyObject *__pyx_n_s___aborted;
+static PyObject *__pyx_n_s___check_open;
+static PyObject *__pyx_n_s__array;
+static PyObject *__pyx_n_s__buffersize;
+static PyObject *__pyx_n_s__data1;
+static PyObject *__pyx_n_s__data2;
+static PyObject *__pyx_n_s__debug;
+static PyObject *__pyx_n_s__i;
+static PyObject *__pyx_n_s__input;
+static PyObject *__pyx_n_s__interf;
+static PyObject *__pyx_n_s__latency;
+static PyObject *__pyx_n_s__message;
+static PyObject *__pyx_n_s__midi;
+static PyObject *__pyx_n_s__msg;
+static PyObject *__pyx_n_s__name;
+static PyObject *__pyx_n_s__opened;
+static PyObject *__pyx_n_s__output;
+static PyObject *__pyx_n_s__range;
+static PyObject *__pyx_n_s__status;
+static PyObject *__pyx_n_s__timestamp;
+static PyObject *__pyx_n_s__tostring;
+static PyObject *__pyx_n_s__when;
+static PyObject *__pyx_int_0;
+static PyObject *__pyx_int_1;
+static PyObject *__pyx_int_8;
+static PyObject *__pyx_int_16;
+static PyObject *__pyx_int_0x1;
+static PyObject *__pyx_int_0x2;
+static PyObject *__pyx_int_0x4;
+static PyObject *__pyx_int_0x8;
+static PyObject *__pyx_int_0x10;
+static PyObject *__pyx_int_0x20;
+static PyObject *__pyx_int_0x30;
+static PyObject *__pyx_int_0x40;
+static PyObject *__pyx_int_0x7F;
+static PyObject *__pyx_int_0x80;
+static PyObject *__pyx_int_0xFF;
+static PyObject *__pyx_int_1024;
+static PyObject *__pyx_int_4096;
+static PyObject *__pyx_int_0x100;
+static PyObject *__pyx_int_0x200;
+static PyObject *__pyx_int_0x300;
+static PyObject *__pyx_int_0x400;
+static PyObject *__pyx_int_0x800;
+static PyObject *__pyx_int_0x1000;
+static PyObject *__pyx_int_0x2000;
+static PyObject *__pyx_int_0x4000;
+static PyObject *__pyx_int_0x8000;
+static PyObject *__pyx_int_0xFF00;
+static PyObject *__pyx_int_0x10000;
+static PyObject *__pyx_int_0xFF0000;
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":132
+ * TRUE=1
+ * 
+ * def Initialize():             # <<<<<<<<<<<<<<
+ *     """
+ * Initialize: call this first
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_Initialize(PyObject *__pyx_self, PyObject *unused); /*proto*/
+static char __pyx_doc_11_pyportmidi_Initialize[] = "\nInitialize: call this first\n    ";
+static PyObject *__pyx_pf_11_pyportmidi_Initialize(PyObject *__pyx_self, PyObject *unused) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannySetupContext("Initialize");
+  __pyx_self = __pyx_self;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":136
+ * Initialize: call this first
+ *     """
+ *     Pm_Initialize()             # <<<<<<<<<<<<<<
+ *     Pt_Start(1, NULL, NULL) # /[inserted by cython to avoid comment start]* equiv to TIME_START: start timer w/ ms accuracy *[inserted by cython to avoid comment closer]/
+ * 
+ */
+  Pm_Initialize();
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":137
+ *     """
+ *     Pm_Initialize()
+ *     Pt_Start(1, NULL, NULL) # /[inserted by cython to avoid comment start]* equiv to TIME_START: start timer w/ ms accuracy *[inserted by cython to avoid comment closer]/             # <<<<<<<<<<<<<<
+ * 
+ * def Terminate():
+ */
+  Pt_Start(1, NULL, NULL);
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":139
+ *     Pt_Start(1, NULL, NULL) # /[inserted by cython to avoid comment start]* equiv to TIME_START: start timer w/ ms accuracy *[inserted by cython to avoid comment closer]/
+ * 
+ * def Terminate():             # <<<<<<<<<<<<<<
+ *     """
+ * Terminate: call this to clean up Midi streams when done.
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_Terminate(PyObject *__pyx_self, PyObject *unused); /*proto*/
+static char __pyx_doc_11_pyportmidi_Terminate[] = "\nTerminate: call this to clean up Midi streams when done.\nIf you do not call this on Windows machines when you are\ndone with MIDI, your system may crash.\n    ";
+static PyObject *__pyx_pf_11_pyportmidi_Terminate(PyObject *__pyx_self, PyObject *unused) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannySetupContext("Terminate");
+  __pyx_self = __pyx_self;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":145
+ * done with MIDI, your system may crash.
+ *     """
+ *     Pm_Terminate()             # <<<<<<<<<<<<<<
+ * 
+ * def GetDefaultInputDeviceID():
+ */
+  Pm_Terminate();
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":147
+ *     Pm_Terminate()
+ * 
+ * def GetDefaultInputDeviceID():             # <<<<<<<<<<<<<<
+ *     return Pm_GetDefaultInputDeviceID()
+ * 
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_GetDefaultInputDeviceID(PyObject *__pyx_self, PyObject *unused); /*proto*/
+static PyObject *__pyx_pf_11_pyportmidi_GetDefaultInputDeviceID(PyObject *__pyx_self, PyObject *unused) {
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  __Pyx_RefNannySetupContext("GetDefaultInputDeviceID");
+  __pyx_self = __pyx_self;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":148
+ * 
+ * def GetDefaultInputDeviceID():
+ *     return Pm_GetDefaultInputDeviceID()             # <<<<<<<<<<<<<<
+ * 
+ * def GetDefaultOutputDeviceID():
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_PyInt_to_py_PmDeviceID(Pm_GetDefaultInputDeviceID()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 148; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_pyportmidi.GetDefaultInputDeviceID");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":150
+ *     return Pm_GetDefaultInputDeviceID()
+ * 
+ * def GetDefaultOutputDeviceID():             # <<<<<<<<<<<<<<
+ *     return Pm_GetDefaultOutputDeviceID()
+ * 
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_GetDefaultOutputDeviceID(PyObject *__pyx_self, PyObject *unused); /*proto*/
+static PyObject *__pyx_pf_11_pyportmidi_GetDefaultOutputDeviceID(PyObject *__pyx_self, PyObject *unused) {
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  __Pyx_RefNannySetupContext("GetDefaultOutputDeviceID");
+  __pyx_self = __pyx_self;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":151
+ * 
+ * def GetDefaultOutputDeviceID():
+ *     return Pm_GetDefaultOutputDeviceID()             # <<<<<<<<<<<<<<
+ * 
+ * def CountDevices():
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_PyInt_to_py_PmDeviceID(Pm_GetDefaultOutputDeviceID()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 151; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_pyportmidi.GetDefaultOutputDeviceID");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":153
+ *     return Pm_GetDefaultOutputDeviceID()
+ * 
+ * def CountDevices():             # <<<<<<<<<<<<<<
+ *     return Pm_CountDevices()
+ * 
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_CountDevices(PyObject *__pyx_self, PyObject *unused); /*proto*/
+static PyObject *__pyx_pf_11_pyportmidi_CountDevices(PyObject *__pyx_self, PyObject *unused) {
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  __Pyx_RefNannySetupContext("CountDevices");
+  __pyx_self = __pyx_self;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":154
+ * 
+ * def CountDevices():
+ *     return Pm_CountDevices()             # <<<<<<<<<<<<<<
+ * 
+ * def GetDeviceInfo(i):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyInt_FromLong(Pm_CountDevices()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 154; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_pyportmidi.CountDevices");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":156
+ *     return Pm_CountDevices()
+ * 
+ * def GetDeviceInfo(i):             # <<<<<<<<<<<<<<
+ *     """
+ * GetDeviceInfo(<device number>): returns 5 parameters
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_GetDeviceInfo(PyObject *__pyx_self, PyObject *__pyx_v_i); /*proto*/
+static char __pyx_doc_11_pyportmidi_GetDeviceInfo[] = "\nGetDeviceInfo(<device number>): returns 5 parameters\n  - underlying MIDI API\n  - device name\n  - TRUE iff input is available\n  - TRUE iff output is available\n  - TRUE iff device stream is already open\n    ";
+static PyObject *__pyx_pf_11_pyportmidi_GetDeviceInfo(PyObject *__pyx_self, PyObject *__pyx_v_i) {
+  PmDeviceInfo *__pyx_v_info;
+  PyObject *__pyx_r = NULL;
+  PmDeviceID __pyx_t_1;
+  int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
+  PyObject *__pyx_t_7 = NULL;
+  PyObject *__pyx_t_8 = NULL;
+  __Pyx_RefNannySetupContext("GetDeviceInfo");
+  __pyx_self = __pyx_self;
+  __Pyx_INCREF(__pyx_v_i);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":168
+ * 
+ *     # disregarding the constness from Pm_GetDeviceInfo, since pyrex doesn't do const.
+ *     info = <PmDeviceInfo *>Pm_GetDeviceInfo(i)             # <<<<<<<<<<<<<<
+ * 
+ *     if info <> NULL: return info.interf, info.name, info.input, info.output, info.opened
+ */
+  __pyx_t_1 = __Pyx_PyInt_from_py_PmDeviceID(__pyx_v_i); if (unlikely((__pyx_t_1 == (PmDeviceID)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_info = ((PmDeviceInfo *)Pm_GetDeviceInfo(__pyx_t_1));
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":170
+ *     info = <PmDeviceInfo *>Pm_GetDeviceInfo(i)
+ * 
+ *     if info <> NULL: return info.interf, info.name, info.input, info.output, info.opened             # <<<<<<<<<<<<<<
+ *     else: return
+ * 
+ */
+  __pyx_t_2 = (__pyx_v_info != NULL);
+  if (__pyx_t_2) {
+    __Pyx_XDECREF(__pyx_r);
+    __pyx_t_3 = __Pyx_PyBytes_FromString(__pyx_v_info->interf); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+    __pyx_t_4 = __Pyx_PyBytes_FromString(__pyx_v_info->name); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+    __pyx_t_5 = PyInt_FromLong(__pyx_v_info->input); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+    __pyx_t_6 = PyInt_FromLong(__pyx_v_info->output); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_6);
+    __pyx_t_7 = PyInt_FromLong(__pyx_v_info->opened); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_7);
+    __pyx_t_8 = PyTuple_New(5); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_8);
+    PyTuple_SET_ITEM(__pyx_t_8, 0, ((PyObject *)__pyx_t_3));
+    __Pyx_GIVEREF(((PyObject *)__pyx_t_3));
+    PyTuple_SET_ITEM(__pyx_t_8, 1, ((PyObject *)__pyx_t_4));
+    __Pyx_GIVEREF(((PyObject *)__pyx_t_4));
+    PyTuple_SET_ITEM(__pyx_t_8, 2, __pyx_t_5);
+    __Pyx_GIVEREF(__pyx_t_5);
+    PyTuple_SET_ITEM(__pyx_t_8, 3, __pyx_t_6);
+    __Pyx_GIVEREF(__pyx_t_6);
+    PyTuple_SET_ITEM(__pyx_t_8, 4, __pyx_t_7);
+    __Pyx_GIVEREF(__pyx_t_7);
+    __pyx_t_3 = 0;
+    __pyx_t_4 = 0;
+    __pyx_t_5 = 0;
+    __pyx_t_6 = 0;
+    __pyx_t_7 = 0;
+    __pyx_r = __pyx_t_8;
+    __pyx_t_8 = 0;
+    goto __pyx_L0;
+    goto __pyx_L5;
+  }
+  /*else*/ {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":171
+ * 
+ *     if info <> NULL: return info.interf, info.name, info.input, info.output, info.opened
+ *     else: return             # <<<<<<<<<<<<<<
+ * 
+ * def Time():
+ */
+    __Pyx_XDECREF(__pyx_r);
+    __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+    goto __pyx_L0;
+  }
+  __pyx_L5:;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_XDECREF(__pyx_t_8);
+  __Pyx_AddTraceback("_pyportmidi.GetDeviceInfo");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_i);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":173
+ *     else: return
+ * 
+ * def Time():             # <<<<<<<<<<<<<<
+ *     """
+ * Time() returns the current time in ms
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_Time(PyObject *__pyx_self, PyObject *unused); /*proto*/
+static char __pyx_doc_11_pyportmidi_Time[] = "\nTime() returns the current time in ms\nof the PortMidi timer\n    ";
+static PyObject *__pyx_pf_11_pyportmidi_Time(PyObject *__pyx_self, PyObject *unused) {
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  __Pyx_RefNannySetupContext("Time");
+  __pyx_self = __pyx_self;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":178
+ * of the PortMidi timer
+ *     """
+ *     return Pt_Time()             # <<<<<<<<<<<<<<
+ * 
+ * def GetErrorText(err):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_PyInt_to_py_PtTimestamp(Pt_Time()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_pyportmidi.Time");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":180
+ *     return Pt_Time()
+ * 
+ * def GetErrorText(err):             # <<<<<<<<<<<<<<
+ *     """
+ * GetErrorText(<err num>) returns human-readable error
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_GetErrorText(PyObject *__pyx_self, PyObject *__pyx_v_err); /*proto*/
+static char __pyx_doc_11_pyportmidi_GetErrorText[] = "\nGetErrorText(<err num>) returns human-readable error\nmessages translated from error numbers\n    ";
+static PyObject *__pyx_pf_11_pyportmidi_GetErrorText(PyObject *__pyx_self, PyObject *__pyx_v_err) {
+  PyObject *__pyx_r = NULL;
+  PmError __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  __Pyx_RefNannySetupContext("GetErrorText");
+  __pyx_self = __pyx_self;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":185
+ * messages translated from error numbers
+ *     """
+ *     return Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ * 
+ * def Channel(chan):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = ((PmError)PyInt_AsLong(__pyx_v_err)); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 185; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_t_1)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 185; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  __pyx_r = ((PyObject *)__pyx_t_2);
+  __pyx_t_2 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_pyportmidi.GetErrorText");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":187
+ *     return Pm_GetErrorText(err)
+ * 
+ * def Channel(chan):             # <<<<<<<<<<<<<<
+ *     """
+ * Channel(<chan>) is used with ChannelMask on input MIDI streams.
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_Channel(PyObject *__pyx_self, PyObject *__pyx_v_chan); /*proto*/
+static char __pyx_doc_11_pyportmidi_Channel[] = "\nChannel(<chan>) is used with ChannelMask on input MIDI streams.\nExample: to receive input on channels 1 and 10 on a MIDI\n         stream called MidiIn:\nMidiIn.SetChannelMask(pypm.Channel(1) | pypm.Channel(10))\n\nnote: PyPortMidi Channel function has been altered from\n      the original PortMidi c call to correct for what\n      seems to be a bug --- i.e. channel filters were\n      all numbered from 0 to 15 instead of 1 to 16.\n    ";
+static PyObject *__pyx_pf_11_pyportmidi_Channel(PyObject *__pyx_self, PyObject *__pyx_v_chan) {
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  __Pyx_RefNannySetupContext("Channel");
+  __pyx_self = __pyx_self;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":199
+ *       all numbered from 0 to 15 instead of 1 to 16.
+ *     """
+ *     return Pm_Channel(chan-1)             # <<<<<<<<<<<<<<
+ * 
+ * cdef class Output:
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyNumber_Subtract(__pyx_v_chan, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 199; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_PyInt_AsInt(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 199; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_t_1 = PyInt_FromLong(Pm_Channel(__pyx_t_2)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 199; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_pyportmidi.Channel");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":214
+ *     cdef int _aborted
+ * 
+ *     def __init__(self, OutputDevice, latency=0):             # <<<<<<<<<<<<<<
+ * 
+ *         cdef PmError err
+ */
+
+static int __pyx_pf_11_pyportmidi_6Output___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pf_11_pyportmidi_6Output___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_OutputDevice = 0;
+  PyObject *__pyx_v_latency = 0;
+  PmError __pyx_v_err;
+  PmTimeProcPtr __pyx_v_PmPtr;
+  PyObject *__pyx_v_s;
+  int __pyx_r;
+  int __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_t_3;
+  long __pyx_t_4;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__OutputDevice,&__pyx_n_s__latency,0};
+  __Pyx_RefNannySetupContext("__init__");
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[2] = {0,0};
+    values[1] = ((PyObject *)__pyx_int_0);
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      case  0: break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  0:
+      values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__OutputDevice);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      if (kw_args > 1) {
+        PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__latency);
+        if (unlikely(value)) { values[1] = value; kw_args--; }
+      }
+    }
+    if (unlikely(kw_args > 0)) {
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 214; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_OutputDevice = values[0];
+    __pyx_v_latency = values[1];
+  } else {
+    __pyx_v_latency = ((PyObject *)__pyx_int_0);
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  2: __pyx_v_latency = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: __pyx_v_OutputDevice = PyTuple_GET_ITEM(__pyx_args, 0);
+      break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__init__", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 214; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_pyportmidi.Output.__init__");
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+  __Pyx_INCREF(__pyx_v_OutputDevice);
+  __Pyx_INCREF(__pyx_v_latency);
+  __pyx_v_s = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":220
+ *         cdef PmTimeProcPtr PmPtr
+ * 
+ *         self.i = OutputDevice             # <<<<<<<<<<<<<<
+ *         self.debug = 0
+ *         self._aborted = 0
+ */
+  __pyx_t_1 = __Pyx_PyInt_AsInt(__pyx_v_OutputDevice); if (unlikely((__pyx_t_1 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 220; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->i = __pyx_t_1;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":221
+ * 
+ *         self.i = OutputDevice
+ *         self.debug = 0             # <<<<<<<<<<<<<<
+ *         self._aborted = 0
+ * 
+ */
+  ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->debug = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":222
+ *         self.i = OutputDevice
+ *         self.debug = 0
+ *         self._aborted = 0             # <<<<<<<<<<<<<<
+ * 
+ *         if latency == 0:
+ */
+  ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->_aborted = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":224
+ *         self._aborted = 0
+ * 
+ *         if latency == 0:             # <<<<<<<<<<<<<<
+ *             PmPtr = NULL
+ *         else:
+ */
+  __pyx_t_2 = PyObject_RichCompare(__pyx_v_latency, __pyx_int_0, Py_EQ); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 224; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 224; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (__pyx_t_3) {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":225
+ * 
+ *         if latency == 0:
+ *             PmPtr = NULL             # <<<<<<<<<<<<<<
+ *         else:
+ *             PmPtr = <PmTimeProcPtr>&Pt_Time
+ */
+    __pyx_v_PmPtr = NULL;
+    goto __pyx_L6;
+  }
+  /*else*/ {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":227
+ *             PmPtr = NULL
+ *         else:
+ *             PmPtr = <PmTimeProcPtr>&Pt_Time             # <<<<<<<<<<<<<<
+ *         if self.debug: print "Opening Midi Output"
+ * 	# Why is bufferSize 0 here?
+ */
+    __pyx_v_PmPtr = ((PmTimestamp (*)(void *))(&Pt_Time));
+  }
+  __pyx_L6:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":228
+ *         else:
+ *             PmPtr = <PmTimeProcPtr>&Pt_Time
+ *         if self.debug: print "Opening Midi Output"             # <<<<<<<<<<<<<<
+ * 	# Why is bufferSize 0 here?
+ *         err = Pm_OpenOutput(&(self.midi), self.i, NULL, 0, PmPtr, NULL, latency)
+ */
+  __pyx_t_1 = ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->debug;
+  if (__pyx_t_1) {
+    if (__Pyx_PrintOne(((PyObject *)__pyx_kp_s_1)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 228; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L7;
+  }
+  __pyx_L7:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":230
+ *         if self.debug: print "Opening Midi Output"
+ * 	# Why is bufferSize 0 here?
+ *         err = Pm_OpenOutput(&(self.midi), self.i, NULL, 0, PmPtr, NULL, latency)             # <<<<<<<<<<<<<<
+ *         if err < 0:
+ *                 s = Pm_GetErrorText(err)
+ */
+  __pyx_t_4 = __Pyx_PyInt_AsLong(__pyx_v_latency); if (unlikely((__pyx_t_4 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 230; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_err = Pm_OpenOutput((&((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi), ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->i, NULL, 0, __pyx_v_PmPtr, NULL, __pyx_t_4);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":231
+ * 	# Why is bufferSize 0 here?
+ *         err = Pm_OpenOutput(&(self.midi), self.i, NULL, 0, PmPtr, NULL, latency)
+ *         if err < 0:             # <<<<<<<<<<<<<<
+ *                 s = Pm_GetErrorText(err)
+ *                 # Something's amiss here - if we try to throw an Exception
+ */
+  __pyx_t_3 = (__pyx_v_err < 0);
+  if (__pyx_t_3) {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":232
+ *         err = Pm_OpenOutput(&(self.midi), self.i, NULL, 0, PmPtr, NULL, latency)
+ *         if err < 0:
+ *                 s = Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ *                 # Something's amiss here - if we try to throw an Exception
+ *                	# here, we crash.
+ */
+    __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 232; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+    __Pyx_DECREF(__pyx_v_s);
+    __pyx_v_s = ((PyObject *)__pyx_t_2);
+    __pyx_t_2 = 0;
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":235
+ *                 # Something's amiss here - if we try to throw an Exception
+ *                	# here, we crash.
+ *                 if not err == -10000:             # <<<<<<<<<<<<<<
+ *                         raise Exception,s
+ *                 else:
+ */
+    __pyx_t_3 = (!(__pyx_v_err == -10000));
+    if (__pyx_t_3) {
+
+      /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":236
+ *                	# here, we crash.
+ *                 if not err == -10000:
+ *                         raise Exception,s             # <<<<<<<<<<<<<<
+ *                 else:
+ *                         print "Unable to open Midi OutputDevice=",OutputDevice," err=",s
+ */
+      __Pyx_Raise(__pyx_builtin_Exception, __pyx_v_s, 0);
+      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 236; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      goto __pyx_L9;
+    }
+    /*else*/ {
+
+      /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":238
+ *                         raise Exception,s
+ *                 else:
+ *                         print "Unable to open Midi OutputDevice=",OutputDevice," err=",s             # <<<<<<<<<<<<<<
+ * 
+ *     def __dealloc__(self):
+ */
+      __pyx_t_2 = PyTuple_New(4); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 238; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_2);
+      __Pyx_INCREF(((PyObject *)__pyx_kp_s_2));
+      PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_kp_s_2));
+      __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_2));
+      __Pyx_INCREF(__pyx_v_OutputDevice);
+      PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_OutputDevice);
+      __Pyx_GIVEREF(__pyx_v_OutputDevice);
+      __Pyx_INCREF(((PyObject *)__pyx_kp_s_3));
+      PyTuple_SET_ITEM(__pyx_t_2, 2, ((PyObject *)__pyx_kp_s_3));
+      __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_3));
+      __Pyx_INCREF(__pyx_v_s);
+      PyTuple_SET_ITEM(__pyx_t_2, 3, __pyx_v_s);
+      __Pyx_GIVEREF(__pyx_v_s);
+      if (__Pyx_Print(__pyx_t_2, 1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 238; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    }
+    __pyx_L9:;
+    goto __pyx_L8;
+  }
+  __pyx_L8:;
+
+  __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_pyportmidi.Output.__init__");
+  __pyx_r = -1;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_s);
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_DECREF(__pyx_v_OutputDevice);
+  __Pyx_DECREF(__pyx_v_latency);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":240
+ *                         print "Unable to open Midi OutputDevice=",OutputDevice," err=",s
+ * 
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         if self.debug: print "Closing MIDI output stream and destroying instance"
+ *         #err = Pm_Abort(self.midi)
+ */
+
+static void __pyx_pf_11_pyportmidi_6Output___dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pf_11_pyportmidi_6Output___dealloc__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_v_err;
+  int __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_t_3;
+  PmError __pyx_t_4;
+  __Pyx_RefNannySetupContext("__dealloc__");
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+  __pyx_v_err = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":241
+ * 
+ *     def __dealloc__(self):
+ *         if self.debug: print "Closing MIDI output stream and destroying instance"             # <<<<<<<<<<<<<<
+ *         #err = Pm_Abort(self.midi)
+ *         #if err < 0: raise Exception, Pm_GetErrorText(err)
+ */
+  __pyx_t_1 = ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->debug;
+  if (__pyx_t_1) {
+    if (__Pyx_PrintOne(((PyObject *)__pyx_kp_s_4)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 241; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":244
+ *         #err = Pm_Abort(self.midi)
+ *         #if err < 0: raise Exception, Pm_GetErrorText(err)
+ *         err = Pm_Close(self.midi)             # <<<<<<<<<<<<<<
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)
+ * 
+ */
+  __pyx_t_2 = PyInt_FromLong(Pm_Close(((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 244; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_v_err);
+  __pyx_v_err = __pyx_t_2;
+  __pyx_t_2 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":245
+ *         #if err < 0: raise Exception, Pm_GetErrorText(err)
+ *         err = Pm_Close(self.midi)
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ * 
+ * 
+ */
+  __pyx_t_2 = PyObject_RichCompare(__pyx_v_err, __pyx_int_0, Py_LT); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (__pyx_t_3) {
+    __pyx_t_4 = ((PmError)PyInt_AsLong(__pyx_v_err)); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_t_4)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_2), 0);
+    __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_pyportmidi.Output.__dealloc__");
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_err);
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_RefNannyFinishContext();
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":248
+ * 
+ * 
+ *     def _check_open(self):             # <<<<<<<<<<<<<<
+ *         """ checks to see if the midi is open, and if not, raises an error.
+ *         """
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_6Output__check_open(PyObject *__pyx_v_self, PyObject *unused); /*proto*/
+static char __pyx_doc_11_pyportmidi_6Output__check_open[] = " checks to see if the midi is open, and if not, raises an error.\n        ";
+static PyObject *__pyx_pf_11_pyportmidi_6Output__check_open(PyObject *__pyx_v_self, PyObject *unused) {
+  PyObject *__pyx_r = NULL;
+  int __pyx_t_1;
+  int __pyx_t_2;
+  __Pyx_RefNannySetupContext("_check_open");
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":252
+ *         """
+ * 
+ *         if self.midi == NULL:             # <<<<<<<<<<<<<<
+ *             raise Exception, "midi Output not open."
+ * 
+ */
+  __pyx_t_1 = (((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi == NULL);
+  if (__pyx_t_1) {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":253
+ * 
+ *         if self.midi == NULL:
+ *             raise Exception, "midi Output not open."             # <<<<<<<<<<<<<<
+ * 
+ *         if self._aborted:
+ */
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_kp_s_5), 0);
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 253; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":255
+ *             raise Exception, "midi Output not open."
+ * 
+ *         if self._aborted:             # <<<<<<<<<<<<<<
+ *             raise Exception, "midi Output aborted.  Need to call Close after Abort."
+ * 
+ */
+  __pyx_t_2 = ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->_aborted;
+  if (__pyx_t_2) {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":256
+ * 
+ *         if self._aborted:
+ *             raise Exception, "midi Output aborted.  Need to call Close after Abort."             # <<<<<<<<<<<<<<
+ * 
+ *     def Close(self):
+ */
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_kp_s_6), 0);
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_pyportmidi.Output._check_open");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":258
+ *             raise Exception, "midi Output aborted.  Need to call Close after Abort."
+ * 
+ *     def Close(self):             # <<<<<<<<<<<<<<
+ *         """
+ * Close()
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_6Output_Close(PyObject *__pyx_v_self, PyObject *unused); /*proto*/
+static char __pyx_doc_11_pyportmidi_6Output_Close[] = "\nClose()\n    closes a midi stream, flushing any pending buffers.\n    (PortMidi attempts to close open streams when the application\n    exits -- this is particularly difficult under Windows.)\n        ";
+static PyObject *__pyx_pf_11_pyportmidi_6Output_Close(PyObject *__pyx_v_self, PyObject *unused) {
+  PyObject *__pyx_v_err;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  PmError __pyx_t_3;
+  __Pyx_RefNannySetupContext("Close");
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+  __pyx_v_err = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":268
+ *         #    return
+ * 
+ *         err = Pm_Close(self.midi)             # <<<<<<<<<<<<<<
+ *         if err < 0:
+ *             raise Exception, Pm_GetErrorText(err)
+ */
+  __pyx_t_1 = PyInt_FromLong(Pm_Close(((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 268; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__pyx_v_err);
+  __pyx_v_err = __pyx_t_1;
+  __pyx_t_1 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":269
+ * 
+ *         err = Pm_Close(self.midi)
+ *         if err < 0:             # <<<<<<<<<<<<<<
+ *             raise Exception, Pm_GetErrorText(err)
+ *         #self.midi = NULL
+ */
+  __pyx_t_1 = PyObject_RichCompare(__pyx_v_err, __pyx_int_0, Py_LT); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":270
+ *         err = Pm_Close(self.midi)
+ *         if err < 0:
+ *             raise Exception, Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ *         #self.midi = NULL
+ * 
+ */
+    __pyx_t_3 = ((PmError)PyInt_AsLong(__pyx_v_err)); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_t_3)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_1), 0);
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_pyportmidi.Output.Close");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_err);
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":274
+ * 
+ * 
+ *     def Abort(self):             # <<<<<<<<<<<<<<
+ *         """
+ * Abort() terminates outgoing messages immediately
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_6Output_Abort(PyObject *__pyx_v_self, PyObject *unused); /*proto*/
+static char __pyx_doc_11_pyportmidi_6Output_Abort[] = "\nAbort() terminates outgoing messages immediately\n    The caller should immediately close the output port;\n    this call may result in transmission of a partial midi message.\n    There is no abort for Midi input because the user can simply\n    ignore messages in the buffer and close an input device at\n    any time.\n        ";
+static PyObject *__pyx_pf_11_pyportmidi_6Output_Abort(PyObject *__pyx_v_self, PyObject *unused) {
+  PyObject *__pyx_v_err;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  PmError __pyx_t_3;
+  __Pyx_RefNannySetupContext("Abort");
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+  __pyx_v_err = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":286
+ *         #    return
+ * 
+ *         err = Pm_Abort(self.midi)             # <<<<<<<<<<<<<<
+ *         if err < 0:
+ *             raise Exception, Pm_GetErrorText(err)
+ */
+  __pyx_t_1 = PyInt_FromLong(Pm_Abort(((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__pyx_v_err);
+  __pyx_v_err = __pyx_t_1;
+  __pyx_t_1 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":287
+ * 
+ *         err = Pm_Abort(self.midi)
+ *         if err < 0:             # <<<<<<<<<<<<<<
+ *             raise Exception, Pm_GetErrorText(err)
+ * 
+ */
+  __pyx_t_1 = PyObject_RichCompare(__pyx_v_err, __pyx_int_0, Py_LT); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 287; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 287; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":288
+ *         err = Pm_Abort(self.midi)
+ *         if err < 0:
+ *             raise Exception, Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ * 
+ *         self._aborted = 1
+ */
+    __pyx_t_3 = ((PmError)PyInt_AsLong(__pyx_v_err)); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 288; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_t_3)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 288; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_1), 0);
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 288; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":290
+ *             raise Exception, Pm_GetErrorText(err)
+ * 
+ *         self._aborted = 1             # <<<<<<<<<<<<<<
+ * 
+ * 
+ */
+  ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->_aborted = 1;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_pyportmidi.Output.Abort");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_err);
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":293
+ * 
+ * 
+ *     def Write(self, data):             # <<<<<<<<<<<<<<
+ *         """
+ * Write(data)
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_6Output_Write(PyObject *__pyx_v_self, PyObject *__pyx_v_data); /*proto*/
+static char __pyx_doc_11_pyportmidi_6Output_Write[] = "\nWrite(data)\n    output a series of MIDI information in the form of a list:\n         Write([[[status <,data1><,data2><,data3>],timestamp],\n                [[status <,data1><,data2><,data3>],timestamp],...])\n    <data> fields are optional\n    example: choose program change 1 at time 20000 and\n    send note 65 with velocity 100 500 ms later.\n         Write([[[0xc0,0,0],20000],[[0x90,60,100],20500]])\n    notes:\n      1. timestamps will be ignored if latency = 0.\n      2. To get a note to play immediately, send MIDI info with\n         timestamp read from function Time.\n      3. understanding optional data fields:\n           Write([[[0xc0,0,0],20000]]) is equivalent to\n           Write([[[0xc0],20000]])\n        ";
+static PyObject *__pyx_pf_11_pyportmidi_6Output_Write(PyObject *__pyx_v_self, PyObject *__pyx_v_data) {
+  PmEvent __pyx_v_buffer[1024];
+  PmError __pyx_v_err;
+  int __pyx_v_i;
+  PyObject *__pyx_v_loop1;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  Py_ssize_t __pyx_t_3;
+  int __pyx_t_4;
+  Py_ssize_t __pyx_t_5;
+  PyObject *__pyx_t_6 = NULL;
+  Py_ssize_t __pyx_t_7;
+  int __pyx_t_8;
+  PyObject *__pyx_t_9 = NULL;
+  PyObject *__pyx_t_10 = NULL;
+  PmMessage __pyx_t_11;
+  PmTimestamp __pyx_t_12;
+  __Pyx_RefNannySetupContext("Write");
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+  __Pyx_INCREF(__pyx_v_data);
+  __pyx_v_loop1 = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":315
+ *         cdef int i
+ * 
+ *         self._check_open()             # <<<<<<<<<<<<<<
+ * 
+ * 
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 315; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 315; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":318
+ * 
+ * 
+ *         if len(data) > 1024: raise IndexError, 'maximum list length is 1024'             # <<<<<<<<<<<<<<
+ *         else:
+ *             for loop1 in range(len(data)):
+ */
+  __pyx_t_3 = PyObject_Length(__pyx_v_data); if (unlikely(__pyx_t_3 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 318; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_4 = (__pyx_t_3 > 1024);
+  if (__pyx_t_4) {
+    __Pyx_Raise(__pyx_builtin_IndexError, ((PyObject *)__pyx_kp_s_7), 0);
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 318; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  /*else*/ {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":320
+ *         if len(data) > 1024: raise IndexError, 'maximum list length is 1024'
+ *         else:
+ *             for loop1 in range(len(data)):             # <<<<<<<<<<<<<<
+ *                 if ((len(data[loop1][0]) > 4) |
+ *                     (len(data[loop1][0]) < 1)):
+ */
+    __pyx_t_5 = PyObject_Length(__pyx_v_data); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = PyInt_FromSsize_t(__pyx_t_5); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_2);
+    __Pyx_GIVEREF(__pyx_t_2);
+    __pyx_t_2 = 0;
+    __pyx_t_2 = PyObject_Call(__pyx_builtin_range, __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    if (PyList_CheckExact(__pyx_t_2) || PyTuple_CheckExact(__pyx_t_2)) {
+      __pyx_t_3 = 0; __pyx_t_1 = __pyx_t_2; __Pyx_INCREF(__pyx_t_1);
+    } else {
+      __pyx_t_3 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_1);
+    }
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    for (;;) {
+      if (likely(PyList_CheckExact(__pyx_t_1))) {
+        if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_1)) break;
+        __pyx_t_2 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++;
+      } else if (likely(PyTuple_CheckExact(__pyx_t_1))) {
+        if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
+        __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++;
+      } else {
+        __pyx_t_2 = PyIter_Next(__pyx_t_1);
+        if (!__pyx_t_2) {
+          if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          break;
+        }
+        __Pyx_GOTREF(__pyx_t_2);
+      }
+      __Pyx_DECREF(__pyx_v_loop1);
+      __pyx_v_loop1 = __pyx_t_2;
+      __pyx_t_2 = 0;
+
+      /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":321
+ *         else:
+ *             for loop1 in range(len(data)):
+ *                 if ((len(data[loop1][0]) > 4) |             # <<<<<<<<<<<<<<
+ *                     (len(data[loop1][0]) < 1)):
+ *                     raise IndexError, str(len(data[loop1][0]))+' arguments in event list'
+ */
+      __pyx_t_2 = PyObject_GetItem(__pyx_v_data, __pyx_v_loop1); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_2);
+      __pyx_t_6 = __Pyx_GetItemInt(__pyx_t_2, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_6) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      __pyx_t_5 = PyObject_Length(__pyx_t_6); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+
+      /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":322
+ *             for loop1 in range(len(data)):
+ *                 if ((len(data[loop1][0]) > 4) |
+ *                     (len(data[loop1][0]) < 1)):             # <<<<<<<<<<<<<<
+ *                     raise IndexError, str(len(data[loop1][0]))+' arguments in event list'
+ *                 buffer[loop1].message = 0
+ */
+      __pyx_t_6 = PyObject_GetItem(__pyx_v_data, __pyx_v_loop1); if (!__pyx_t_6) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_6, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_2);
+      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+      __pyx_t_7 = PyObject_Length(__pyx_t_2); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 322; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      __pyx_t_4 = ((__pyx_t_5 > 4) | (__pyx_t_7 < 1));
+      if (__pyx_t_4) {
+
+        /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":323
+ *                 if ((len(data[loop1][0]) > 4) |
+ *                     (len(data[loop1][0]) < 1)):
+ *                     raise IndexError, str(len(data[loop1][0]))+' arguments in event list'             # <<<<<<<<<<<<<<
+ *                 buffer[loop1].message = 0
+ *                 for i in range(len(data[loop1][0])):
+ */
+        __pyx_t_2 = PyObject_GetItem(__pyx_v_data, __pyx_v_loop1); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_2);
+        __pyx_t_6 = __Pyx_GetItemInt(__pyx_t_2, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_6) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_6);
+        __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+        __pyx_t_7 = PyObject_Length(__pyx_t_6); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+        __pyx_t_6 = PyInt_FromSsize_t(__pyx_t_7); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_6);
+        __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_2);
+        PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_6);
+        __Pyx_GIVEREF(__pyx_t_6);
+        __pyx_t_6 = 0;
+        __pyx_t_6 = PyObject_Call(((PyObject *)((PyObject*)&PyString_Type)), __pyx_t_2, NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_6);
+        __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+        __pyx_t_2 = PyNumber_Add(__pyx_t_6, ((PyObject *)__pyx_kp_s_8)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_2);
+        __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+        __Pyx_Raise(__pyx_builtin_IndexError, __pyx_t_2, 0);
+        __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+        {__pyx_filename = __pyx_f[0]; __pyx_lineno = 323; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        goto __pyx_L8;
+      }
+      __pyx_L8:;
+
+      /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":324
+ *                     (len(data[loop1][0]) < 1)):
+ *                     raise IndexError, str(len(data[loop1][0]))+' arguments in event list'
+ *                 buffer[loop1].message = 0             # <<<<<<<<<<<<<<
+ *                 for i in range(len(data[loop1][0])):
+ *                     buffer[loop1].message = buffer[loop1].message + ((data[loop1][0][i]&0xFF) << (8*i))
+ */
+      __pyx_t_7 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop1); if (unlikely((__pyx_t_7 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 324; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      (__pyx_v_buffer[__pyx_t_7]).message = 0;
+
+      /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":325
+ *                     raise IndexError, str(len(data[loop1][0]))+' arguments in event list'
+ *                 buffer[loop1].message = 0
+ *                 for i in range(len(data[loop1][0])):             # <<<<<<<<<<<<<<
+ *                     buffer[loop1].message = buffer[loop1].message + ((data[loop1][0][i]&0xFF) << (8*i))
+ *                 buffer[loop1].timestamp = data[loop1][1]
+ */
+      __pyx_t_2 = PyObject_GetItem(__pyx_v_data, __pyx_v_loop1); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 325; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_2);
+      __pyx_t_6 = __Pyx_GetItemInt(__pyx_t_2, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_6) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 325; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      __pyx_t_7 = PyObject_Length(__pyx_t_6); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 325; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+      for (__pyx_t_8 = 0; __pyx_t_8 < __pyx_t_7; __pyx_t_8+=1) {
+        __pyx_v_i = __pyx_t_8;
+
+        /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":326
+ *                 buffer[loop1].message = 0
+ *                 for i in range(len(data[loop1][0])):
+ *                     buffer[loop1].message = buffer[loop1].message + ((data[loop1][0][i]&0xFF) << (8*i))             # <<<<<<<<<<<<<<
+ *                 buffer[loop1].timestamp = data[loop1][1]
+ *                 if self.debug: print loop1," : ",buffer[loop1].message," : ",buffer[loop1].timestamp
+ */
+        __pyx_t_5 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop1); if (unlikely((__pyx_t_5 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_6 = __Pyx_PyInt_to_py_PmMessage((__pyx_v_buffer[__pyx_t_5]).message); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_6);
+        __pyx_t_2 = PyObject_GetItem(__pyx_v_data, __pyx_v_loop1); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_2);
+        __pyx_t_9 = __Pyx_GetItemInt(__pyx_t_2, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_9) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_9);
+        __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+        __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_9, __pyx_v_i, sizeof(int), PyInt_FromLong); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_2);
+        __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+        __pyx_t_9 = PyNumber_And(__pyx_t_2, __pyx_int_0xFF); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_9);
+        __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+        __pyx_t_2 = PyInt_FromLong((8 * __pyx_v_i)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_2);
+        __pyx_t_10 = PyNumber_Lshift(__pyx_t_9, __pyx_t_2); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_10);
+        __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+        __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+        __pyx_t_2 = PyNumber_Add(__pyx_t_6, __pyx_t_10); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_2);
+        __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+        __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+        __pyx_t_11 = __Pyx_PyInt_from_py_PmMessage(__pyx_t_2); if (unlikely((__pyx_t_11 == (PmMessage)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+        __pyx_t_5 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop1); if (unlikely((__pyx_t_5 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 326; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        (__pyx_v_buffer[__pyx_t_5]).message = __pyx_t_11;
+      }
+
+      /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":327
+ *                 for i in range(len(data[loop1][0])):
+ *                     buffer[loop1].message = buffer[loop1].message + ((data[loop1][0][i]&0xFF) << (8*i))
+ *                 buffer[loop1].timestamp = data[loop1][1]             # <<<<<<<<<<<<<<
+ *                 if self.debug: print loop1," : ",buffer[loop1].message," : ",buffer[loop1].timestamp
+ *         if self.debug: print "writing to midi buffer"
+ */
+      __pyx_t_2 = PyObject_GetItem(__pyx_v_data, __pyx_v_loop1); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 327; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_2);
+      __pyx_t_10 = __Pyx_GetItemInt(__pyx_t_2, 1, sizeof(long), PyInt_FromLong); if (!__pyx_t_10) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 327; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_10);
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      __pyx_t_12 = __Pyx_PyInt_from_py_PmTimestamp(__pyx_t_10); if (unlikely((__pyx_t_12 == (PmTimestamp)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 327; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+      __pyx_t_5 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop1); if (unlikely((__pyx_t_5 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 327; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      (__pyx_v_buffer[__pyx_t_5]).timestamp = __pyx_t_12;
+
+      /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":328
+ *                     buffer[loop1].message = buffer[loop1].message + ((data[loop1][0][i]&0xFF) << (8*i))
+ *                 buffer[loop1].timestamp = data[loop1][1]
+ *                 if self.debug: print loop1," : ",buffer[loop1].message," : ",buffer[loop1].timestamp             # <<<<<<<<<<<<<<
+ *         if self.debug: print "writing to midi buffer"
+ *         err= Pm_Write(self.midi, buffer, len(data))
+ */
+      __pyx_t_8 = ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->debug;
+      if (__pyx_t_8) {
+        __pyx_t_5 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop1); if (unlikely((__pyx_t_5 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_10 = __Pyx_PyInt_to_py_PmMessage((__pyx_v_buffer[__pyx_t_5]).message); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_10);
+        __pyx_t_5 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop1); if (unlikely((__pyx_t_5 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_2 = __Pyx_PyInt_to_py_PmTimestamp((__pyx_v_buffer[__pyx_t_5]).timestamp); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_2);
+        __pyx_t_6 = PyTuple_New(5); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_6);
+        __Pyx_INCREF(__pyx_v_loop1);
+        PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_v_loop1);
+        __Pyx_GIVEREF(__pyx_v_loop1);
+        __Pyx_INCREF(((PyObject *)__pyx_kp_s_9));
+        PyTuple_SET_ITEM(__pyx_t_6, 1, ((PyObject *)__pyx_kp_s_9));
+        __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_9));
+        PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_t_10);
+        __Pyx_GIVEREF(__pyx_t_10);
+        __Pyx_INCREF(((PyObject *)__pyx_kp_s_9));
+        PyTuple_SET_ITEM(__pyx_t_6, 3, ((PyObject *)__pyx_kp_s_9));
+        __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_9));
+        PyTuple_SET_ITEM(__pyx_t_6, 4, __pyx_t_2);
+        __Pyx_GIVEREF(__pyx_t_2);
+        __pyx_t_10 = 0;
+        __pyx_t_2 = 0;
+        if (__Pyx_Print(__pyx_t_6, 1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 328; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+        goto __pyx_L11;
+      }
+      __pyx_L11:;
+    }
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  }
+  __pyx_L5:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":329
+ *                 buffer[loop1].timestamp = data[loop1][1]
+ *                 if self.debug: print loop1," : ",buffer[loop1].message," : ",buffer[loop1].timestamp
+ *         if self.debug: print "writing to midi buffer"             # <<<<<<<<<<<<<<
+ *         err= Pm_Write(self.midi, buffer, len(data))
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)
+ */
+  __pyx_t_8 = ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->debug;
+  if (__pyx_t_8) {
+    if (__Pyx_PrintOne(((PyObject *)__pyx_kp_s_10)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 329; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L12;
+  }
+  __pyx_L12:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":330
+ *                 if self.debug: print loop1," : ",buffer[loop1].message," : ",buffer[loop1].timestamp
+ *         if self.debug: print "writing to midi buffer"
+ *         err= Pm_Write(self.midi, buffer, len(data))             # <<<<<<<<<<<<<<
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)
+ * 
+ */
+  __pyx_t_3 = PyObject_Length(__pyx_v_data); if (unlikely(__pyx_t_3 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 330; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_err = Pm_Write(((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi, __pyx_v_buffer, __pyx_t_3);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":331
+ *         if self.debug: print "writing to midi buffer"
+ *         err= Pm_Write(self.midi, buffer, len(data))
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ * 
+ *     def WriteShort(self, status, data1 = 0, data2 = 0):
+ */
+  __pyx_t_4 = (__pyx_v_err < 0);
+  if (__pyx_t_4) {
+    __pyx_t_1 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 331; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_1), 0);
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 331; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L13;
+  }
+  __pyx_L13:;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_XDECREF(__pyx_t_9);
+  __Pyx_XDECREF(__pyx_t_10);
+  __Pyx_AddTraceback("_pyportmidi.Output.Write");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_loop1);
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_DECREF(__pyx_v_data);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":333
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)
+ * 
+ *     def WriteShort(self, status, data1 = 0, data2 = 0):             # <<<<<<<<<<<<<<
+ *         """
+ * WriteShort(status <, data1><, data2>)
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_6Output_WriteShort(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static char __pyx_doc_11_pyportmidi_6Output_WriteShort[] = "\nWriteShort(status <, data1><, data2>)\n     output MIDI information of 3 bytes or less.\n     data fields are optional\n     status byte could be:\n          0xc0 = program change\n          0x90 = note on\n          etc.\n          data bytes are optional and assumed 0 if omitted\n     example: note 65 on with velocity 100\n          WriteShort(0x90,65,100)\n        ";
+static PyObject *__pyx_pf_11_pyportmidi_6Output_WriteShort(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_status = 0;
+  PyObject *__pyx_v_data1 = 0;
+  PyObject *__pyx_v_data2 = 0;
+  PmEvent __pyx_v_buffer[1];
+  PmError __pyx_v_err;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PmMessage __pyx_t_4;
+  int __pyx_t_5;
+  int __pyx_t_6;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__status,&__pyx_n_s__data1,&__pyx_n_s__data2,0};
+  __Pyx_RefNannySetupContext("WriteShort");
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[3] = {0,0,0};
+    values[1] = ((PyObject *)__pyx_int_0);
+    values[2] = ((PyObject *)__pyx_int_0);
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
+      case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      case  0: break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  0:
+      values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__status);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      if (kw_args > 1) {
+        PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__data1);
+        if (unlikely(value)) { values[1] = value; kw_args--; }
+      }
+      case  2:
+      if (kw_args > 1) {
+        PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__data2);
+        if (unlikely(value)) { values[2] = value; kw_args--; }
+      }
+    }
+    if (unlikely(kw_args > 0)) {
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "WriteShort") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 333; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_status = values[0];
+    __pyx_v_data1 = values[1];
+    __pyx_v_data2 = values[2];
+  } else {
+    __pyx_v_data1 = ((PyObject *)__pyx_int_0);
+    __pyx_v_data2 = ((PyObject *)__pyx_int_0);
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  3: __pyx_v_data2 = PyTuple_GET_ITEM(__pyx_args, 2);
+      case  2: __pyx_v_data1 = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: __pyx_v_status = PyTuple_GET_ITEM(__pyx_args, 0);
+      break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("WriteShort", 0, 1, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 333; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_pyportmidi.Output.WriteShort");
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+  __Pyx_INCREF(__pyx_v_status);
+  __Pyx_INCREF(__pyx_v_data1);
+  __Pyx_INCREF(__pyx_v_data2);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":348
+ *         cdef PmEvent buffer[1]
+ *         cdef PmError err
+ *         self._check_open()             # <<<<<<<<<<<<<<
+ * 
+ *         buffer[0].timestamp = Pt_Time()
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 348; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 348; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":350
+ *         self._check_open()
+ * 
+ *         buffer[0].timestamp = Pt_Time()             # <<<<<<<<<<<<<<
+ *         buffer[0].message = ((((data2) << 16) & 0xFF0000) | (((data1) << 8) & 0xFF00) | ((status) & 0xFF))
+ *         if self.debug: print "Writing to MIDI buffer"
+ */
+  (__pyx_v_buffer[0]).timestamp = Pt_Time();
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":351
+ * 
+ *         buffer[0].timestamp = Pt_Time()
+ *         buffer[0].message = ((((data2) << 16) & 0xFF0000) | (((data1) << 8) & 0xFF00) | ((status) & 0xFF))             # <<<<<<<<<<<<<<
+ *         if self.debug: print "Writing to MIDI buffer"
+ *         err = Pm_Write(self.midi, buffer, 1) # stream, buffer, length
+ */
+  __pyx_t_2 = PyNumber_Lshift(__pyx_v_data2, __pyx_int_16); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_1 = PyNumber_And(__pyx_t_2, __pyx_int_0xFF0000); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyNumber_Lshift(__pyx_v_data1, __pyx_int_8); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyNumber_And(__pyx_t_2, __pyx_int_0xFF00); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyNumber_Or(__pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_3 = PyNumber_And(__pyx_v_status, __pyx_int_0xFF); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_1 = PyNumber_Or(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_4 = __Pyx_PyInt_from_py_PmMessage(__pyx_t_1); if (unlikely((__pyx_t_4 == (PmMessage)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 351; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  (__pyx_v_buffer[0]).message = __pyx_t_4;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":352
+ *         buffer[0].timestamp = Pt_Time()
+ *         buffer[0].message = ((((data2) << 16) & 0xFF0000) | (((data1) << 8) & 0xFF00) | ((status) & 0xFF))
+ *         if self.debug: print "Writing to MIDI buffer"             # <<<<<<<<<<<<<<
+ *         err = Pm_Write(self.midi, buffer, 1) # stream, buffer, length
+ *         if err < 0 : raise Exception, Pm_GetErrorText(err)
+ */
+  __pyx_t_5 = ((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->debug;
+  if (__pyx_t_5) {
+    if (__Pyx_PrintOne(((PyObject *)__pyx_kp_s_11)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 352; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":353
+ *         buffer[0].message = ((((data2) << 16) & 0xFF0000) | (((data1) << 8) & 0xFF00) | ((status) & 0xFF))
+ *         if self.debug: print "Writing to MIDI buffer"
+ *         err = Pm_Write(self.midi, buffer, 1) # stream, buffer, length             # <<<<<<<<<<<<<<
+ *         if err < 0 : raise Exception, Pm_GetErrorText(err)
+ * 
+ */
+  __pyx_v_err = Pm_Write(((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi, __pyx_v_buffer, 1);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":354
+ *         if self.debug: print "Writing to MIDI buffer"
+ *         err = Pm_Write(self.midi, buffer, 1) # stream, buffer, length
+ *         if err < 0 : raise Exception, Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ * 
+ *     def WriteSysEx(self, when, msg):
+ */
+  __pyx_t_6 = (__pyx_v_err < 0);
+  if (__pyx_t_6) {
+    __pyx_t_1 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 354; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_1), 0);
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 354; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L7;
+  }
+  __pyx_L7:;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("_pyportmidi.Output.WriteShort");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_DECREF(__pyx_v_status);
+  __Pyx_DECREF(__pyx_v_data1);
+  __Pyx_DECREF(__pyx_v_data2);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":356
+ *         if err < 0 : raise Exception, Pm_GetErrorText(err)
+ * 
+ *     def WriteSysEx(self, when, msg):             # <<<<<<<<<<<<<<
+ *         """
+ *         WriteSysEx(<timestamp>,<msg>)
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_6Output_WriteSysEx(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static char __pyx_doc_11_pyportmidi_6Output_WriteSysEx[] = "\n        WriteSysEx(<timestamp>,<msg>)\n        writes a timestamped system-exclusive midi message.\n        <msg> can be a *list* or a *string*\n        example:\n            (assuming y is an input MIDI stream)\n            y.WriteSysEx(0,'\\xF0\\x7D\\x10\\x11\\x12\\x13\\xF7')\n                              is equivalent to\n            y.WriteSysEx(pypm.Time,\n            [0xF0, 0x7D, 0x10, 0x11, 0x12, 0x13, 0xF7])\n        ";
+static PyObject *__pyx_pf_11_pyportmidi_6Output_WriteSysEx(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_when = 0;
+  PyObject *__pyx_v_msg = 0;
+  PmError __pyx_v_err;
+  char *__pyx_v_cmsg;
+  PtTimestamp __pyx_v_CurTime;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  char *__pyx_t_5;
+  PmTimestamp __pyx_t_6;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__when,&__pyx_n_s__msg,0};
+  __Pyx_RefNannySetupContext("WriteSysEx");
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[2] = {0,0};
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      case  0: break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  0:
+      values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__when);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__msg);
+      if (likely(values[1])) kw_args--;
+      else {
+        __Pyx_RaiseArgtupleInvalid("WriteSysEx", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 356; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    }
+    if (unlikely(kw_args > 0)) {
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "WriteSysEx") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 356; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_when = values[0];
+    __pyx_v_msg = values[1];
+  } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
+    goto __pyx_L5_argtuple_error;
+  } else {
+    __pyx_v_when = PyTuple_GET_ITEM(__pyx_args, 0);
+    __pyx_v_msg = PyTuple_GET_ITEM(__pyx_args, 1);
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("WriteSysEx", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 356; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_pyportmidi.Output.WriteSysEx");
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+  __Pyx_INCREF(__pyx_v_when);
+  __Pyx_INCREF(__pyx_v_msg);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":372
+ *         cdef PtTimestamp CurTime
+ * 
+ *         self._check_open()             # <<<<<<<<<<<<<<
+ * 
+ *         if type(msg) is list:
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":374
+ *         self._check_open()
+ * 
+ *         if type(msg) is list:             # <<<<<<<<<<<<<<
+ *             msg = array.array('B',msg).tostring() # Markus Pfaff contribution
+ *         cmsg = msg
+ */
+  __pyx_t_3 = (((PyObject *)Py_TYPE(__pyx_v_msg)) == ((PyObject *)((PyObject*)&PyList_Type)));
+  if (__pyx_t_3) {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":375
+ * 
+ *         if type(msg) is list:
+ *             msg = array.array('B',msg).tostring() # Markus Pfaff contribution             # <<<<<<<<<<<<<<
+ *         cmsg = msg
+ * 
+ */
+    __pyx_t_2 = __Pyx_GetName(__pyx_m, __pyx_n_s__array); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__array); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __Pyx_INCREF(((PyObject *)__pyx_n_s__B));
+    PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_n_s__B));
+    __Pyx_GIVEREF(((PyObject *)__pyx_n_s__B));
+    __Pyx_INCREF(__pyx_v_msg);
+    PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_msg);
+    __Pyx_GIVEREF(__pyx_v_msg);
+    __pyx_t_4 = PyObject_Call(__pyx_t_1, __pyx_t_2, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __pyx_t_2 = PyObject_GetAttr(__pyx_t_4, __pyx_n_s__tostring); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_4 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 375; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __Pyx_DECREF(__pyx_v_msg);
+    __pyx_v_msg = __pyx_t_4;
+    __pyx_t_4 = 0;
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":376
+ *         if type(msg) is list:
+ *             msg = array.array('B',msg).tostring() # Markus Pfaff contribution
+ *         cmsg = msg             # <<<<<<<<<<<<<<
+ * 
+ *         CurTime = Pt_Time()
+ */
+  __pyx_t_5 = __Pyx_PyBytes_AsString(__pyx_v_msg); if (unlikely((!__pyx_t_5) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 376; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_cmsg = __pyx_t_5;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":378
+ *         cmsg = msg
+ * 
+ *         CurTime = Pt_Time()             # <<<<<<<<<<<<<<
+ *         err = Pm_WriteSysEx(self.midi, when, <unsigned char *> cmsg)
+ *         if err < 0 : raise Exception, Pm_GetErrorText(err)
+ */
+  __pyx_v_CurTime = Pt_Time();
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":379
+ * 
+ *         CurTime = Pt_Time()
+ *         err = Pm_WriteSysEx(self.midi, when, <unsigned char *> cmsg)             # <<<<<<<<<<<<<<
+ *         if err < 0 : raise Exception, Pm_GetErrorText(err)
+ *         while Pt_Time() == CurTime: # wait for SysEx to go thru or...my
+ */
+  __pyx_t_6 = __Pyx_PyInt_from_py_PmTimestamp(__pyx_v_when); if (unlikely((__pyx_t_6 == (PmTimestamp)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 379; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_err = Pm_WriteSysEx(((struct __pyx_obj_11_pyportmidi_Output *)__pyx_v_self)->midi, __pyx_t_6, ((unsigned char *)__pyx_v_cmsg));
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":380
+ *         CurTime = Pt_Time()
+ *         err = Pm_WriteSysEx(self.midi, when, <unsigned char *> cmsg)
+ *         if err < 0 : raise Exception, Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ *         while Pt_Time() == CurTime: # wait for SysEx to go thru or...my
+ *             pass                    # win32 machine crashes w/ multiple SysEx
+ */
+  __pyx_t_3 = (__pyx_v_err < 0);
+  if (__pyx_t_3) {
+    __pyx_t_4 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 380; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_4), 0);
+    __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 380; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L7;
+  }
+  __pyx_L7:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":381
+ *         err = Pm_WriteSysEx(self.midi, when, <unsigned char *> cmsg)
+ *         if err < 0 : raise Exception, Pm_GetErrorText(err)
+ *         while Pt_Time() == CurTime: # wait for SysEx to go thru or...my             # <<<<<<<<<<<<<<
+ *             pass                    # win32 machine crashes w/ multiple SysEx
+ * 
+ */
+  while (1) {
+    __pyx_t_3 = (Pt_Time() == __pyx_v_CurTime);
+    if (!__pyx_t_3) break;
+  }
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("_pyportmidi.Output.WriteSysEx");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_DECREF(__pyx_v_when);
+  __Pyx_DECREF(__pyx_v_msg);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":404
+ *     cdef int i
+ * 
+ *     def __init__(self, InputDevice, buffersize=4096):             # <<<<<<<<<<<<<<
+ *         cdef PmError err
+ *         self.i = InputDevice
+ */
+
+static int __pyx_pf_11_pyportmidi_5Input___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pf_11_pyportmidi_5Input___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_InputDevice = 0;
+  PyObject *__pyx_v_buffersize = 0;
+  PmError __pyx_v_err;
+  int __pyx_r;
+  int __pyx_t_1;
+  long __pyx_t_2;
+  int __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__InputDevice,&__pyx_n_s__buffersize,0};
+  __Pyx_RefNannySetupContext("__init__");
+  if (unlikely(__pyx_kwds)) {
+    Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
+    PyObject* values[2] = {0,0};
+    values[1] = ((PyObject *)__pyx_int_4096);
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      case  0: break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  0:
+      values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__InputDevice);
+      if (likely(values[0])) kw_args--;
+      else goto __pyx_L5_argtuple_error;
+      case  1:
+      if (kw_args > 1) {
+        PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__buffersize);
+        if (unlikely(value)) { values[1] = value; kw_args--; }
+      }
+    }
+    if (unlikely(kw_args > 0)) {
+      if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 404; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    }
+    __pyx_v_InputDevice = values[0];
+    __pyx_v_buffersize = values[1];
+  } else {
+    __pyx_v_buffersize = ((PyObject *)__pyx_int_4096);
+    switch (PyTuple_GET_SIZE(__pyx_args)) {
+      case  2: __pyx_v_buffersize = PyTuple_GET_ITEM(__pyx_args, 1);
+      case  1: __pyx_v_InputDevice = PyTuple_GET_ITEM(__pyx_args, 0);
+      break;
+      default: goto __pyx_L5_argtuple_error;
+    }
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__init__", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 404; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_pyportmidi.Input.__init__");
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+  __Pyx_INCREF(__pyx_v_InputDevice);
+  __Pyx_INCREF(__pyx_v_buffersize);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":406
+ *     def __init__(self, InputDevice, buffersize=4096):
+ *         cdef PmError err
+ *         self.i = InputDevice             # <<<<<<<<<<<<<<
+ *         self.debug = 0
+ *         err= Pm_OpenInput(&(self.midi),self.i,NULL,buffersize,&Pt_Time,NULL)
+ */
+  __pyx_t_1 = __Pyx_PyInt_AsInt(__pyx_v_InputDevice); if (unlikely((__pyx_t_1 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 406; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  ((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->i = __pyx_t_1;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":407
+ *         cdef PmError err
+ *         self.i = InputDevice
+ *         self.debug = 0             # <<<<<<<<<<<<<<
+ *         err= Pm_OpenInput(&(self.midi),self.i,NULL,buffersize,&Pt_Time,NULL)
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)
+ */
+  ((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->debug = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":408
+ *         self.i = InputDevice
+ *         self.debug = 0
+ *         err= Pm_OpenInput(&(self.midi),self.i,NULL,buffersize,&Pt_Time,NULL)             # <<<<<<<<<<<<<<
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)
+ *         if self.debug: print "MIDI input opened."
+ */
+  __pyx_t_2 = __Pyx_PyInt_AsLong(__pyx_v_buffersize); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 408; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_err = Pm_OpenInput((&((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi), ((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->i, NULL, __pyx_t_2, (&Pt_Time), NULL);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":409
+ *         self.debug = 0
+ *         err= Pm_OpenInput(&(self.midi),self.i,NULL,buffersize,&Pt_Time,NULL)
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ *         if self.debug: print "MIDI input opened."
+ * 
+ */
+  __pyx_t_3 = (__pyx_v_err < 0);
+  if (__pyx_t_3) {
+    __pyx_t_4 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 409; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_4), 0);
+    __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 409; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":410
+ *         err= Pm_OpenInput(&(self.midi),self.i,NULL,buffersize,&Pt_Time,NULL)
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)
+ *         if self.debug: print "MIDI input opened."             # <<<<<<<<<<<<<<
+ * 
+ *     def __dealloc__(self):
+ */
+  __pyx_t_1 = ((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->debug;
+  if (__pyx_t_1) {
+    if (__Pyx_PrintOne(((PyObject *)__pyx_kp_s_12)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 410; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L7;
+  }
+  __pyx_L7:;
+
+  __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("_pyportmidi.Input.__init__");
+  __pyx_r = -1;
+  __pyx_L0:;
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_DECREF(__pyx_v_InputDevice);
+  __Pyx_DECREF(__pyx_v_buffersize);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":412
+ *         if self.debug: print "MIDI input opened."
+ * 
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         cdef PmError err
+ *         if self.debug: print "Closing MIDI input stream and destroying instance"
+ */
+
+static void __pyx_pf_11_pyportmidi_5Input___dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pf_11_pyportmidi_5Input___dealloc__(PyObject *__pyx_v_self) {
+  PmError __pyx_v_err;
+  int __pyx_t_1;
+  int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  __Pyx_RefNannySetupContext("__dealloc__");
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":414
+ *     def __dealloc__(self):
+ *         cdef PmError err
+ *         if self.debug: print "Closing MIDI input stream and destroying instance"             # <<<<<<<<<<<<<<
+ * 
+ *         err = Pm_Close(self.midi)
+ */
+  __pyx_t_1 = ((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->debug;
+  if (__pyx_t_1) {
+    if (__Pyx_PrintOne(((PyObject *)__pyx_kp_s_13)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 414; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":416
+ *         if self.debug: print "Closing MIDI input stream and destroying instance"
+ * 
+ *         err = Pm_Close(self.midi)             # <<<<<<<<<<<<<<
+ *         if err < 0:
+ *             raise Exception, Pm_GetErrorText(err)
+ */
+  __pyx_v_err = Pm_Close(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":417
+ * 
+ *         err = Pm_Close(self.midi)
+ *         if err < 0:             # <<<<<<<<<<<<<<
+ *             raise Exception, Pm_GetErrorText(err)
+ * 
+ */
+  __pyx_t_2 = (__pyx_v_err < 0);
+  if (__pyx_t_2) {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":418
+ *         err = Pm_Close(self.midi)
+ *         if err < 0:
+ *             raise Exception, Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ * 
+ * 
+ */
+    __pyx_t_3 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 418; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_3), 0);
+    __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 418; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("_pyportmidi.Input.__dealloc__");
+  __pyx_L0:;
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_RefNannyFinishContext();
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":422
+ * 
+ * 
+ *     def _check_open(self):             # <<<<<<<<<<<<<<
+ *         """ checks to see if the midi is open, and if not, raises an error.
+ *         """
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_5Input__check_open(PyObject *__pyx_v_self, PyObject *unused); /*proto*/
+static char __pyx_doc_11_pyportmidi_5Input__check_open[] = " checks to see if the midi is open, and if not, raises an error.\n        ";
+static PyObject *__pyx_pf_11_pyportmidi_5Input__check_open(PyObject *__pyx_v_self, PyObject *unused) {
+  PyObject *__pyx_r = NULL;
+  int __pyx_t_1;
+  __Pyx_RefNannySetupContext("_check_open");
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":426
+ *         """
+ * 
+ *         if self.midi == NULL:             # <<<<<<<<<<<<<<
+ *             raise Exception, "midi Input not open."
+ * 
+ */
+  __pyx_t_1 = (((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi == NULL);
+  if (__pyx_t_1) {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":427
+ * 
+ *         if self.midi == NULL:
+ *             raise Exception, "midi Input not open."             # <<<<<<<<<<<<<<
+ * 
+ * 
+ */
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_kp_s_14), 0);
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 427; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_pyportmidi.Input._check_open");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":430
+ * 
+ * 
+ *     def Close(self):             # <<<<<<<<<<<<<<
+ *         """
+ * Close()
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_5Input_Close(PyObject *__pyx_v_self, PyObject *unused); /*proto*/
+static char __pyx_doc_11_pyportmidi_5Input_Close[] = "\nClose()\n    closes a midi stream, flushing any pending buffers.\n    (PortMidi attempts to close open streams when the application\n    exits -- this is particularly difficult under Windows.)\n        ";
+static PyObject *__pyx_pf_11_pyportmidi_5Input_Close(PyObject *__pyx_v_self, PyObject *unused) {
+  PyObject *__pyx_v_err;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  PmError __pyx_t_3;
+  __Pyx_RefNannySetupContext("Close");
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+  __pyx_v_err = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":440
+ *         #    return
+ * 
+ *         err = Pm_Close(self.midi)             # <<<<<<<<<<<<<<
+ *         if err < 0:
+ *             raise Exception, Pm_GetErrorText(err)
+ */
+  __pyx_t_1 = PyInt_FromLong(Pm_Close(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 440; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__pyx_v_err);
+  __pyx_v_err = __pyx_t_1;
+  __pyx_t_1 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":441
+ * 
+ *         err = Pm_Close(self.midi)
+ *         if err < 0:             # <<<<<<<<<<<<<<
+ *             raise Exception, Pm_GetErrorText(err)
+ *         #self.midi = NULL
+ */
+  __pyx_t_1 = PyObject_RichCompare(__pyx_v_err, __pyx_int_0, Py_LT); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 441; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 441; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":442
+ *         err = Pm_Close(self.midi)
+ *         if err < 0:
+ *             raise Exception, Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ *         #self.midi = NULL
+ * 
+ */
+    __pyx_t_3 = ((PmError)PyInt_AsLong(__pyx_v_err)); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 442; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_t_3)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 442; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_1), 0);
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 442; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_pyportmidi.Input.Close");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_err);
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":447
+ * 
+ * 
+ *     def SetFilter(self, filters):             # <<<<<<<<<<<<<<
+ *         """
+ *     SetFilter(<filters>) sets filters on an open input stream
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_5Input_SetFilter(PyObject *__pyx_v_self, PyObject *__pyx_v_filters); /*proto*/
+static char __pyx_doc_11_pyportmidi_5Input_SetFilter[] = "\n    SetFilter(<filters>) sets filters on an open input stream\n    to drop selected input types. By default, only active sensing\n    messages are filtered. To prohibit, say, active sensing and\n    sysex messages, call\n    SetFilter(stream, FILT_ACTIVE | FILT_SYSEX);\n\n    Filtering is useful when midi routing or midi thru functionality\n    is being provided by the user application.\n    For example, you may want to exclude timing messages\n    (clock, MTC, start/stop/continue), while allowing note-related\n    messages to pass. Or you may be using a sequencer or drum-machine\n    for MIDI clock information but want to exclude any notes\n    it may play.\n\n    Note: SetFilter empties the buffer after setting the filter,\n    just in case anything got through.\n        ";
+static PyObject *__pyx_pf_11_pyportmidi_5Input_SetFilter(PyObject *__pyx_v_self, PyObject *__pyx_v_filters) {
+  PmEvent __pyx_v_buffer[1];
+  PmError __pyx_v_err;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  long __pyx_t_3;
+  int __pyx_t_4;
+  __Pyx_RefNannySetupContext("SetFilter");
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+  __Pyx_INCREF(__pyx_v_filters);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":469
+ *         cdef PmError err
+ * 
+ *         self._check_open()             # <<<<<<<<<<<<<<
+ * 
+ * 
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 469; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 469; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":472
+ * 
+ * 
+ *         err = Pm_SetFilter(self.midi, filters)             # <<<<<<<<<<<<<<
+ * 
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)
+ */
+  __pyx_t_3 = __Pyx_PyInt_AsLong(__pyx_v_filters); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 472; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_err = Pm_SetFilter(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi, __pyx_t_3);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":474
+ *         err = Pm_SetFilter(self.midi, filters)
+ * 
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ * 
+ *         while(Pm_Poll(self.midi) != pmNoError):
+ */
+  __pyx_t_4 = (__pyx_v_err < 0);
+  if (__pyx_t_4) {
+    __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 474; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_2), 0);
+    __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 474; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":476
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)
+ * 
+ *         while(Pm_Poll(self.midi) != pmNoError):             # <<<<<<<<<<<<<<
+ * 
+ *             err = Pm_Read(self.midi,buffer,1)
+ */
+  while (1) {
+    __pyx_t_4 = (Pm_Poll(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi) != pmNoError);
+    if (!__pyx_t_4) break;
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":478
+ *         while(Pm_Poll(self.midi) != pmNoError):
+ * 
+ *             err = Pm_Read(self.midi,buffer,1)             # <<<<<<<<<<<<<<
+ *             if err < 0: raise Exception, Pm_GetErrorText(err)
+ * 
+ */
+    __pyx_v_err = Pm_Read(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi, __pyx_v_buffer, 1);
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":479
+ * 
+ *             err = Pm_Read(self.midi,buffer,1)
+ *             if err < 0: raise Exception, Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ * 
+ *     def SetChannelMask(self, mask):
+ */
+    __pyx_t_4 = (__pyx_v_err < 0);
+    if (__pyx_t_4) {
+      __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 479; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+      __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_2), 0);
+      __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 479; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      goto __pyx_L8;
+    }
+    __pyx_L8:;
+  }
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_pyportmidi.Input.SetFilter");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_DECREF(__pyx_v_filters);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":481
+ *             if err < 0: raise Exception, Pm_GetErrorText(err)
+ * 
+ *     def SetChannelMask(self, mask):             # <<<<<<<<<<<<<<
+ *         """
+ *     SetChannelMask(<mask>) filters incoming messages based on channel.
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_5Input_SetChannelMask(PyObject *__pyx_v_self, PyObject *__pyx_v_mask); /*proto*/
+static char __pyx_doc_11_pyportmidi_5Input_SetChannelMask[] = "\n    SetChannelMask(<mask>) filters incoming messages based on channel.\n    The mask is a 16-bit bitfield corresponding to appropriate channels\n    Channel(<channel>) can assist in calling this function.\n    i.e. to set receive only input on channel 1, call with\n    SetChannelMask(Channel(1))\n    Multiple channels should be OR'd together, like\n    SetChannelMask(Channel(10) | Channel(11))\n    note: PyPortMidi Channel function has been altered from\n          the original PortMidi c call to correct for what\n          seems to be a bug --- i.e. channel filters were\n          all numbered from 0 to 15 instead of 1 to 16.\n        ";
+static PyObject *__pyx_pf_11_pyportmidi_5Input_SetChannelMask(PyObject *__pyx_v_self, PyObject *__pyx_v_mask) {
+  PmError __pyx_v_err;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_t_3;
+  int __pyx_t_4;
+  __Pyx_RefNannySetupContext("SetChannelMask");
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+  __Pyx_INCREF(__pyx_v_mask);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":497
+ *         cdef PmError err
+ * 
+ *         self._check_open()             # <<<<<<<<<<<<<<
+ * 
+ *         err = Pm_SetChannelMask(self.midi,mask)
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 497; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 497; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":499
+ *         self._check_open()
+ * 
+ *         err = Pm_SetChannelMask(self.midi,mask)             # <<<<<<<<<<<<<<
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)
+ * 
+ */
+  __pyx_t_3 = __Pyx_PyInt_AsInt(__pyx_v_mask); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 499; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_err = Pm_SetChannelMask(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi, __pyx_t_3);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":500
+ * 
+ *         err = Pm_SetChannelMask(self.midi,mask)
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ * 
+ *     def Poll(self):
+ */
+  __pyx_t_4 = (__pyx_v_err < 0);
+  if (__pyx_t_4) {
+    __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 500; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_2), 0);
+    __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 500; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_pyportmidi.Input.SetChannelMask");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_DECREF(__pyx_v_mask);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":502
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)
+ * 
+ *     def Poll(self):             # <<<<<<<<<<<<<<
+ *         """
+ *     Poll tests whether input is available,
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_5Input_Poll(PyObject *__pyx_v_self, PyObject *unused); /*proto*/
+static char __pyx_doc_11_pyportmidi_5Input_Poll[] = "\n    Poll tests whether input is available,\n    returning TRUE, FALSE, or an error value.\n        ";
+static PyObject *__pyx_pf_11_pyportmidi_5Input_Poll(PyObject *__pyx_v_self, PyObject *unused) {
+  PmError __pyx_v_err;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_t_3;
+  __Pyx_RefNannySetupContext("Poll");
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":508
+ *         """
+ *         cdef PmError err
+ *         self._check_open()             # <<<<<<<<<<<<<<
+ * 
+ *         err = Pm_Poll(self.midi)
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 508; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 508; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":510
+ *         self._check_open()
+ * 
+ *         err = Pm_Poll(self.midi)             # <<<<<<<<<<<<<<
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)
+ *         return err
+ */
+  __pyx_v_err = Pm_Poll(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":511
+ * 
+ *         err = Pm_Poll(self.midi)
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)             # <<<<<<<<<<<<<<
+ *         return err
+ * 
+ */
+  __pyx_t_3 = (__pyx_v_err < 0);
+  if (__pyx_t_3) {
+    __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_v_err)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 511; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_2), 0);
+    __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 511; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":512
+ *         err = Pm_Poll(self.midi)
+ *         if err < 0: raise Exception, Pm_GetErrorText(err)
+ *         return err             # <<<<<<<<<<<<<<
+ * 
+ *     def Read(self,length):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_2 = PyInt_FromLong(__pyx_v_err); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_r = __pyx_t_2;
+  __pyx_t_2 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_pyportmidi.Input.Poll");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":514
+ *         return err
+ * 
+ *     def Read(self,length):             # <<<<<<<<<<<<<<
+ *         """
+ * Read(length): returns up to <length> midi events stored in
+ */
+
+static PyObject *__pyx_pf_11_pyportmidi_5Input_Read(PyObject *__pyx_v_self, PyObject *__pyx_v_length); /*proto*/
+static char __pyx_doc_11_pyportmidi_5Input_Read[] = "\nRead(length): returns up to <length> midi events stored in\nthe buffer and returns them as a list:\n[[[status,data1,data2,data3],timestamp],\n [[status,data1,data2,data3],timestamp],...]\nexample: Read(50) returns all the events in the buffer,\n         up to 50 events.\n        ";
+static PyObject *__pyx_pf_11_pyportmidi_5Input_Read(PyObject *__pyx_v_self, PyObject *__pyx_v_length) {
+  PmEvent __pyx_v_buffer[1024];
+  PyObject *__pyx_v_x;
+  PyObject *__pyx_v_NumEvents;
+  PyObject *__pyx_v_loop;
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_t_3;
+  long __pyx_t_4;
+  PmError __pyx_t_5;
+  Py_ssize_t __pyx_t_6;
+  Py_ssize_t __pyx_t_7;
+  PyObject *__pyx_t_8 = NULL;
+  PyObject *__pyx_t_9 = NULL;
+  PyObject *__pyx_t_10 = NULL;
+  PyObject *__pyx_t_11 = NULL;
+  __Pyx_RefNannySetupContext("Read");
+  __Pyx_INCREF((PyObject *)__pyx_v_self);
+  __Pyx_INCREF(__pyx_v_length);
+  __pyx_v_x = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_v_NumEvents = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_v_loop = Py_None; __Pyx_INCREF(Py_None);
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":525
+ *         cdef PmEvent buffer[1024]
+ * 
+ *         self._check_open()             # <<<<<<<<<<<<<<
+ * 
+ *         x = []
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_self, __pyx_n_s___check_open); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 525; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 525; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":527
+ *         self._check_open()
+ * 
+ *         x = []             # <<<<<<<<<<<<<<
+ * 
+ *         if length > 1024: raise IndexError, 'maximum buffer length is 1024'
+ */
+  __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 527; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  __Pyx_DECREF(__pyx_v_x);
+  __pyx_v_x = ((PyObject *)__pyx_t_2);
+  __pyx_t_2 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":529
+ *         x = []
+ * 
+ *         if length > 1024: raise IndexError, 'maximum buffer length is 1024'             # <<<<<<<<<<<<<<
+ *         if length < 1: raise IndexError, 'minimum buffer length is 1'
+ *         NumEvents = Pm_Read(self.midi,buffer,length)
+ */
+  __pyx_t_2 = PyObject_RichCompare(__pyx_v_length, __pyx_int_1024, Py_GT); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 529; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 529; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (__pyx_t_3) {
+    __Pyx_Raise(__pyx_builtin_IndexError, ((PyObject *)__pyx_kp_s_15), 0);
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 529; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":530
+ * 
+ *         if length > 1024: raise IndexError, 'maximum buffer length is 1024'
+ *         if length < 1: raise IndexError, 'minimum buffer length is 1'             # <<<<<<<<<<<<<<
+ *         NumEvents = Pm_Read(self.midi,buffer,length)
+ *         if NumEvents < 0: raise Exception, Pm_GetErrorText(NumEvents)
+ */
+  __pyx_t_2 = PyObject_RichCompare(__pyx_v_length, __pyx_int_1, Py_LT); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 530; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 530; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (__pyx_t_3) {
+    __Pyx_Raise(__pyx_builtin_IndexError, ((PyObject *)__pyx_kp_s_16), 0);
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 530; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":531
+ *         if length > 1024: raise IndexError, 'maximum buffer length is 1024'
+ *         if length < 1: raise IndexError, 'minimum buffer length is 1'
+ *         NumEvents = Pm_Read(self.midi,buffer,length)             # <<<<<<<<<<<<<<
+ *         if NumEvents < 0: raise Exception, Pm_GetErrorText(NumEvents)
+ *         x=[]
+ */
+  __pyx_t_4 = __Pyx_PyInt_AsLong(__pyx_v_length); if (unlikely((__pyx_t_4 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 531; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyInt_FromLong(Pm_Read(((struct __pyx_obj_11_pyportmidi_Input *)__pyx_v_self)->midi, __pyx_v_buffer, __pyx_t_4)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 531; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_v_NumEvents);
+  __pyx_v_NumEvents = __pyx_t_2;
+  __pyx_t_2 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":532
+ *         if length < 1: raise IndexError, 'minimum buffer length is 1'
+ *         NumEvents = Pm_Read(self.midi,buffer,length)
+ *         if NumEvents < 0: raise Exception, Pm_GetErrorText(NumEvents)             # <<<<<<<<<<<<<<
+ *         x=[]
+ *         if NumEvents >= 1:
+ */
+  __pyx_t_2 = PyObject_RichCompare(__pyx_v_NumEvents, __pyx_int_0, Py_LT); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (__pyx_t_3) {
+    __pyx_t_5 = ((PmError)PyInt_AsLong(__pyx_v_NumEvents)); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = __Pyx_PyBytes_FromString(Pm_GetErrorText(__pyx_t_5)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+    __Pyx_Raise(__pyx_builtin_Exception, ((PyObject *)__pyx_t_2), 0);
+    __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L7;
+  }
+  __pyx_L7:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":533
+ *         NumEvents = Pm_Read(self.midi,buffer,length)
+ *         if NumEvents < 0: raise Exception, Pm_GetErrorText(NumEvents)
+ *         x=[]             # <<<<<<<<<<<<<<
+ *         if NumEvents >= 1:
+ *             for loop in range(NumEvents):
+ */
+  __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 533; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  __Pyx_DECREF(__pyx_v_x);
+  __pyx_v_x = ((PyObject *)__pyx_t_2);
+  __pyx_t_2 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":534
+ *         if NumEvents < 0: raise Exception, Pm_GetErrorText(NumEvents)
+ *         x=[]
+ *         if NumEvents >= 1:             # <<<<<<<<<<<<<<
+ *             for loop in range(NumEvents):
+ *                  x.append([[buffer[loop].message & 0xff, (buffer[loop].message >> 8) & 0xFF, (buffer[loop].message >> 16) & 0xFF, (buffer[loop].message >> 24) & 0xFF], buffer[loop].timestamp])
+ */
+  __pyx_t_2 = PyObject_RichCompare(__pyx_v_NumEvents, __pyx_int_1, Py_GE); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 534; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 534; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (__pyx_t_3) {
+
+    /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":535
+ *         x=[]
+ *         if NumEvents >= 1:
+ *             for loop in range(NumEvents):             # <<<<<<<<<<<<<<
+ *                  x.append([[buffer[loop].message & 0xff, (buffer[loop].message >> 8) & 0xFF, (buffer[loop].message >> 16) & 0xFF, (buffer[loop].message >> 24) & 0xFF], buffer[loop].timestamp])
+ *         return x
+ */
+    __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 535; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __Pyx_INCREF(__pyx_v_NumEvents);
+    PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_NumEvents);
+    __Pyx_GIVEREF(__pyx_v_NumEvents);
+    __pyx_t_1 = PyObject_Call(__pyx_builtin_range, __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 535; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    if (PyList_CheckExact(__pyx_t_1) || PyTuple_CheckExact(__pyx_t_1)) {
+      __pyx_t_6 = 0; __pyx_t_2 = __pyx_t_1; __Pyx_INCREF(__pyx_t_2);
+    } else {
+      __pyx_t_6 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 535; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_2);
+    }
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    for (;;) {
+      if (likely(PyList_CheckExact(__pyx_t_2))) {
+        if (__pyx_t_6 >= PyList_GET_SIZE(__pyx_t_2)) break;
+        __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_6); __Pyx_INCREF(__pyx_t_1); __pyx_t_6++;
+      } else if (likely(PyTuple_CheckExact(__pyx_t_2))) {
+        if (__pyx_t_6 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
+        __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_6); __Pyx_INCREF(__pyx_t_1); __pyx_t_6++;
+      } else {
+        __pyx_t_1 = PyIter_Next(__pyx_t_2);
+        if (!__pyx_t_1) {
+          if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 535; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          break;
+        }
+        __Pyx_GOTREF(__pyx_t_1);
+      }
+      __Pyx_DECREF(__pyx_v_loop);
+      __pyx_v_loop = __pyx_t_1;
+      __pyx_t_1 = 0;
+
+      /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":536
+ *         if NumEvents >= 1:
+ *             for loop in range(NumEvents):
+ *                  x.append([[buffer[loop].message & 0xff, (buffer[loop].message >> 8) & 0xFF, (buffer[loop].message >> 16) & 0xFF, (buffer[loop].message >> 24) & 0xFF], buffer[loop].timestamp])             # <<<<<<<<<<<<<<
+ *         return x
+ */
+      __pyx_t_7 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop); if (unlikely((__pyx_t_7 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_1 = __Pyx_PyInt_to_py_PmMessage(((__pyx_v_buffer[__pyx_t_7]).message & 0xff)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_1);
+      __pyx_t_7 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop); if (unlikely((__pyx_t_7 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_8 = __Pyx_PyInt_to_py_PmMessage((((__pyx_v_buffer[__pyx_t_7]).message >> 8) & 0xFF)); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_8);
+      __pyx_t_7 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop); if (unlikely((__pyx_t_7 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_9 = __Pyx_PyInt_to_py_PmMessage((((__pyx_v_buffer[__pyx_t_7]).message >> 16) & 0xFF)); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_9);
+      __pyx_t_7 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop); if (unlikely((__pyx_t_7 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_10 = __Pyx_PyInt_to_py_PmMessage((((__pyx_v_buffer[__pyx_t_7]).message >> 24) & 0xFF)); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_10);
+      __pyx_t_11 = PyList_New(4); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_11));
+      PyList_SET_ITEM(__pyx_t_11, 0, __pyx_t_1);
+      __Pyx_GIVEREF(__pyx_t_1);
+      PyList_SET_ITEM(__pyx_t_11, 1, __pyx_t_8);
+      __Pyx_GIVEREF(__pyx_t_8);
+      PyList_SET_ITEM(__pyx_t_11, 2, __pyx_t_9);
+      __Pyx_GIVEREF(__pyx_t_9);
+      PyList_SET_ITEM(__pyx_t_11, 3, __pyx_t_10);
+      __Pyx_GIVEREF(__pyx_t_10);
+      __pyx_t_1 = 0;
+      __pyx_t_8 = 0;
+      __pyx_t_9 = 0;
+      __pyx_t_10 = 0;
+      __pyx_t_7 = __Pyx_PyIndex_AsSsize_t(__pyx_v_loop); if (unlikely((__pyx_t_7 == (Py_ssize_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_10 = __Pyx_PyInt_to_py_PmTimestamp((__pyx_v_buffer[__pyx_t_7]).timestamp); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_10);
+      __pyx_t_9 = PyList_New(2); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_9));
+      PyList_SET_ITEM(__pyx_t_9, 0, ((PyObject *)__pyx_t_11));
+      __Pyx_GIVEREF(((PyObject *)__pyx_t_11));
+      PyList_SET_ITEM(__pyx_t_9, 1, __pyx_t_10);
+      __Pyx_GIVEREF(__pyx_t_10);
+      __pyx_t_11 = 0;
+      __pyx_t_10 = 0;
+      __pyx_t_10 = __Pyx_PyObject_Append(__pyx_v_x, ((PyObject *)__pyx_t_9)); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 536; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_10);
+      __Pyx_DECREF(((PyObject *)__pyx_t_9)); __pyx_t_9 = 0;
+      __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+    }
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    goto __pyx_L8;
+  }
+  __pyx_L8:;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":537
+ *             for loop in range(NumEvents):
+ *                  x.append([[buffer[loop].message & 0xff, (buffer[loop].message >> 8) & 0xFF, (buffer[loop].message >> 16) & 0xFF, (buffer[loop].message >> 24) & 0xFF], buffer[loop].timestamp])
+ *         return x             # <<<<<<<<<<<<<<
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(__pyx_v_x);
+  __pyx_r = __pyx_v_x;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_8);
+  __Pyx_XDECREF(__pyx_t_9);
+  __Pyx_XDECREF(__pyx_t_10);
+  __Pyx_XDECREF(__pyx_t_11);
+  __Pyx_AddTraceback("_pyportmidi.Input.Read");
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(__pyx_v_x);
+  __Pyx_DECREF(__pyx_v_NumEvents);
+  __Pyx_DECREF(__pyx_v_loop);
+  __Pyx_DECREF((PyObject *)__pyx_v_self);
+  __Pyx_DECREF(__pyx_v_length);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_tp_new_11_pyportmidi_Output(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_11_pyportmidi_Output(PyObject *o) {
+  {
+    PyObject *etype, *eval, *etb;
+    PyErr_Fetch(&etype, &eval, &etb);
+    ++Py_REFCNT(o);
+    __pyx_pf_11_pyportmidi_6Output___dealloc__(o);
+    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
+    --Py_REFCNT(o);
+    PyErr_Restore(etype, eval, etb);
+  }
+  (*Py_TYPE(o)->tp_free)(o);
+}
+
+static struct PyMethodDef __pyx_methods_11_pyportmidi_Output[] = {
+  {__Pyx_NAMESTR("_check_open"), (PyCFunction)__pyx_pf_11_pyportmidi_6Output__check_open, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_6Output__check_open)},
+  {__Pyx_NAMESTR("Close"), (PyCFunction)__pyx_pf_11_pyportmidi_6Output_Close, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_6Output_Close)},
+  {__Pyx_NAMESTR("Abort"), (PyCFunction)__pyx_pf_11_pyportmidi_6Output_Abort, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_6Output_Abort)},
+  {__Pyx_NAMESTR("Write"), (PyCFunction)__pyx_pf_11_pyportmidi_6Output_Write, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_6Output_Write)},
+  {__Pyx_NAMESTR("WriteShort"), (PyCFunction)__pyx_pf_11_pyportmidi_6Output_WriteShort, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_6Output_WriteShort)},
+  {__Pyx_NAMESTR("WriteSysEx"), (PyCFunction)__pyx_pf_11_pyportmidi_6Output_WriteSysEx, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_6Output_WriteSysEx)},
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_Output = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION >= 3
+  0, /*reserved*/
+  #else
+  0, /*nb_long*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_INDEX)
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_Output = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_Output = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_Output = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+PyTypeObject __pyx_type_11_pyportmidi_Output = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_pyportmidi.Output"), /*tp_name*/
+  sizeof(struct __pyx_obj_11_pyportmidi_Output), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_11_pyportmidi_Output, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  0, /*tp_compare*/
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_Output, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Output, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Output, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_Output, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER, /*tp_flags*/
+  __Pyx_DOCSTR("\nclass Output:\n    define an output MIDI stream. Takes the form:\n        x = pypm.Output(MidiOutputDevice, latency)\n    latency is in ms.\n    If latency = 0 then timestamps for output are ignored.\n    "), /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_11_pyportmidi_Output, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  __pyx_pf_11_pyportmidi_6Output___init__, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_11_pyportmidi_Output, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyObject *__pyx_tp_new_11_pyportmidi_Input(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_11_pyportmidi_Input(PyObject *o) {
+  {
+    PyObject *etype, *eval, *etb;
+    PyErr_Fetch(&etype, &eval, &etb);
+    ++Py_REFCNT(o);
+    __pyx_pf_11_pyportmidi_5Input___dealloc__(o);
+    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
+    --Py_REFCNT(o);
+    PyErr_Restore(etype, eval, etb);
+  }
+  (*Py_TYPE(o)->tp_free)(o);
+}
+
+static struct PyMethodDef __pyx_methods_11_pyportmidi_Input[] = {
+  {__Pyx_NAMESTR("_check_open"), (PyCFunction)__pyx_pf_11_pyportmidi_5Input__check_open, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_5Input__check_open)},
+  {__Pyx_NAMESTR("Close"), (PyCFunction)__pyx_pf_11_pyportmidi_5Input_Close, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_5Input_Close)},
+  {__Pyx_NAMESTR("SetFilter"), (PyCFunction)__pyx_pf_11_pyportmidi_5Input_SetFilter, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_5Input_SetFilter)},
+  {__Pyx_NAMESTR("SetChannelMask"), (PyCFunction)__pyx_pf_11_pyportmidi_5Input_SetChannelMask, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_5Input_SetChannelMask)},
+  {__Pyx_NAMESTR("Poll"), (PyCFunction)__pyx_pf_11_pyportmidi_5Input_Poll, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_5Input_Poll)},
+  {__Pyx_NAMESTR("Read"), (PyCFunction)__pyx_pf_11_pyportmidi_5Input_Read, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_5Input_Read)},
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_Input = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION >= 3
+  0, /*reserved*/
+  #else
+  0, /*nb_long*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_INDEX)
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_Input = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_Input = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_Input = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+PyTypeObject __pyx_type_11_pyportmidi_Input = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_pyportmidi.Input"), /*tp_name*/
+  sizeof(struct __pyx_obj_11_pyportmidi_Input), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_11_pyportmidi_Input, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  0, /*tp_compare*/
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_Input, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Input, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Input, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_Input, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER, /*tp_flags*/
+  __Pyx_DOCSTR("\nclass Input:\n    define an input MIDI stream. Takes the form:\n        x = pypm.Input(MidiInputDevice)\n    "), /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_11_pyportmidi_Input, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  __pyx_pf_11_pyportmidi_5Input___init__, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_11_pyportmidi_Input, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static struct PyMethodDef __pyx_methods[] = {
+  {__Pyx_NAMESTR("Initialize"), (PyCFunction)__pyx_pf_11_pyportmidi_Initialize, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_Initialize)},
+  {__Pyx_NAMESTR("Terminate"), (PyCFunction)__pyx_pf_11_pyportmidi_Terminate, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_Terminate)},
+  {__Pyx_NAMESTR("GetDefaultInputDeviceID"), (PyCFunction)__pyx_pf_11_pyportmidi_GetDefaultInputDeviceID, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("GetDefaultOutputDeviceID"), (PyCFunction)__pyx_pf_11_pyportmidi_GetDefaultOutputDeviceID, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("CountDevices"), (PyCFunction)__pyx_pf_11_pyportmidi_CountDevices, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("GetDeviceInfo"), (PyCFunction)__pyx_pf_11_pyportmidi_GetDeviceInfo, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_GetDeviceInfo)},
+  {__Pyx_NAMESTR("Time"), (PyCFunction)__pyx_pf_11_pyportmidi_Time, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_Time)},
+  {__Pyx_NAMESTR("GetErrorText"), (PyCFunction)__pyx_pf_11_pyportmidi_GetErrorText, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_GetErrorText)},
+  {__Pyx_NAMESTR("Channel"), (PyCFunction)__pyx_pf_11_pyportmidi_Channel, METH_O, __Pyx_DOCSTR(__pyx_doc_11_pyportmidi_Channel)},
+  {0, 0, 0, 0}
+};
+
+static void __pyx_init_filenames(void); /*proto*/
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef __pyx_moduledef = {
+    PyModuleDef_HEAD_INIT,
+    __Pyx_NAMESTR("_pyportmidi"),
+    0, /* m_doc */
+    -1, /* m_size */
+    __pyx_methods /* m_methods */,
+    NULL, /* m_reload */
+    NULL, /* m_traverse */
+    NULL, /* m_clear */
+    NULL /* m_free */
+};
+#endif
+
+static __Pyx_StringTabEntry __pyx_string_tab[] = {
+  {&__pyx_kp_s_1, __pyx_k_1, sizeof(__pyx_k_1), 0, 0, 1, 0},
+  {&__pyx_kp_s_10, __pyx_k_10, sizeof(__pyx_k_10), 0, 0, 1, 0},
+  {&__pyx_kp_s_11, __pyx_k_11, sizeof(__pyx_k_11), 0, 0, 1, 0},
+  {&__pyx_kp_s_12, __pyx_k_12, sizeof(__pyx_k_12), 0, 0, 1, 0},
+  {&__pyx_kp_s_13, __pyx_k_13, sizeof(__pyx_k_13), 0, 0, 1, 0},
+  {&__pyx_kp_s_14, __pyx_k_14, sizeof(__pyx_k_14), 0, 0, 1, 0},
+  {&__pyx_kp_s_15, __pyx_k_15, sizeof(__pyx_k_15), 0, 0, 1, 0},
+  {&__pyx_kp_s_16, __pyx_k_16, sizeof(__pyx_k_16), 0, 0, 1, 0},
+  {&__pyx_kp_s_17, __pyx_k_17, sizeof(__pyx_k_17), 0, 0, 1, 0},
+  {&__pyx_n_s_18, __pyx_k_18, sizeof(__pyx_k_18), 0, 0, 1, 1},
+  {&__pyx_n_s_19, __pyx_k_19, sizeof(__pyx_k_19), 0, 0, 1, 1},
+  {&__pyx_kp_s_2, __pyx_k_2, sizeof(__pyx_k_2), 0, 0, 1, 0},
+  {&__pyx_kp_u_20, __pyx_k_20, sizeof(__pyx_k_20), 0, 1, 0, 0},
+  {&__pyx_kp_u_21, __pyx_k_21, sizeof(__pyx_k_21), 0, 1, 0, 0},
+  {&__pyx_kp_u_22, __pyx_k_22, sizeof(__pyx_k_22), 0, 1, 0, 0},
+  {&__pyx_kp_u_23, __pyx_k_23, sizeof(__pyx_k_23), 0, 1, 0, 0},
+  {&__pyx_kp_u_24, __pyx_k_24, sizeof(__pyx_k_24), 0, 1, 0, 0},
+  {&__pyx_kp_u_25, __pyx_k_25, sizeof(__pyx_k_25), 0, 1, 0, 0},
+  {&__pyx_kp_u_26, __pyx_k_26, sizeof(__pyx_k_26), 0, 1, 0, 0},
+  {&__pyx_kp_u_27, __pyx_k_27, sizeof(__pyx_k_27), 0, 1, 0, 0},
+  {&__pyx_kp_u_28, __pyx_k_28, sizeof(__pyx_k_28), 0, 1, 0, 0},
+  {&__pyx_kp_u_29, __pyx_k_29, sizeof(__pyx_k_29), 0, 1, 0, 0},
+  {&__pyx_kp_s_3, __pyx_k_3, sizeof(__pyx_k_3), 0, 0, 1, 0},
+  {&__pyx_kp_u_30, __pyx_k_30, sizeof(__pyx_k_30), 0, 1, 0, 0},
+  {&__pyx_kp_u_31, __pyx_k_31, sizeof(__pyx_k_31), 0, 1, 0, 0},
+  {&__pyx_kp_u_32, __pyx_k_32, sizeof(__pyx_k_32), 0, 1, 0, 0},
+  {&__pyx_kp_u_33, __pyx_k_33, sizeof(__pyx_k_33), 0, 1, 0, 0},
+  {&__pyx_kp_u_34, __pyx_k_34, sizeof(__pyx_k_34), 0, 1, 0, 0},
+  {&__pyx_kp_u_35, __pyx_k_35, sizeof(__pyx_k_35), 0, 1, 0, 0},
+  {&__pyx_kp_u_36, __pyx_k_36, sizeof(__pyx_k_36), 0, 1, 0, 0},
+  {&__pyx_kp_u_37, __pyx_k_37, sizeof(__pyx_k_37), 0, 1, 0, 0},
+  {&__pyx_kp_s_4, __pyx_k_4, sizeof(__pyx_k_4), 0, 0, 1, 0},
+  {&__pyx_kp_s_5, __pyx_k_5, sizeof(__pyx_k_5), 0, 0, 1, 0},
+  {&__pyx_kp_s_6, __pyx_k_6, sizeof(__pyx_k_6), 0, 0, 1, 0},
+  {&__pyx_kp_s_7, __pyx_k_7, sizeof(__pyx_k_7), 0, 0, 1, 0},
+  {&__pyx_kp_s_8, __pyx_k_8, sizeof(__pyx_k_8), 0, 0, 1, 0},
+  {&__pyx_kp_s_9, __pyx_k_9, sizeof(__pyx_k_9), 0, 0, 1, 0},
+  {&__pyx_n_s__Abort, __pyx_k__Abort, sizeof(__pyx_k__Abort), 0, 0, 1, 1},
+  {&__pyx_n_s__B, __pyx_k__B, sizeof(__pyx_k__B), 0, 0, 1, 1},
+  {&__pyx_n_s__Channel, __pyx_k__Channel, sizeof(__pyx_k__Channel), 0, 0, 1, 1},
+  {&__pyx_n_s__Close, __pyx_k__Close, sizeof(__pyx_k__Close), 0, 0, 1, 1},
+  {&__pyx_n_s__Exception, __pyx_k__Exception, sizeof(__pyx_k__Exception), 0, 0, 1, 1},
+  {&__pyx_n_s__FALSE, __pyx_k__FALSE, sizeof(__pyx_k__FALSE), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_ACTIVE, __pyx_k__FILT_ACTIVE, sizeof(__pyx_k__FILT_ACTIVE), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_AFTERTOUCH, __pyx_k__FILT_AFTERTOUCH, sizeof(__pyx_k__FILT_AFTERTOUCH), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_CLOCK, __pyx_k__FILT_CLOCK, sizeof(__pyx_k__FILT_CLOCK), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_CONTROL, __pyx_k__FILT_CONTROL, sizeof(__pyx_k__FILT_CONTROL), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_F9, __pyx_k__FILT_F9, sizeof(__pyx_k__FILT_F9), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_FD, __pyx_k__FILT_FD, sizeof(__pyx_k__FILT_FD), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_MTC, __pyx_k__FILT_MTC, sizeof(__pyx_k__FILT_MTC), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_NOTE, __pyx_k__FILT_NOTE, sizeof(__pyx_k__FILT_NOTE), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_PITCHBEND, __pyx_k__FILT_PITCHBEND, sizeof(__pyx_k__FILT_PITCHBEND), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_PLAY, __pyx_k__FILT_PLAY, sizeof(__pyx_k__FILT_PLAY), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_PROGRAM, __pyx_k__FILT_PROGRAM, sizeof(__pyx_k__FILT_PROGRAM), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_REALTIME, __pyx_k__FILT_REALTIME, sizeof(__pyx_k__FILT_REALTIME), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_RESET, __pyx_k__FILT_RESET, sizeof(__pyx_k__FILT_RESET), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_SONG_POSITION, __pyx_k__FILT_SONG_POSITION, sizeof(__pyx_k__FILT_SONG_POSITION), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_SONG_SELECT, __pyx_k__FILT_SONG_SELECT, sizeof(__pyx_k__FILT_SONG_SELECT), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_SYSEX, __pyx_k__FILT_SYSEX, sizeof(__pyx_k__FILT_SYSEX), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_TICK, __pyx_k__FILT_TICK, sizeof(__pyx_k__FILT_TICK), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_TUNE, __pyx_k__FILT_TUNE, sizeof(__pyx_k__FILT_TUNE), 0, 0, 1, 1},
+  {&__pyx_n_s__FILT_UNDEFINED, __pyx_k__FILT_UNDEFINED, sizeof(__pyx_k__FILT_UNDEFINED), 0, 0, 1, 1},
+  {&__pyx_n_s__GetDeviceInfo, __pyx_k__GetDeviceInfo, sizeof(__pyx_k__GetDeviceInfo), 0, 0, 1, 1},
+  {&__pyx_n_s__GetErrorText, __pyx_k__GetErrorText, sizeof(__pyx_k__GetErrorText), 0, 0, 1, 1},
+  {&__pyx_n_s__IndexError, __pyx_k__IndexError, sizeof(__pyx_k__IndexError), 0, 0, 1, 1},
+  {&__pyx_n_s__Initialize, __pyx_k__Initialize, sizeof(__pyx_k__Initialize), 0, 0, 1, 1},
+  {&__pyx_n_s__Input, __pyx_k__Input, sizeof(__pyx_k__Input), 0, 0, 1, 1},
+  {&__pyx_n_s__InputDevice, __pyx_k__InputDevice, sizeof(__pyx_k__InputDevice), 0, 0, 1, 1},
+  {&__pyx_n_s__Output, __pyx_k__Output, sizeof(__pyx_k__Output), 0, 0, 1, 1},
+  {&__pyx_n_s__OutputDevice, __pyx_k__OutputDevice, sizeof(__pyx_k__OutputDevice), 0, 0, 1, 1},
+  {&__pyx_n_s__Poll, __pyx_k__Poll, sizeof(__pyx_k__Poll), 0, 0, 1, 1},
+  {&__pyx_n_s__Read, __pyx_k__Read, sizeof(__pyx_k__Read), 0, 0, 1, 1},
+  {&__pyx_n_s__SetChannelMask, __pyx_k__SetChannelMask, sizeof(__pyx_k__SetChannelMask), 0, 0, 1, 1},
+  {&__pyx_n_s__SetFilter, __pyx_k__SetFilter, sizeof(__pyx_k__SetFilter), 0, 0, 1, 1},
+  {&__pyx_n_s__TRUE, __pyx_k__TRUE, sizeof(__pyx_k__TRUE), 0, 0, 1, 1},
+  {&__pyx_n_s__Terminate, __pyx_k__Terminate, sizeof(__pyx_k__Terminate), 0, 0, 1, 1},
+  {&__pyx_n_s__Time, __pyx_k__Time, sizeof(__pyx_k__Time), 0, 0, 1, 1},
+  {&__pyx_n_s__Write, __pyx_k__Write, sizeof(__pyx_k__Write), 0, 0, 1, 1},
+  {&__pyx_n_s__WriteShort, __pyx_k__WriteShort, sizeof(__pyx_k__WriteShort), 0, 0, 1, 1},
+  {&__pyx_n_s__WriteSysEx, __pyx_k__WriteSysEx, sizeof(__pyx_k__WriteSysEx), 0, 0, 1, 1},
+  {&__pyx_n_s____main__, __pyx_k____main__, sizeof(__pyx_k____main__), 0, 0, 1, 1},
+  {&__pyx_n_s____test__, __pyx_k____test__, sizeof(__pyx_k____test__), 0, 0, 1, 1},
+  {&__pyx_n_s____version__, __pyx_k____version__, sizeof(__pyx_k____version__), 0, 0, 1, 1},
+  {&__pyx_n_s___aborted, __pyx_k___aborted, sizeof(__pyx_k___aborted), 0, 0, 1, 1},
+  {&__pyx_n_s___check_open, __pyx_k___check_open, sizeof(__pyx_k___check_open), 0, 0, 1, 1},
+  {&__pyx_n_s__array, __pyx_k__array, sizeof(__pyx_k__array), 0, 0, 1, 1},
+  {&__pyx_n_s__buffersize, __pyx_k__buffersize, sizeof(__pyx_k__buffersize), 0, 0, 1, 1},
+  {&__pyx_n_s__data1, __pyx_k__data1, sizeof(__pyx_k__data1), 0, 0, 1, 1},
+  {&__pyx_n_s__data2, __pyx_k__data2, sizeof(__pyx_k__data2), 0, 0, 1, 1},
+  {&__pyx_n_s__debug, __pyx_k__debug, sizeof(__pyx_k__debug), 0, 0, 1, 1},
+  {&__pyx_n_s__i, __pyx_k__i, sizeof(__pyx_k__i), 0, 0, 1, 1},
+  {&__pyx_n_s__input, __pyx_k__input, sizeof(__pyx_k__input), 0, 0, 1, 1},
+  {&__pyx_n_s__interf, __pyx_k__interf, sizeof(__pyx_k__interf), 0, 0, 1, 1},
+  {&__pyx_n_s__latency, __pyx_k__latency, sizeof(__pyx_k__latency), 0, 0, 1, 1},
+  {&__pyx_n_s__message, __pyx_k__message, sizeof(__pyx_k__message), 0, 0, 1, 1},
+  {&__pyx_n_s__midi, __pyx_k__midi, sizeof(__pyx_k__midi), 0, 0, 1, 1},
+  {&__pyx_n_s__msg, __pyx_k__msg, sizeof(__pyx_k__msg), 0, 0, 1, 1},
+  {&__pyx_n_s__name, __pyx_k__name, sizeof(__pyx_k__name), 0, 0, 1, 1},
+  {&__pyx_n_s__opened, __pyx_k__opened, sizeof(__pyx_k__opened), 0, 0, 1, 1},
+  {&__pyx_n_s__output, __pyx_k__output, sizeof(__pyx_k__output), 0, 0, 1, 1},
+  {&__pyx_n_s__range, __pyx_k__range, sizeof(__pyx_k__range), 0, 0, 1, 1},
+  {&__pyx_n_s__status, __pyx_k__status, sizeof(__pyx_k__status), 0, 0, 1, 1},
+  {&__pyx_n_s__timestamp, __pyx_k__timestamp, sizeof(__pyx_k__timestamp), 0, 0, 1, 1},
+  {&__pyx_n_s__tostring, __pyx_k__tostring, sizeof(__pyx_k__tostring), 0, 0, 1, 1},
+  {&__pyx_n_s__when, __pyx_k__when, sizeof(__pyx_k__when), 0, 0, 1, 1},
+  {0, 0, 0, 0, 0, 0, 0}
+};
+static int __Pyx_InitCachedBuiltins(void) {
+  __pyx_builtin_Exception = __Pyx_GetName(__pyx_b, __pyx_n_s__Exception); if (!__pyx_builtin_Exception) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 236; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_IndexError = __Pyx_GetName(__pyx_b, __pyx_n_s__IndexError); if (!__pyx_builtin_IndexError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 318; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_range = __Pyx_GetName(__pyx_b, __pyx_n_s__range); if (!__pyx_builtin_range) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  return 0;
+  __pyx_L1_error:;
+  return -1;
+}
+
+static int __Pyx_InitGlobals(void) {
+  if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_8 = PyInt_FromLong(8); if (unlikely(!__pyx_int_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_16 = PyInt_FromLong(16); if (unlikely(!__pyx_int_16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x1 = PyInt_FromLong(0x1); if (unlikely(!__pyx_int_0x1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x2 = PyInt_FromLong(0x2); if (unlikely(!__pyx_int_0x2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x4 = PyInt_FromLong(0x4); if (unlikely(!__pyx_int_0x4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x8 = PyInt_FromLong(0x8); if (unlikely(!__pyx_int_0x8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x10 = PyInt_FromLong(0x10); if (unlikely(!__pyx_int_0x10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x20 = PyInt_FromLong(0x20); if (unlikely(!__pyx_int_0x20)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x30 = PyInt_FromLong(0x30); if (unlikely(!__pyx_int_0x30)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x40 = PyInt_FromLong(0x40); if (unlikely(!__pyx_int_0x40)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x7F = PyInt_FromLong(0x7F); if (unlikely(!__pyx_int_0x7F)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x80 = PyInt_FromLong(0x80); if (unlikely(!__pyx_int_0x80)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0xFF = PyInt_FromLong(0xFF); if (unlikely(!__pyx_int_0xFF)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_1024 = PyInt_FromLong(1024); if (unlikely(!__pyx_int_1024)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_4096 = PyInt_FromLong(4096); if (unlikely(!__pyx_int_4096)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x100 = PyInt_FromLong(0x100); if (unlikely(!__pyx_int_0x100)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x200 = PyInt_FromLong(0x200); if (unlikely(!__pyx_int_0x200)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x300 = PyInt_FromLong(0x300); if (unlikely(!__pyx_int_0x300)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x400 = PyInt_FromLong(0x400); if (unlikely(!__pyx_int_0x400)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x800 = PyInt_FromLong(0x800); if (unlikely(!__pyx_int_0x800)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x1000 = PyInt_FromLong(0x1000); if (unlikely(!__pyx_int_0x1000)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x2000 = PyInt_FromLong(0x2000); if (unlikely(!__pyx_int_0x2000)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x4000 = PyInt_FromLong(0x4000); if (unlikely(!__pyx_int_0x4000)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x8000 = PyInt_FromLong(0x8000); if (unlikely(!__pyx_int_0x8000)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0xFF00 = PyInt_FromLong(0xFF00); if (unlikely(!__pyx_int_0xFF00)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0x10000 = PyInt_FromLong(0x10000); if (unlikely(!__pyx_int_0x10000)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  __pyx_int_0xFF0000 = PyInt_FromLong(0xFF0000); if (unlikely(!__pyx_int_0xFF0000)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  return 0;
+  __pyx_L1_error:;
+  return -1;
+}
+
+#if PY_MAJOR_VERSION < 3
+PyMODINIT_FUNC init_pyportmidi(void); /*proto*/
+PyMODINIT_FUNC init_pyportmidi(void)
+#else
+PyMODINIT_FUNC PyInit__pyportmidi(void); /*proto*/
+PyMODINIT_FUNC PyInit__pyportmidi(void)
+#endif
+{
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  #if CYTHON_REFNANNY
+  void* __pyx_refnanny = NULL;
+  __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny");
+  if (!__Pyx_RefNanny) {
+      PyErr_Clear();
+      __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny");
+      if (!__Pyx_RefNanny)
+          Py_FatalError("failed to import 'refnanny' module");
+  }
+  __pyx_refnanny = __Pyx_RefNanny->SetupContext("PyMODINIT_FUNC PyInit__pyportmidi(void)", __LINE__, __FILE__);
+  #endif
+  __pyx_init_filenames();
+  __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  #if PY_MAJOR_VERSION < 3
+  __pyx_empty_bytes = PyString_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  #else
+  __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  #endif
+  /*--- Library function declarations ---*/
+  /*--- Threads initialization code ---*/
+  #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS
+  #ifdef WITH_THREAD /* Python build with threading support? */
+  PyEval_InitThreads();
+  #endif
+  #endif
+  /*--- Module creation code ---*/
+  #if PY_MAJOR_VERSION < 3
+  __pyx_m = Py_InitModule4(__Pyx_NAMESTR("_pyportmidi"), __pyx_methods, 0, 0, PYTHON_API_VERSION);
+  #else
+  __pyx_m = PyModule_Create(&__pyx_moduledef);
+  #endif
+  if (!__pyx_m) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  #if PY_MAJOR_VERSION < 3
+  Py_INCREF(__pyx_m);
+  #endif
+  __pyx_b = PyImport_AddModule(__Pyx_NAMESTR(__Pyx_BUILTIN_MODULE_NAME));
+  if (!__pyx_b) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  if (__Pyx_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  /*--- Initialize various global constants etc. ---*/
+  if (unlikely(__Pyx_InitGlobals() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_module_is_main__pyportmidi) {
+    if (__Pyx_SetAttrString(__pyx_m, "__name__", __pyx_n_s____main__) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+  }
+  /*--- Builtin init code ---*/
+  if (unlikely(__Pyx_InitCachedBuiltins() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  /*--- Global init code ---*/
+  /*--- Function export code ---*/
+  /*--- Type init code ---*/
+  if (PyType_Ready(&__pyx_type_11_pyportmidi_Output) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 201; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "Output", (PyObject *)&__pyx_type_11_pyportmidi_Output) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 201; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_11_pyportmidi_Output = &__pyx_type_11_pyportmidi_Output;
+  if (PyType_Ready(&__pyx_type_11_pyportmidi_Input) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 394; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "Input", (PyObject *)&__pyx_type_11_pyportmidi_Input) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 394; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_11_pyportmidi_Input = &__pyx_type_11_pyportmidi_Input;
+  /*--- Type import code ---*/
+  /*--- Function import code ---*/
+  /*--- Execution code ---*/
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":7
+ * # harrison@media.mit.edu
+ * # written in Pyrex
+ * __version__="0.07"             # <<<<<<<<<<<<<<
+ * 
+ * import array
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s____version__, ((PyObject *)__pyx_kp_s_17)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":9
+ * __version__="0.07"
+ * 
+ * import array             # <<<<<<<<<<<<<<
+ * 
+ * # CHANGES:
+ */
+  __pyx_t_1 = __Pyx_Import(((PyObject *)__pyx_n_s__array), 0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__array, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":108
+ *     PtTimestamp Pt_Time()
+ * 
+ * FILT_ACTIVE=0x1             # <<<<<<<<<<<<<<
+ * FILT_SYSEX=0x2
+ * FILT_CLOCK=0x4
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_ACTIVE, __pyx_int_0x1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":109
+ * 
+ * FILT_ACTIVE=0x1
+ * FILT_SYSEX=0x2             # <<<<<<<<<<<<<<
+ * FILT_CLOCK=0x4
+ * FILT_PLAY=0x8
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_SYSEX, __pyx_int_0x2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 109; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":110
+ * FILT_ACTIVE=0x1
+ * FILT_SYSEX=0x2
+ * FILT_CLOCK=0x4             # <<<<<<<<<<<<<<
+ * FILT_PLAY=0x8
+ * FILT_F9=0x10
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_CLOCK, __pyx_int_0x4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":111
+ * FILT_SYSEX=0x2
+ * FILT_CLOCK=0x4
+ * FILT_PLAY=0x8             # <<<<<<<<<<<<<<
+ * FILT_F9=0x10
+ * FILT_TICK=0x10
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_PLAY, __pyx_int_0x8) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":112
+ * FILT_CLOCK=0x4
+ * FILT_PLAY=0x8
+ * FILT_F9=0x10             # <<<<<<<<<<<<<<
+ * FILT_TICK=0x10
+ * FILT_FD=0x20
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_F9, __pyx_int_0x10) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":113
+ * FILT_PLAY=0x8
+ * FILT_F9=0x10
+ * FILT_TICK=0x10             # <<<<<<<<<<<<<<
+ * FILT_FD=0x20
+ * FILT_UNDEFINED=0x30
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_TICK, __pyx_int_0x10) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":114
+ * FILT_F9=0x10
+ * FILT_TICK=0x10
+ * FILT_FD=0x20             # <<<<<<<<<<<<<<
+ * FILT_UNDEFINED=0x30
+ * FILT_RESET=0x40
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_FD, __pyx_int_0x20) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 114; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":115
+ * FILT_TICK=0x10
+ * FILT_FD=0x20
+ * FILT_UNDEFINED=0x30             # <<<<<<<<<<<<<<
+ * FILT_RESET=0x40
+ * FILT_REALTIME=0x7F
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_UNDEFINED, __pyx_int_0x30) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":116
+ * FILT_FD=0x20
+ * FILT_UNDEFINED=0x30
+ * FILT_RESET=0x40             # <<<<<<<<<<<<<<
+ * FILT_REALTIME=0x7F
+ * FILT_NOTE=0x80
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_RESET, __pyx_int_0x40) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":117
+ * FILT_UNDEFINED=0x30
+ * FILT_RESET=0x40
+ * FILT_REALTIME=0x7F             # <<<<<<<<<<<<<<
+ * FILT_NOTE=0x80
+ * FILT_CHANNEL_AFTERTOUCH=0x100
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_REALTIME, __pyx_int_0x7F) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 117; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":118
+ * FILT_RESET=0x40
+ * FILT_REALTIME=0x7F
+ * FILT_NOTE=0x80             # <<<<<<<<<<<<<<
+ * FILT_CHANNEL_AFTERTOUCH=0x100
+ * FILT_POLY_AFTERTOUCH=0x200
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_NOTE, __pyx_int_0x80) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":119
+ * FILT_REALTIME=0x7F
+ * FILT_NOTE=0x80
+ * FILT_CHANNEL_AFTERTOUCH=0x100             # <<<<<<<<<<<<<<
+ * FILT_POLY_AFTERTOUCH=0x200
+ * FILT_AFTERTOUCH=0x300
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s_18, __pyx_int_0x100) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":120
+ * FILT_NOTE=0x80
+ * FILT_CHANNEL_AFTERTOUCH=0x100
+ * FILT_POLY_AFTERTOUCH=0x200             # <<<<<<<<<<<<<<
+ * FILT_AFTERTOUCH=0x300
+ * FILT_PROGRAM=0x400
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s_19, __pyx_int_0x200) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":121
+ * FILT_CHANNEL_AFTERTOUCH=0x100
+ * FILT_POLY_AFTERTOUCH=0x200
+ * FILT_AFTERTOUCH=0x300             # <<<<<<<<<<<<<<
+ * FILT_PROGRAM=0x400
+ * FILT_CONTROL=0x800
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_AFTERTOUCH, __pyx_int_0x300) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":122
+ * FILT_POLY_AFTERTOUCH=0x200
+ * FILT_AFTERTOUCH=0x300
+ * FILT_PROGRAM=0x400             # <<<<<<<<<<<<<<
+ * FILT_CONTROL=0x800
+ * FILT_PITCHBEND=0x1000
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_PROGRAM, __pyx_int_0x400) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":123
+ * FILT_AFTERTOUCH=0x300
+ * FILT_PROGRAM=0x400
+ * FILT_CONTROL=0x800             # <<<<<<<<<<<<<<
+ * FILT_PITCHBEND=0x1000
+ * FILT_MTC=0x2000
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_CONTROL, __pyx_int_0x800) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":124
+ * FILT_PROGRAM=0x400
+ * FILT_CONTROL=0x800
+ * FILT_PITCHBEND=0x1000             # <<<<<<<<<<<<<<
+ * FILT_MTC=0x2000
+ * FILT_SONG_POSITION=0x4000
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_PITCHBEND, __pyx_int_0x1000) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":125
+ * FILT_CONTROL=0x800
+ * FILT_PITCHBEND=0x1000
+ * FILT_MTC=0x2000             # <<<<<<<<<<<<<<
+ * FILT_SONG_POSITION=0x4000
+ * FILT_SONG_SELECT=0x8000
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_MTC, __pyx_int_0x2000) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":126
+ * FILT_PITCHBEND=0x1000
+ * FILT_MTC=0x2000
+ * FILT_SONG_POSITION=0x4000             # <<<<<<<<<<<<<<
+ * FILT_SONG_SELECT=0x8000
+ * FILT_TUNE=0x10000
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_SONG_POSITION, __pyx_int_0x4000) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":127
+ * FILT_MTC=0x2000
+ * FILT_SONG_POSITION=0x4000
+ * FILT_SONG_SELECT=0x8000             # <<<<<<<<<<<<<<
+ * FILT_TUNE=0x10000
+ * FALSE=0
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_SONG_SELECT, __pyx_int_0x8000) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 127; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":128
+ * FILT_SONG_POSITION=0x4000
+ * FILT_SONG_SELECT=0x8000
+ * FILT_TUNE=0x10000             # <<<<<<<<<<<<<<
+ * FALSE=0
+ * TRUE=1
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FILT_TUNE, __pyx_int_0x10000) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":129
+ * FILT_SONG_SELECT=0x8000
+ * FILT_TUNE=0x10000
+ * FALSE=0             # <<<<<<<<<<<<<<
+ * TRUE=1
+ * 
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__FALSE, __pyx_int_0) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":130
+ * FILT_TUNE=0x10000
+ * FALSE=0
+ * TRUE=1             # <<<<<<<<<<<<<<
+ * 
+ * def Initialize():
+ */
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__TRUE, __pyx_int_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/rene/dev/portmedia/portmedia/portmidi/trunk/pm_python/pyportmidi/_pyportmidi.pyx":1
+ * # pyPortMidi             # <<<<<<<<<<<<<<
+ * # Python bindings for PortMidi
+ * # John Harrison
+ */
+  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Initialize); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = __Pyx_GetAttrString(__pyx_t_2, "__doc__");
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_20), __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_3 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Terminate); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_21), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__GetDeviceInfo); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = __Pyx_GetAttrString(__pyx_t_2, "__doc__");
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_22), __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_3 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Time); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_23), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__GetErrorText); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = __Pyx_GetAttrString(__pyx_t_2, "__doc__");
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_24), __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_3 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Channel); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_25), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Output); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s___check_open); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_26), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Output); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Close); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_27), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Output); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Abort); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_28), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Output); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Write); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_29), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Output); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__WriteShort); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_30), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Output); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__WriteSysEx); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_31), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Input); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s___check_open); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_32), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Input); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Close); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_33), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Input); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__SetFilter); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_34), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Input); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__SetChannelMask); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_35), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Input); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Poll); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_36), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_GetAttr(__pyx_m, __pyx_n_s__Input); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__Read); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = __Pyx_GetAttrString(__pyx_t_3, "__doc__");
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_kp_u_37), __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s____test__, ((PyObject *)__pyx_t_1)) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  if (__pyx_m) {
+    __Pyx_AddTraceback("init _pyportmidi");
+    Py_DECREF(__pyx_m); __pyx_m = 0;
+  } else if (!PyErr_Occurred()) {
+    PyErr_SetString(PyExc_ImportError, "init _pyportmidi");
+  }
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  #if PY_MAJOR_VERSION < 3
+  return;
+  #else
+  return __pyx_m;
+  #endif
+}
+
+static const char *__pyx_filenames[] = {
+  "_pyportmidi.pyx",
+};
+
+/* Runtime support code */
+
+static void __pyx_init_filenames(void) {
+  __pyx_f = __pyx_filenames;
+}
+
+static void __Pyx_RaiseDoubleKeywordsError(
+    const char* func_name,
+    PyObject* kw_name)
+{
+    PyErr_Format(PyExc_TypeError,
+        #if PY_MAJOR_VERSION >= 3
+        "%s() got multiple values for keyword argument '%U'", func_name, kw_name);
+        #else
+        "%s() got multiple values for keyword argument '%s'", func_name,
+        PyString_AS_STRING(kw_name));
+        #endif
+}
+
+static void __Pyx_RaiseArgtupleInvalid(
+    const char* func_name,
+    int exact,
+    Py_ssize_t num_min,
+    Py_ssize_t num_max,
+    Py_ssize_t num_found)
+{
+    Py_ssize_t num_expected;
+    const char *number, *more_or_less;
+
+    if (num_found < num_min) {
+        num_expected = num_min;
+        more_or_less = "at least";
+    } else {
+        num_expected = num_max;
+        more_or_less = "at most";
+    }
+    if (exact) {
+        more_or_less = "exactly";
+    }
+    number = (num_expected == 1) ? "" : "s";
+    PyErr_Format(PyExc_TypeError,
+        #if PY_VERSION_HEX < 0x02050000
+            "%s() takes %s %d positional argument%s (%d given)",
+        #else
+            "%s() takes %s %zd positional argument%s (%zd given)",
+        #endif
+        func_name, more_or_less, num_expected, number, num_found);
+}
+
+static int __Pyx_ParseOptionalKeywords(
+    PyObject *kwds,
+    PyObject **argnames[],
+    PyObject *kwds2,
+    PyObject *values[],
+    Py_ssize_t num_pos_args,
+    const char* function_name)
+{
+    PyObject *key = 0, *value = 0;
+    Py_ssize_t pos = 0;
+    PyObject*** name;
+    PyObject*** first_kw_arg = argnames + num_pos_args;
+
+    while (PyDict_Next(kwds, &pos, &key, &value)) {
+        name = first_kw_arg;
+        while (*name && (**name != key)) name++;
+        if (*name) {
+            values[name-argnames] = value;
+        } else {
+            #if PY_MAJOR_VERSION < 3
+            if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key))) {
+            #else
+            if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key))) {
+            #endif
+                goto invalid_keyword_type;
+            } else {
+                for (name = first_kw_arg; *name; name++) {
+                    #if PY_MAJOR_VERSION >= 3
+                    if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) &&
+                        PyUnicode_Compare(**name, key) == 0) break;
+                    #else
+                    if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) &&
+                        _PyString_Eq(**name, key)) break;
+                    #endif
+                }
+                if (*name) {
+                    values[name-argnames] = value;
+                } else {
+                    /* unexpected keyword found */
+                    for (name=argnames; name != first_kw_arg; name++) {
+                        if (**name == key) goto arg_passed_twice;
+                        #if PY_MAJOR_VERSION >= 3
+                        if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) &&
+                            PyUnicode_Compare(**name, key) == 0) goto arg_passed_twice;
+                        #else
+                        if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) &&
+                            _PyString_Eq(**name, key)) goto arg_passed_twice;
+                        #endif
+                    }
+                    if (kwds2) {
+                        if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad;
+                    } else {
+                        goto invalid_keyword;
+                    }
+                }
+            }
+        }
+    }
+    return 0;
+arg_passed_twice:
+    __Pyx_RaiseDoubleKeywordsError(function_name, **name);
+    goto bad;
+invalid_keyword_type:
+    PyErr_Format(PyExc_TypeError,
+        "%s() keywords must be strings", function_name);
+    goto bad;
+invalid_keyword:
+    PyErr_Format(PyExc_TypeError,
+    #if PY_MAJOR_VERSION < 3
+        "%s() got an unexpected keyword argument '%s'",
+        function_name, PyString_AsString(key));
+    #else
+        "%s() got an unexpected keyword argument '%U'",
+        function_name, key);
+    #endif
+bad:
+    return -1;
+}
+
+
+static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) {
+    PyObject *__import__ = 0;
+    PyObject *empty_list = 0;
+    PyObject *module = 0;
+    PyObject *global_dict = 0;
+    PyObject *empty_dict = 0;
+    PyObject *list;
+    __import__ = __Pyx_GetAttrString(__pyx_b, "__import__");
+    if (!__import__)
+        goto bad;
+    if (from_list)
+        list = from_list;
+    else {
+        empty_list = PyList_New(0);
+        if (!empty_list)
+            goto bad;
+        list = empty_list;
+    }
+    global_dict = PyModule_GetDict(__pyx_m);
+    if (!global_dict)
+        goto bad;
+    empty_dict = PyDict_New();
+    if (!empty_dict)
+        goto bad;
+    module = PyObject_CallFunctionObjArgs(__import__,
+        name, global_dict, empty_dict, list, NULL);
+bad:
+    Py_XDECREF(empty_list);
+    Py_XDECREF(__import__);
+    Py_XDECREF(empty_dict);
+    return module;
+}
+
+static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PmDeviceID(PmDeviceID val) {
+    const PmDeviceID neg_one = (PmDeviceID)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(PmDeviceID) <  sizeof(long)) {
+        return PyInt_FromLong((long)val);
+    } else if (sizeof(PmDeviceID) == sizeof(long)) {
+        if (is_unsigned)
+            return PyLong_FromUnsignedLong((unsigned long)val);
+        else
+            return PyInt_FromLong((long)val);
+    } else { /* (sizeof(PmDeviceID) > sizeof(long)) */
+        if (is_unsigned)
+            return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val);
+        else
+            return PyLong_FromLongLong((PY_LONG_LONG)val);
+    }
+}
+
+static CYTHON_INLINE PmDeviceID __Pyx_PyInt_from_py_PmDeviceID(PyObject* x) {
+    const PmDeviceID neg_one = (PmDeviceID)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(PmDeviceID) == sizeof(char)) {
+        if (is_unsigned)
+            return (PmDeviceID)__Pyx_PyInt_AsUnsignedChar(x);
+        else
+            return (PmDeviceID)__Pyx_PyInt_AsSignedChar(x);
+    } else if (sizeof(PmDeviceID) == sizeof(short)) {
+        if (is_unsigned)
+            return (PmDeviceID)__Pyx_PyInt_AsUnsignedShort(x);
+        else
+            return (PmDeviceID)__Pyx_PyInt_AsSignedShort(x);
+    } else if (sizeof(PmDeviceID) == sizeof(int)) {
+        if (is_unsigned)
+            return (PmDeviceID)__Pyx_PyInt_AsUnsignedInt(x);
+        else
+            return (PmDeviceID)__Pyx_PyInt_AsSignedInt(x);
+    } else if (sizeof(PmDeviceID) == sizeof(long)) {
+        if (is_unsigned)
+            return (PmDeviceID)__Pyx_PyInt_AsUnsignedLong(x);
+        else
+            return (PmDeviceID)__Pyx_PyInt_AsSignedLong(x);
+    } else if (sizeof(PmDeviceID) == sizeof(PY_LONG_LONG)) {
+        if (is_unsigned)
+            return (PmDeviceID)__Pyx_PyInt_AsUnsignedLongLong(x);
+        else
+            return (PmDeviceID)__Pyx_PyInt_AsSignedLongLong(x);
+#if 0
+    } else if (sizeof(PmDeviceID) > sizeof(short) &&
+               sizeof(PmDeviceID) < sizeof(int)) { /*  __int32 ILP64 ? */
+        if (is_unsigned)
+            return (PmDeviceID)__Pyx_PyInt_AsUnsignedInt(x);
+        else
+            return (PmDeviceID)__Pyx_PyInt_AsSignedInt(x);
+#endif
+    }
+    PyErr_SetString(PyExc_TypeError, "PmDeviceID");
+    return (PmDeviceID)-1;
+}
+
+static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PtTimestamp(PtTimestamp val) {
+    const PtTimestamp neg_one = (PtTimestamp)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(PtTimestamp) <  sizeof(long)) {
+        return PyInt_FromLong((long)val);
+    } else if (sizeof(PtTimestamp) == sizeof(long)) {
+        if (is_unsigned)
+            return PyLong_FromUnsignedLong((unsigned long)val);
+        else
+            return PyInt_FromLong((long)val);
+    } else { /* (sizeof(PtTimestamp) > sizeof(long)) */
+        if (is_unsigned)
+            return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val);
+        else
+            return PyLong_FromLongLong((PY_LONG_LONG)val);
+    }
+}
+
+#if PY_MAJOR_VERSION < 3
+static PyObject *__Pyx_GetStdout(void) {
+    PyObject *f = PySys_GetObject((char *)"stdout");
+    if (!f) {
+        PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout");
+    }
+    return f;
+}
+
+static int __Pyx_Print(PyObject *arg_tuple, int newline) {
+    PyObject *f;
+    PyObject* v;
+    int i;
+
+    if (!(f = __Pyx_GetStdout()))
+        return -1;
+    for (i=0; i < PyTuple_GET_SIZE(arg_tuple); i++) {
+        if (PyFile_SoftSpace(f, 1)) {
+            if (PyFile_WriteString(" ", f) < 0)
+                return -1;
+        }
+        v = PyTuple_GET_ITEM(arg_tuple, i);
+        if (PyFile_WriteObject(v, f, Py_PRINT_RAW) < 0)
+            return -1;
+        if (PyString_Check(v)) {
+            char *s = PyString_AsString(v);
+            Py_ssize_t len = PyString_Size(v);
+            if (len > 0 &&
+                isspace(Py_CHARMASK(s[len-1])) &&
+                s[len-1] != ' ')
+                    PyFile_SoftSpace(f, 0);
+        }
+    }
+    if (newline) {
+        if (PyFile_WriteString("\n", f) < 0)
+            return -1;
+        PyFile_SoftSpace(f, 0);
+    }
+    return 0;
+}
+
+#else /* Python 3 has a print function */
+
+static int __Pyx_Print(PyObject *arg_tuple, int newline) {
+    PyObject* kwargs = 0;
+    PyObject* result = 0;
+    PyObject* end_string;
+    if (!__pyx_print) {
+        __pyx_print = __Pyx_GetAttrString(__pyx_b, "print");
+        if (!__pyx_print)
+            return -1;
+    }
+    if (!newline) {
+        if (!__pyx_print_kwargs) {
+            __pyx_print_kwargs = PyDict_New();
+            if (!__pyx_print_kwargs)
+                return -1;
+            end_string = PyUnicode_FromStringAndSize(" ", 1);
+            if (!end_string)
+                return -1;
+            if (PyDict_SetItemString(__pyx_print_kwargs, "end", end_string) < 0) {
+                Py_DECREF(end_string);
+                return -1;
+            }
+            Py_DECREF(end_string);
+        }
+        kwargs = __pyx_print_kwargs;
+    }
+    result = PyObject_Call(__pyx_print, arg_tuple, kwargs);
+    if (!result)
+        return -1;
+    Py_DECREF(result);
+    return 0;
+}
+
+#endif
+
+#if PY_MAJOR_VERSION < 3
+
+static int __Pyx_PrintOne(PyObject *o) {
+    PyObject *f;
+    if (!(f = __Pyx_GetStdout()))
+        return -1;
+    if (PyFile_SoftSpace(f, 0)) {
+        if (PyFile_WriteString(" ", f) < 0)
+            return -1;
+    }
+    if (PyFile_WriteObject(o, f, Py_PRINT_RAW) < 0)
+        return -1;
+    if (PyFile_WriteString("\n", f) < 0)
+        return -1;
+    return 0;
+    /* the line below is just to avoid compiler
+     * compiler warnings about unused functions */
+    return __Pyx_Print(NULL, 0);
+}
+
+#else /* Python 3 has a print function */
+
+static int __Pyx_PrintOne(PyObject *o) {
+    int res;
+    PyObject* arg_tuple = PyTuple_New(1);
+    if (unlikely(!arg_tuple))
+        return -1;
+    Py_INCREF(o);
+    PyTuple_SET_ITEM(arg_tuple, 0, o);
+    res = __Pyx_Print(arg_tuple, 1);
+    Py_DECREF(arg_tuple);
+    return res;
+}
+
+#endif
+
+static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) {
+    PyObject *result;
+    result = PyObject_GetAttr(dict, name);
+    if (!result)
+        PyErr_SetObject(PyExc_NameError, name);
+    return result;
+}
+
+static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) {
+    PyObject *tmp_type, *tmp_value, *tmp_tb;
+    PyThreadState *tstate = PyThreadState_GET();
+
+    tmp_type = tstate->curexc_type;
+    tmp_value = tstate->curexc_value;
+    tmp_tb = tstate->curexc_traceback;
+    tstate->curexc_type = type;
+    tstate->curexc_value = value;
+    tstate->curexc_traceback = tb;
+    Py_XDECREF(tmp_type);
+    Py_XDECREF(tmp_value);
+    Py_XDECREF(tmp_tb);
+}
+
+static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) {
+    PyThreadState *tstate = PyThreadState_GET();
+    *type = tstate->curexc_type;
+    *value = tstate->curexc_value;
+    *tb = tstate->curexc_traceback;
+
+    tstate->curexc_type = 0;
+    tstate->curexc_value = 0;
+    tstate->curexc_traceback = 0;
+}
+
+
+#if PY_MAJOR_VERSION < 3
+static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
+    Py_XINCREF(type);
+    Py_XINCREF(value);
+    Py_XINCREF(tb);
+    /* First, check the traceback argument, replacing None with NULL. */
+    if (tb == Py_None) {
+        Py_DECREF(tb);
+        tb = 0;
+    }
+    else if (tb != NULL && !PyTraceBack_Check(tb)) {
+        PyErr_SetString(PyExc_TypeError,
+            "raise: arg 3 must be a traceback or None");
+        goto raise_error;
+    }
+    /* Next, replace a missing value with None */
+    if (value == NULL) {
+        value = Py_None;
+        Py_INCREF(value);
+    }
+    #if PY_VERSION_HEX < 0x02050000
+    if (!PyClass_Check(type))
+    #else
+    if (!PyType_Check(type))
+    #endif
+    {
+        /* Raising an instance.  The value should be a dummy. */
+        if (value != Py_None) {
+            PyErr_SetString(PyExc_TypeError,
+                "instance exception may not have a separate value");
+            goto raise_error;
+        }
+        /* Normalize to raise <class>, <instance> */
+        Py_DECREF(value);
+        value = type;
+        #if PY_VERSION_HEX < 0x02050000
+            if (PyInstance_Check(type)) {
+                type = (PyObject*) ((PyInstanceObject*)type)->in_class;
+                Py_INCREF(type);
+            }
+            else {
+                type = 0;
+                PyErr_SetString(PyExc_TypeError,
+                    "raise: exception must be an old-style class or instance");
+                goto raise_error;
+            }
+        #else
+            type = (PyObject*) Py_TYPE(type);
+            Py_INCREF(type);
+            if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) {
+                PyErr_SetString(PyExc_TypeError,
+                    "raise: exception class must be a subclass of BaseException");
+                goto raise_error;
+            }
+        #endif
+    }
+
+    __Pyx_ErrRestore(type, value, tb);
+    return;
+raise_error:
+    Py_XDECREF(value);
+    Py_XDECREF(type);
+    Py_XDECREF(tb);
+    return;
+}
+
+#else /* Python 3+ */
+
+static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
+    if (tb == Py_None) {
+        tb = 0;
+    } else if (tb && !PyTraceBack_Check(tb)) {
+        PyErr_SetString(PyExc_TypeError,
+            "raise: arg 3 must be a traceback or None");
+        goto bad;
+    }
+    if (value == Py_None)
+        value = 0;
+
+    if (PyExceptionInstance_Check(type)) {
+        if (value) {
+            PyErr_SetString(PyExc_TypeError,
+                "instance exception may not have a separate value");
+            goto bad;
+        }
+        value = type;
+        type = (PyObject*) Py_TYPE(value);
+    } else if (!PyExceptionClass_Check(type)) {
+        PyErr_SetString(PyExc_TypeError,
+            "raise: exception class must be a subclass of BaseException");
+        goto bad;
+    }
+
+    PyErr_SetObject(type, value);
+
+    if (tb) {
+        PyThreadState *tstate = PyThreadState_GET();
+        PyObject* tmp_tb = tstate->curexc_traceback;
+        if (tb != tmp_tb) {
+            Py_INCREF(tb);
+            tstate->curexc_traceback = tb;
+            Py_XDECREF(tmp_tb);
+        }
+    }
+
+bad:
+    return;
+}
+#endif
+
+static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PmMessage(PmMessage val) {
+    const PmMessage neg_one = (PmMessage)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(PmMessage) <  sizeof(long)) {
+        return PyInt_FromLong((long)val);
+    } else if (sizeof(PmMessage) == sizeof(long)) {
+        if (is_unsigned)
+            return PyLong_FromUnsignedLong((unsigned long)val);
+        else
+            return PyInt_FromLong((long)val);
+    } else { /* (sizeof(PmMessage) > sizeof(long)) */
+        if (is_unsigned)
+            return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val);
+        else
+            return PyLong_FromLongLong((PY_LONG_LONG)val);
+    }
+}
+
+static CYTHON_INLINE PmMessage __Pyx_PyInt_from_py_PmMessage(PyObject* x) {
+    const PmMessage neg_one = (PmMessage)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(PmMessage) == sizeof(char)) {
+        if (is_unsigned)
+            return (PmMessage)__Pyx_PyInt_AsUnsignedChar(x);
+        else
+            return (PmMessage)__Pyx_PyInt_AsSignedChar(x);
+    } else if (sizeof(PmMessage) == sizeof(short)) {
+        if (is_unsigned)
+            return (PmMessage)__Pyx_PyInt_AsUnsignedShort(x);
+        else
+            return (PmMessage)__Pyx_PyInt_AsSignedShort(x);
+    } else if (sizeof(PmMessage) == sizeof(int)) {
+        if (is_unsigned)
+            return (PmMessage)__Pyx_PyInt_AsUnsignedInt(x);
+        else
+            return (PmMessage)__Pyx_PyInt_AsSignedInt(x);
+    } else if (sizeof(PmMessage) == sizeof(long)) {
+        if (is_unsigned)
+            return (PmMessage)__Pyx_PyInt_AsUnsignedLong(x);
+        else
+            return (PmMessage)__Pyx_PyInt_AsSignedLong(x);
+    } else if (sizeof(PmMessage) == sizeof(PY_LONG_LONG)) {
+        if (is_unsigned)
+            return (PmMessage)__Pyx_PyInt_AsUnsignedLongLong(x);
+        else
+            return (PmMessage)__Pyx_PyInt_AsSignedLongLong(x);
+#if 0
+    } else if (sizeof(PmMessage) > sizeof(short) &&
+               sizeof(PmMessage) < sizeof(int)) { /*  __int32 ILP64 ? */
+        if (is_unsigned)
+            return (PmMessage)__Pyx_PyInt_AsUnsignedInt(x);
+        else
+            return (PmMessage)__Pyx_PyInt_AsSignedInt(x);
+#endif
+    }
+    PyErr_SetString(PyExc_TypeError, "PmMessage");
+    return (PmMessage)-1;
+}
+
+static CYTHON_INLINE PmTimestamp __Pyx_PyInt_from_py_PmTimestamp(PyObject* x) {
+    const PmTimestamp neg_one = (PmTimestamp)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(PmTimestamp) == sizeof(char)) {
+        if (is_unsigned)
+            return (PmTimestamp)__Pyx_PyInt_AsUnsignedChar(x);
+        else
+            return (PmTimestamp)__Pyx_PyInt_AsSignedChar(x);
+    } else if (sizeof(PmTimestamp) == sizeof(short)) {
+        if (is_unsigned)
+            return (PmTimestamp)__Pyx_PyInt_AsUnsignedShort(x);
+        else
+            return (PmTimestamp)__Pyx_PyInt_AsSignedShort(x);
+    } else if (sizeof(PmTimestamp) == sizeof(int)) {
+        if (is_unsigned)
+            return (PmTimestamp)__Pyx_PyInt_AsUnsignedInt(x);
+        else
+            return (PmTimestamp)__Pyx_PyInt_AsSignedInt(x);
+    } else if (sizeof(PmTimestamp) == sizeof(long)) {
+        if (is_unsigned)
+            return (PmTimestamp)__Pyx_PyInt_AsUnsignedLong(x);
+        else
+            return (PmTimestamp)__Pyx_PyInt_AsSignedLong(x);
+    } else if (sizeof(PmTimestamp) == sizeof(PY_LONG_LONG)) {
+        if (is_unsigned)
+            return (PmTimestamp)__Pyx_PyInt_AsUnsignedLongLong(x);
+        else
+            return (PmTimestamp)__Pyx_PyInt_AsSignedLongLong(x);
+#if 0
+    } else if (sizeof(PmTimestamp) > sizeof(short) &&
+               sizeof(PmTimestamp) < sizeof(int)) { /*  __int32 ILP64 ? */
+        if (is_unsigned)
+            return (PmTimestamp)__Pyx_PyInt_AsUnsignedInt(x);
+        else
+            return (PmTimestamp)__Pyx_PyInt_AsSignedInt(x);
+#endif
+    }
+    PyErr_SetString(PyExc_TypeError, "PmTimestamp");
+    return (PmTimestamp)-1;
+}
+
+static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_PmTimestamp(PmTimestamp val) {
+    const PmTimestamp neg_one = (PmTimestamp)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(PmTimestamp) <  sizeof(long)) {
+        return PyInt_FromLong((long)val);
+    } else if (sizeof(PmTimestamp) == sizeof(long)) {
+        if (is_unsigned)
+            return PyLong_FromUnsignedLong((unsigned long)val);
+        else
+            return PyInt_FromLong((long)val);
+    } else { /* (sizeof(PmTimestamp) > sizeof(long)) */
+        if (is_unsigned)
+            return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val);
+        else
+            return PyLong_FromLongLong((PY_LONG_LONG)val);
+    }
+}
+
+static CYTHON_INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject* x) {
+    const unsigned char neg_one = (unsigned char)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(unsigned char) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(unsigned char)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to unsigned char" :
+                    "value too large to convert to unsigned char");
+            }
+            return (unsigned char)-1;
+        }
+        return (unsigned char)val;
+    }
+    return (unsigned char)__Pyx_PyInt_AsUnsignedLong(x);
+}
+
+static CYTHON_INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject* x) {
+    const unsigned short neg_one = (unsigned short)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(unsigned short) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(unsigned short)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to unsigned short" :
+                    "value too large to convert to unsigned short");
+            }
+            return (unsigned short)-1;
+        }
+        return (unsigned short)val;
+    }
+    return (unsigned short)__Pyx_PyInt_AsUnsignedLong(x);
+}
+
+static CYTHON_INLINE unsigned int __Pyx_PyInt_AsUnsignedInt(PyObject* x) {
+    const unsigned int neg_one = (unsigned int)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(unsigned int) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(unsigned int)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to unsigned int" :
+                    "value too large to convert to unsigned int");
+            }
+            return (unsigned int)-1;
+        }
+        return (unsigned int)val;
+    }
+    return (unsigned int)__Pyx_PyInt_AsUnsignedLong(x);
+}
+
+static CYTHON_INLINE char __Pyx_PyInt_AsChar(PyObject* x) {
+    const char neg_one = (char)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(char) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(char)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to char" :
+                    "value too large to convert to char");
+            }
+            return (char)-1;
+        }
+        return (char)val;
+    }
+    return (char)__Pyx_PyInt_AsLong(x);
+}
+
+static CYTHON_INLINE short __Pyx_PyInt_AsShort(PyObject* x) {
+    const short neg_one = (short)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(short) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(short)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to short" :
+                    "value too large to convert to short");
+            }
+            return (short)-1;
+        }
+        return (short)val;
+    }
+    return (short)__Pyx_PyInt_AsLong(x);
+}
+
+static CYTHON_INLINE int __Pyx_PyInt_AsInt(PyObject* x) {
+    const int neg_one = (int)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(int) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(int)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to int" :
+                    "value too large to convert to int");
+            }
+            return (int)-1;
+        }
+        return (int)val;
+    }
+    return (int)__Pyx_PyInt_AsLong(x);
+}
+
+static CYTHON_INLINE signed char __Pyx_PyInt_AsSignedChar(PyObject* x) {
+    const signed char neg_one = (signed char)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(signed char) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(signed char)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to signed char" :
+                    "value too large to convert to signed char");
+            }
+            return (signed char)-1;
+        }
+        return (signed char)val;
+    }
+    return (signed char)__Pyx_PyInt_AsSignedLong(x);
+}
+
+static CYTHON_INLINE signed short __Pyx_PyInt_AsSignedShort(PyObject* x) {
+    const signed short neg_one = (signed short)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(signed short) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(signed short)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to signed short" :
+                    "value too large to convert to signed short");
+            }
+            return (signed short)-1;
+        }
+        return (signed short)val;
+    }
+    return (signed short)__Pyx_PyInt_AsSignedLong(x);
+}
+
+static CYTHON_INLINE signed int __Pyx_PyInt_AsSignedInt(PyObject* x) {
+    const signed int neg_one = (signed int)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+    if (sizeof(signed int) < sizeof(long)) {
+        long val = __Pyx_PyInt_AsLong(x);
+        if (unlikely(val != (long)(signed int)val)) {
+            if (!unlikely(val == -1 && PyErr_Occurred())) {
+                PyErr_SetString(PyExc_OverflowError,
+                    (is_unsigned && unlikely(val < 0)) ?
+                    "can't convert negative value to signed int" :
+                    "value too large to convert to signed int");
+            }
+            return (signed int)-1;
+        }
+        return (signed int)val;
+    }
+    return (signed int)__Pyx_PyInt_AsSignedLong(x);
+}
+
+static CYTHON_INLINE unsigned long __Pyx_PyInt_AsUnsignedLong(PyObject* x) {
+    const unsigned long neg_one = (unsigned long)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+#if PY_VERSION_HEX < 0x03000000
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (is_unsigned && unlikely(val < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to unsigned long");
+            return (unsigned long)-1;
+        }
+        return (unsigned long)val;
+    } else
+#endif
+    if (likely(PyLong_Check(x))) {
+        if (is_unsigned) {
+            if (unlikely(Py_SIZE(x) < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to unsigned long");
+                return (unsigned long)-1;
+            }
+            return PyLong_AsUnsignedLong(x);
+        } else {
+            return PyLong_AsLong(x);
+        }
+    } else {
+        unsigned long val;
+        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        if (!tmp) return (unsigned long)-1;
+        val = __Pyx_PyInt_AsUnsignedLong(tmp);
+        Py_DECREF(tmp);
+        return val;
+    }
+}
+
+static CYTHON_INLINE unsigned PY_LONG_LONG __Pyx_PyInt_AsUnsignedLongLong(PyObject* x) {
+    const unsigned PY_LONG_LONG neg_one = (unsigned PY_LONG_LONG)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+#if PY_VERSION_HEX < 0x03000000
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (is_unsigned && unlikely(val < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to unsigned PY_LONG_LONG");
+            return (unsigned PY_LONG_LONG)-1;
+        }
+        return (unsigned PY_LONG_LONG)val;
+    } else
+#endif
+    if (likely(PyLong_Check(x))) {
+        if (is_unsigned) {
+            if (unlikely(Py_SIZE(x) < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to unsigned PY_LONG_LONG");
+                return (unsigned PY_LONG_LONG)-1;
+            }
+            return PyLong_AsUnsignedLongLong(x);
+        } else {
+            return PyLong_AsLongLong(x);
+        }
+    } else {
+        unsigned PY_LONG_LONG val;
+        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        if (!tmp) return (unsigned PY_LONG_LONG)-1;
+        val = __Pyx_PyInt_AsUnsignedLongLong(tmp);
+        Py_DECREF(tmp);
+        return val;
+    }
+}
+
+static CYTHON_INLINE long __Pyx_PyInt_AsLong(PyObject* x) {
+    const long neg_one = (long)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+#if PY_VERSION_HEX < 0x03000000
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (is_unsigned && unlikely(val < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to long");
+            return (long)-1;
+        }
+        return (long)val;
+    } else
+#endif
+    if (likely(PyLong_Check(x))) {
+        if (is_unsigned) {
+            if (unlikely(Py_SIZE(x) < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to long");
+                return (long)-1;
+            }
+            return PyLong_AsUnsignedLong(x);
+        } else {
+            return PyLong_AsLong(x);
+        }
+    } else {
+        long val;
+        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        if (!tmp) return (long)-1;
+        val = __Pyx_PyInt_AsLong(tmp);
+        Py_DECREF(tmp);
+        return val;
+    }
+}
+
+static CYTHON_INLINE PY_LONG_LONG __Pyx_PyInt_AsLongLong(PyObject* x) {
+    const PY_LONG_LONG neg_one = (PY_LONG_LONG)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+#if PY_VERSION_HEX < 0x03000000
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (is_unsigned && unlikely(val < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to PY_LONG_LONG");
+            return (PY_LONG_LONG)-1;
+        }
+        return (PY_LONG_LONG)val;
+    } else
+#endif
+    if (likely(PyLong_Check(x))) {
+        if (is_unsigned) {
+            if (unlikely(Py_SIZE(x) < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to PY_LONG_LONG");
+                return (PY_LONG_LONG)-1;
+            }
+            return PyLong_AsUnsignedLongLong(x);
+        } else {
+            return PyLong_AsLongLong(x);
+        }
+    } else {
+        PY_LONG_LONG val;
+        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        if (!tmp) return (PY_LONG_LONG)-1;
+        val = __Pyx_PyInt_AsLongLong(tmp);
+        Py_DECREF(tmp);
+        return val;
+    }
+}
+
+static CYTHON_INLINE signed long __Pyx_PyInt_AsSignedLong(PyObject* x) {
+    const signed long neg_one = (signed long)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+#if PY_VERSION_HEX < 0x03000000
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (is_unsigned && unlikely(val < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to signed long");
+            return (signed long)-1;
+        }
+        return (signed long)val;
+    } else
+#endif
+    if (likely(PyLong_Check(x))) {
+        if (is_unsigned) {
+            if (unlikely(Py_SIZE(x) < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to signed long");
+                return (signed long)-1;
+            }
+            return PyLong_AsUnsignedLong(x);
+        } else {
+            return PyLong_AsLong(x);
+        }
+    } else {
+        signed long val;
+        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        if (!tmp) return (signed long)-1;
+        val = __Pyx_PyInt_AsSignedLong(tmp);
+        Py_DECREF(tmp);
+        return val;
+    }
+}
+
+static CYTHON_INLINE signed PY_LONG_LONG __Pyx_PyInt_AsSignedLongLong(PyObject* x) {
+    const signed PY_LONG_LONG neg_one = (signed PY_LONG_LONG)-1, const_zero = 0;
+    const int is_unsigned = neg_one > const_zero;
+#if PY_VERSION_HEX < 0x03000000
+    if (likely(PyInt_Check(x))) {
+        long val = PyInt_AS_LONG(x);
+        if (is_unsigned && unlikely(val < 0)) {
+            PyErr_SetString(PyExc_OverflowError,
+                            "can't convert negative value to signed PY_LONG_LONG");
+            return (signed PY_LONG_LONG)-1;
+        }
+        return (signed PY_LONG_LONG)val;
+    } else
+#endif
+    if (likely(PyLong_Check(x))) {
+        if (is_unsigned) {
+            if (unlikely(Py_SIZE(x) < 0)) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "can't convert negative value to signed PY_LONG_LONG");
+                return (signed PY_LONG_LONG)-1;
+            }
+            return PyLong_AsUnsignedLongLong(x);
+        } else {
+            return PyLong_AsLongLong(x);
+        }
+    } else {
+        signed PY_LONG_LONG val;
+        PyObject *tmp = __Pyx_PyNumber_Int(x);
+        if (!tmp) return (signed PY_LONG_LONG)-1;
+        val = __Pyx_PyInt_AsSignedLongLong(tmp);
+        Py_DECREF(tmp);
+        return val;
+    }
+}
+
+#include "compile.h"
+#include "frameobject.h"
+#include "traceback.h"
+
+static void __Pyx_AddTraceback(const char *funcname) {
+    PyObject *py_srcfile = 0;
+    PyObject *py_funcname = 0;
+    PyObject *py_globals = 0;
+    PyCodeObject *py_code = 0;
+    PyFrameObject *py_frame = 0;
+
+    #if PY_MAJOR_VERSION < 3
+    py_srcfile = PyString_FromString(__pyx_filename);
+    #else
+    py_srcfile = PyUnicode_FromString(__pyx_filename);
+    #endif
+    if (!py_srcfile) goto bad;
+    if (__pyx_clineno) {
+        #if PY_MAJOR_VERSION < 3
+        py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, __pyx_clineno);
+        #else
+        py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, __pyx_clineno);
+        #endif
+    }
+    else {
+        #if PY_MAJOR_VERSION < 3
+        py_funcname = PyString_FromString(funcname);
+        #else
+        py_funcname = PyUnicode_FromString(funcname);
+        #endif
+    }
+    if (!py_funcname) goto bad;
+    py_globals = PyModule_GetDict(__pyx_m);
+    if (!py_globals) goto bad;
+    py_code = PyCode_New(
+        0,            /*int argcount,*/
+        #if PY_MAJOR_VERSION >= 3
+        0,            /*int kwonlyargcount,*/
+        #endif
+        0,            /*int nlocals,*/
+        0,            /*int stacksize,*/
+        0,            /*int flags,*/
+        __pyx_empty_bytes, /*PyObject *code,*/
+        __pyx_empty_tuple,  /*PyObject *consts,*/
+        __pyx_empty_tuple,  /*PyObject *names,*/
+        __pyx_empty_tuple,  /*PyObject *varnames,*/
+        __pyx_empty_tuple,  /*PyObject *freevars,*/
+        __pyx_empty_tuple,  /*PyObject *cellvars,*/
+        py_srcfile,   /*PyObject *filename,*/
+        py_funcname,  /*PyObject *name,*/
+        __pyx_lineno,   /*int firstlineno,*/
+        __pyx_empty_bytes  /*PyObject *lnotab*/
+    );
+    if (!py_code) goto bad;
+    py_frame = PyFrame_New(
+        PyThreadState_GET(), /*PyThreadState *tstate,*/
+        py_code,             /*PyCodeObject *code,*/
+        py_globals,          /*PyObject *globals,*/
+        0                    /*PyObject *locals*/
+    );
+    if (!py_frame) goto bad;
+    py_frame->f_lineno = __pyx_lineno;
+    PyTraceBack_Here(py_frame);
+bad:
+    Py_XDECREF(py_srcfile);
+    Py_XDECREF(py_funcname);
+    Py_XDECREF(py_code);
+    Py_XDECREF(py_frame);
+}
+
+static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
+    while (t->p) {
+        #if PY_MAJOR_VERSION < 3
+        if (t->is_unicode) {
+            *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL);
+        } else if (t->intern) {
+            *t->p = PyString_InternFromString(t->s);
+        } else {
+            *t->p = PyString_FromStringAndSize(t->s, t->n - 1);
+        }
+        #else  /* Python 3+ has unicode identifiers */
+        if (t->is_unicode | t->is_str) {
+            if (t->intern) {
+                *t->p = PyUnicode_InternFromString(t->s);
+            } else if (t->encoding) {
+                *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL);
+            } else {
+                *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1);
+            }
+        } else {
+            *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1);
+        }
+        #endif
+        if (!*t->p)
+            return -1;
+        ++t;
+    }
+    return 0;
+}
+
+/* Type Conversion Functions */
+
+static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
+   if (x == Py_True) return 1;
+   else if ((x == Py_False) | (x == Py_None)) return 0;
+   else return PyObject_IsTrue(x);
+}
+
+static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) {
+  PyNumberMethods *m;
+  const char *name = NULL;
+  PyObject *res = NULL;
+#if PY_VERSION_HEX < 0x03000000
+  if (PyInt_Check(x) || PyLong_Check(x))
+#else
+  if (PyLong_Check(x))
+#endif
+    return Py_INCREF(x), x;
+  m = Py_TYPE(x)->tp_as_number;
+#if PY_VERSION_HEX < 0x03000000
+  if (m && m->nb_int) {
+    name = "int";
+    res = PyNumber_Int(x);
+  }
+  else if (m && m->nb_long) {
+    name = "long";
+    res = PyNumber_Long(x);
+  }
+#else
+  if (m && m->nb_int) {
+    name = "int";
+    res = PyNumber_Long(x);
+  }
+#endif
+  if (res) {
+#if PY_VERSION_HEX < 0x03000000
+    if (!PyInt_Check(res) && !PyLong_Check(res)) {
+#else
+    if (!PyLong_Check(res)) {
+#endif
+      PyErr_Format(PyExc_TypeError,
+                   "__%s__ returned non-%s (type %.200s)",
+                   name, name, Py_TYPE(res)->tp_name);
+      Py_DECREF(res);
+      return NULL;
+    }
+  }
+  else if (!PyErr_Occurred()) {
+    PyErr_SetString(PyExc_TypeError,
+                    "an integer is required");
+  }
+  return res;
+}
+
+static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
+  Py_ssize_t ival;
+  PyObject* x = PyNumber_Index(b);
+  if (!x) return -1;
+  ival = PyInt_AsSsize_t(x);
+  Py_DECREF(x);
+  return ival;
+}
+
+static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) {
+#if PY_VERSION_HEX < 0x02050000
+   if (ival <= LONG_MAX)
+       return PyInt_FromLong((long)ival);
+   else {
+       unsigned char *bytes = (unsigned char *) &ival;
+       int one = 1; int little = (int)*(unsigned char*)&one;
+       return _PyLong_FromByteArray(bytes, sizeof(size_t), little, 0);
+   }
+#else
+   return PyInt_FromSize_t(ival);
+#endif
+}
+
+static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject* x) {
+   unsigned PY_LONG_LONG val = __Pyx_PyInt_AsUnsignedLongLong(x);
+   if (unlikely(val == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())) {
+       return (size_t)-1;
+   } else if (unlikely(val != (unsigned PY_LONG_LONG)(size_t)val)) {
+       PyErr_SetString(PyExc_OverflowError,
+                       "value too large to convert to size_t");
+       return (size_t)-1;
+   }
+   return (size_t)val;
+}
+
+
+#endif /* Py_PYTHON_H */
diff --git a/pd/portmidi/pm_python/pyportmidi/_pyportmidi.pyx b/pd/portmidi/pm_python/pyportmidi/_pyportmidi.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..e43bd2b28b41c334b73ec5d95fccfe8cdadb5855
--- /dev/null
+++ b/pd/portmidi/pm_python/pyportmidi/_pyportmidi.pyx
@@ -0,0 +1,537 @@
+# pyPortMidi
+# Python bindings for PortMidi
+# John Harrison
+# http://sound.media.mit.edu/~harrison
+# harrison@media.mit.edu
+# written in Pyrex
+__version__="0.07"
+
+import array
+
+# CHANGES:
+
+# 0.0.5: (June 1st, 2009)
+#   Output no longer calls abort when it deallocates.
+#   Added abort and close methods.
+#   Need to call Abort() explicityly if you want that to happen.
+
+
+#
+# 0.0.3: (March 15, 2005)
+#   changed everything from tuples to lists
+#   return 4 values for PmRead instead of 3 (for SysEx)
+#   minor fixes for flexibility and error checking
+#   flushed out DistUtils package and added Mac and Linux compile support
+#   Markus Pfaff: added ability for WriteSysEx to accept lists as well
+#                 as strings
+
+# 0.0.2:
+#   fixed pointer to function calls to avoid necessity of pyport library
+
+# 0.0.1:
+#   initial release
+
+cdef extern from "portmidi.h":
+    ctypedef enum PmError:
+        pmNoError = 0,
+        pmHostError = -10000,
+        pmInvalidDeviceId, #/* out of range or output device when input is requested or vice versa */
+        pmInsufficientMemory,
+        pmBufferTooSmall,
+        pmBufferOverflow,
+        pmBadPtr,
+        pmBadData, #/* illegal midi data, e.g. missing EOX */
+        pmInternalError,
+        pmBufferMaxSize, #/* buffer is already as large as it can be */
+    PmError Pm_Initialize()
+    PmError Pm_Terminate()
+    ctypedef void PortMidiStream
+    ctypedef PortMidiStream PmStream # CHECK THIS!
+    ctypedef int PmDeviceID
+    int Pm_HasHostError( PortMidiStream * stream )  
+    char *Pm_GetErrorText( PmError errnum )
+    Pm_GetHostErrorText(char * msg, unsigned int len)
+    ctypedef struct PmDeviceInfo:
+        int structVersion
+        char *interf #/* underlying MIDI API, e.g. MMSystem or DirectX */
+        char *name   #/* device name, e.g. USB MidiSport 1x1 */
+        int input    #/* true iff input is available */
+        int output   #/* true iff output is available */
+        int opened   #/* used by generic PortMidi code to do error checking on arguments */
+    int Pm_CountDevices()
+    PmDeviceID Pm_GetDefaultInputDeviceID()
+    PmDeviceID Pm_GetDefaultOutputDeviceID()
+    ctypedef long PmTimestamp
+    ctypedef PmTimestamp (*PmTimeProcPtr)(void *time_info)
+    #PmBefore is not defined...
+    PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id )
+    PmError Pm_OpenInput( PortMidiStream** stream,
+                          PmDeviceID inputDevice,
+                          void *inputDriverInfo,
+                          long bufferSize,
+                          long (*PmPtr) (), # long = PtTimestamp
+                          void *time_info )
+    PmError Pm_OpenOutput( PortMidiStream** stream,
+                           PmDeviceID outputDevice,
+                           void *outputDriverInfo,
+                           long bufferSize,
+                           #long (*PmPtr) (), # long = PtTimestamp
+                           PmTimeProcPtr time_proc, # long = PtTimestamp
+                           void *time_info,
+                           long latency )
+    PmError Pm_SetFilter( PortMidiStream* stream, long filters )
+    PmError Pm_Abort( PortMidiStream* stream )
+    PmError Pm_Close( PortMidiStream* stream )
+    ctypedef long PmMessage
+    ctypedef struct PmEvent:
+        PmMessage message
+        PmTimestamp timestamp
+    PmError Pm_Read( PortMidiStream *stream, PmEvent *buffer, long length )
+    PmError Pm_Poll( PortMidiStream *stream)
+    int Pm_Channel(int channel)
+    PmError Pm_SetChannelMask(PortMidiStream *stream, int mask)
+    PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length )
+    PmError Pm_WriteSysEx( PortMidiStream *stream, PmTimestamp when, unsigned char *msg)
+
+cdef extern from "porttime.h":
+    ctypedef enum PtError:
+        ptNoError = 0,
+        ptHostError = -10000,
+        ptAlreadyStarted,
+        ptAlreadyStopped,
+        ptInsufficientMemory
+    ctypedef long PtTimestamp
+    ctypedef void (* PtCallback)( PtTimestamp timestamp, void *userData )
+    PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
+    PtTimestamp Pt_Time()
+
+FILT_ACTIVE=0x1
+FILT_SYSEX=0x2
+FILT_CLOCK=0x4
+FILT_PLAY=0x8
+FILT_F9=0x10
+FILT_TICK=0x10
+FILT_FD=0x20
+FILT_UNDEFINED=0x30
+FILT_RESET=0x40
+FILT_REALTIME=0x7F
+FILT_NOTE=0x80
+FILT_CHANNEL_AFTERTOUCH=0x100
+FILT_POLY_AFTERTOUCH=0x200
+FILT_AFTERTOUCH=0x300
+FILT_PROGRAM=0x400
+FILT_CONTROL=0x800
+FILT_PITCHBEND=0x1000
+FILT_MTC=0x2000
+FILT_SONG_POSITION=0x4000
+FILT_SONG_SELECT=0x8000
+FILT_TUNE=0x10000
+FALSE=0
+TRUE=1
+
+def Initialize():
+    """
+Initialize: call this first
+    """
+    Pm_Initialize()
+    Pt_Start(1, NULL, NULL) # /* equiv to TIME_START: start timer w/ ms accuracy */
+
+def Terminate():
+    """
+Terminate: call this to clean up Midi streams when done.
+If you do not call this on Windows machines when you are
+done with MIDI, your system may crash.
+    """
+    Pm_Terminate()
+
+def GetDefaultInputDeviceID():
+    return Pm_GetDefaultInputDeviceID()
+
+def GetDefaultOutputDeviceID():
+    return Pm_GetDefaultOutputDeviceID()
+
+def CountDevices():
+    return Pm_CountDevices()
+
+def GetDeviceInfo(i):
+    """
+GetDeviceInfo(<device number>): returns 5 parameters
+  - underlying MIDI API
+  - device name
+  - TRUE iff input is available
+  - TRUE iff output is available
+  - TRUE iff device stream is already open
+    """
+    cdef PmDeviceInfo *info
+
+    # disregarding the constness from Pm_GetDeviceInfo, since pyrex doesn't do const.
+    info = <PmDeviceInfo *>Pm_GetDeviceInfo(i)
+
+    if info <> NULL: return info.interf, info.name, info.input, info.output, info.opened
+    else: return 
+
+def Time():
+    """
+Time() returns the current time in ms
+of the PortMidi timer
+    """
+    return Pt_Time()
+
+def GetErrorText(err):
+    """
+GetErrorText(<err num>) returns human-readable error
+messages translated from error numbers
+    """
+    return Pm_GetErrorText(err)
+
+def Channel(chan):
+    """
+Channel(<chan>) is used with ChannelMask on input MIDI streams.
+Example: to receive input on channels 1 and 10 on a MIDI
+         stream called MidiIn:
+MidiIn.SetChannelMask(pypm.Channel(1) | pypm.Channel(10))
+
+note: PyPortMidi Channel function has been altered from
+      the original PortMidi c call to correct for what
+      seems to be a bug --- i.e. channel filters were
+      all numbered from 0 to 15 instead of 1 to 16.
+    """
+    return Pm_Channel(chan-1)
+
+cdef class Output:
+    """
+class Output:
+    define an output MIDI stream. Takes the form:
+        x = pypm.Output(MidiOutputDevice, latency)
+    latency is in ms.
+    If latency = 0 then timestamps for output are ignored.
+    """
+    cdef int i
+    cdef PmStream *midi
+    cdef int debug
+    cdef int _aborted
+
+    def __init__(self, OutputDevice, latency=0):
+        
+        cdef PmError err
+        #cdef PtTimestamp (*PmPtr) ()
+        cdef PmTimeProcPtr PmPtr
+
+        self.i = OutputDevice
+        self.debug = 0
+        self._aborted = 0
+        
+        if latency == 0:
+            PmPtr = NULL
+        else:
+            PmPtr = <PmTimeProcPtr>&Pt_Time
+        if self.debug: print "Opening Midi Output"
+	# Why is bufferSize 0 here?
+        err = Pm_OpenOutput(&(self.midi), self.i, NULL, 0, PmPtr, NULL, latency)
+        if err < 0:
+                s = Pm_GetErrorText(err)
+                # Something's amiss here - if we try to throw an Exception
+               	# here, we crash.
+                if not err == -10000:
+                        raise Exception,s
+                else:
+                        print "Unable to open Midi OutputDevice=",OutputDevice," err=",s
+
+    def __dealloc__(self):
+        if self.debug: print "Closing MIDI output stream and destroying instance"
+        #err = Pm_Abort(self.midi)
+        #if err < 0: raise Exception, Pm_GetErrorText(err)
+        err = Pm_Close(self.midi)
+        if err < 0: raise Exception, Pm_GetErrorText(err) 
+
+
+    def _check_open(self):
+        """ checks to see if the midi is open, and if not, raises an error.
+        """
+
+        if self.midi == NULL:
+            raise Exception, "midi Output not open."
+
+        if self._aborted:
+            raise Exception, "midi Output aborted.  Need to call Close after Abort."
+
+    def Close(self):
+        """
+Close()
+    closes a midi stream, flushing any pending buffers.
+    (PortMidi attempts to close open streams when the application
+    exits -- this is particularly difficult under Windows.)
+        """
+        #if not self.midi:
+        #    return
+
+        err = Pm_Close(self.midi)
+        if err < 0:
+            raise Exception, Pm_GetErrorText(err)
+        #self.midi = NULL
+
+
+    def Abort(self):
+        """
+Abort() terminates outgoing messages immediately
+    The caller should immediately close the output port;
+    this call may result in transmission of a partial midi message.
+    There is no abort for Midi input because the user can simply
+    ignore messages in the buffer and close an input device at
+    any time.
+        """
+        #if not self.midi:
+        #    return
+
+        err = Pm_Abort(self.midi)
+        if err < 0:
+            raise Exception, Pm_GetErrorText(err)
+
+        self._aborted = 1
+
+
+    def Write(self, data):
+        """
+Write(data)
+    output a series of MIDI information in the form of a list:
+         Write([[[status <,data1><,data2><,data3>],timestamp],
+                [[status <,data1><,data2><,data3>],timestamp],...])
+    <data> fields are optional
+    example: choose program change 1 at time 20000 and
+    send note 65 with velocity 100 500 ms later.
+         Write([[[0xc0,0,0],20000],[[0x90,60,100],20500]])
+    notes:
+      1. timestamps will be ignored if latency = 0.
+      2. To get a note to play immediately, send MIDI info with
+         timestamp read from function Time.
+      3. understanding optional data fields:
+           Write([[[0xc0,0,0],20000]]) is equivalent to
+           Write([[[0xc0],20000]])
+        """
+        cdef PmEvent buffer[1024]
+        cdef PmError err
+        cdef int i
+
+        self._check_open()
+
+
+        if len(data) > 1024: raise IndexError, 'maximum list length is 1024'
+        else:
+            for loop1 in range(len(data)):
+                if ((len(data[loop1][0]) > 4) |
+                    (len(data[loop1][0]) < 1)):
+                    raise IndexError, str(len(data[loop1][0]))+' arguments in event list'
+                buffer[loop1].message = 0
+                for i in range(len(data[loop1][0])):
+                    buffer[loop1].message = buffer[loop1].message + ((data[loop1][0][i]&0xFF) << (8*i))
+                buffer[loop1].timestamp = data[loop1][1]
+                if self.debug: print loop1," : ",buffer[loop1].message," : ",buffer[loop1].timestamp
+        if self.debug: print "writing to midi buffer"
+        err= Pm_Write(self.midi, buffer, len(data))
+        if err < 0: raise Exception, Pm_GetErrorText(err)
+        
+    def WriteShort(self, status, data1 = 0, data2 = 0):
+        """
+WriteShort(status <, data1><, data2>)
+     output MIDI information of 3 bytes or less.
+     data fields are optional
+     status byte could be:
+          0xc0 = program change
+          0x90 = note on
+          etc.
+          data bytes are optional and assumed 0 if omitted
+     example: note 65 on with velocity 100
+          WriteShort(0x90,65,100)
+        """
+        cdef PmEvent buffer[1]
+        cdef PmError err
+        self._check_open()
+
+        buffer[0].timestamp = Pt_Time()
+        buffer[0].message = ((((data2) << 16) & 0xFF0000) | (((data1) << 8) & 0xFF00) | ((status) & 0xFF))
+        if self.debug: print "Writing to MIDI buffer"
+        err = Pm_Write(self.midi, buffer, 1) # stream, buffer, length
+        if err < 0 : raise Exception, Pm_GetErrorText(err)
+
+    def WriteSysEx(self, when, msg):
+        """
+        WriteSysEx(<timestamp>,<msg>)
+        writes a timestamped system-exclusive midi message.
+        <msg> can be a *list* or a *string*
+        example:
+            (assuming y is an input MIDI stream)
+            y.WriteSysEx(0,'\\xF0\\x7D\\x10\\x11\\x12\\x13\\xF7')
+                              is equivalent to
+            y.WriteSysEx(pypm.Time,
+            [0xF0, 0x7D, 0x10, 0x11, 0x12, 0x13, 0xF7])
+        """
+        cdef PmError err
+        cdef char *cmsg
+        cdef PtTimestamp CurTime
+
+        self._check_open()
+
+        if type(msg) is list:
+            msg = array.array('B',msg).tostring() # Markus Pfaff contribution
+        cmsg = msg
+
+        CurTime = Pt_Time()
+        err = Pm_WriteSysEx(self.midi, when, <unsigned char *> cmsg)
+        if err < 0 : raise Exception, Pm_GetErrorText(err)
+        while Pt_Time() == CurTime: # wait for SysEx to go thru or...my
+            pass                    # win32 machine crashes w/ multiple SysEx
+
+
+
+
+
+
+
+
+
+
+
+cdef class Input:
+    """
+class Input:
+    define an input MIDI stream. Takes the form:
+        x = pypm.Input(MidiInputDevice)
+    """
+    cdef PmStream *midi
+    cdef int debug
+    cdef int i
+
+    def __init__(self, InputDevice, buffersize=4096):
+        cdef PmError err
+        self.i = InputDevice
+        self.debug = 0
+        err= Pm_OpenInput(&(self.midi),self.i,NULL,buffersize,&Pt_Time,NULL)
+        if err < 0: raise Exception, Pm_GetErrorText(err)
+        if self.debug: print "MIDI input opened."
+
+    def __dealloc__(self):
+        cdef PmError err
+        if self.debug: print "Closing MIDI input stream and destroying instance"
+
+        err = Pm_Close(self.midi)
+        if err < 0:
+            raise Exception, Pm_GetErrorText(err)
+
+
+
+    def _check_open(self):
+        """ checks to see if the midi is open, and if not, raises an error.
+        """
+
+        if self.midi == NULL:
+            raise Exception, "midi Input not open."
+
+
+    def Close(self):
+        """
+Close()
+    closes a midi stream, flushing any pending buffers.
+    (PortMidi attempts to close open streams when the application
+    exits -- this is particularly difficult under Windows.)
+        """
+        #if not self.midi:
+        #    return
+
+        err = Pm_Close(self.midi)
+        if err < 0:
+            raise Exception, Pm_GetErrorText(err)
+        #self.midi = NULL
+
+
+
+    def SetFilter(self, filters):
+        """
+    SetFilter(<filters>) sets filters on an open input stream
+    to drop selected input types. By default, only active sensing
+    messages are filtered. To prohibit, say, active sensing and
+    sysex messages, call
+    SetFilter(stream, FILT_ACTIVE | FILT_SYSEX);
+
+    Filtering is useful when midi routing or midi thru functionality
+    is being provided by the user application.
+    For example, you may want to exclude timing messages
+    (clock, MTC, start/stop/continue), while allowing note-related
+    messages to pass. Or you may be using a sequencer or drum-machine
+    for MIDI clock information but want to exclude any notes
+    it may play.
+
+    Note: SetFilter empties the buffer after setting the filter,
+    just in case anything got through.
+        """
+        cdef PmEvent buffer[1]
+        cdef PmError err
+
+        self._check_open()
+
+
+        err = Pm_SetFilter(self.midi, filters)
+
+        if err < 0: raise Exception, Pm_GetErrorText(err)
+
+        while(Pm_Poll(self.midi) != pmNoError):
+
+            err = Pm_Read(self.midi,buffer,1)
+            if err < 0: raise Exception, Pm_GetErrorText(err)
+
+    def SetChannelMask(self, mask):
+        """
+    SetChannelMask(<mask>) filters incoming messages based on channel.
+    The mask is a 16-bit bitfield corresponding to appropriate channels
+    Channel(<channel>) can assist in calling this function.
+    i.e. to set receive only input on channel 1, call with
+    SetChannelMask(Channel(1))
+    Multiple channels should be OR'd together, like
+    SetChannelMask(Channel(10) | Channel(11))
+    note: PyPortMidi Channel function has been altered from
+          the original PortMidi c call to correct for what
+          seems to be a bug --- i.e. channel filters were
+          all numbered from 0 to 15 instead of 1 to 16.
+        """
+        cdef PmError err
+
+        self._check_open()
+
+        err = Pm_SetChannelMask(self.midi,mask)
+        if err < 0: raise Exception, Pm_GetErrorText(err)
+        
+    def Poll(self):
+        """
+    Poll tests whether input is available,
+    returning TRUE, FALSE, or an error value.
+        """
+        cdef PmError err
+        self._check_open()
+
+        err = Pm_Poll(self.midi)
+        if err < 0: raise Exception, Pm_GetErrorText(err)
+        return err
+    
+    def Read(self,length):
+        """
+Read(length): returns up to <length> midi events stored in
+the buffer and returns them as a list:
+[[[status,data1,data2,data3],timestamp],
+ [[status,data1,data2,data3],timestamp],...]
+example: Read(50) returns all the events in the buffer,
+         up to 50 events.
+        """
+        cdef PmEvent buffer[1024]
+        
+        self._check_open()
+
+        x = []
+        
+        if length > 1024: raise IndexError, 'maximum buffer length is 1024'
+        if length < 1: raise IndexError, 'minimum buffer length is 1'
+        NumEvents = Pm_Read(self.midi,buffer,length)
+        if NumEvents < 0: raise Exception, Pm_GetErrorText(NumEvents)
+        x=[]
+        if NumEvents >= 1:
+            for loop in range(NumEvents):
+                 x.append([[buffer[loop].message & 0xff, (buffer[loop].message >> 8) & 0xFF, (buffer[loop].message >> 16) & 0xFF, (buffer[loop].message >> 24) & 0xFF], buffer[loop].timestamp])
+        return x
diff --git a/pd/portmidi/pm_python/pyportmidi/midi.py b/pd/portmidi/pm_python/pyportmidi/midi.py
new file mode 100644
index 0000000000000000000000000000000000000000..71e4f2b4b8f7106552f13d41e7bdc863dad3ff93
--- /dev/null
+++ b/pd/portmidi/pm_python/pyportmidi/midi.py
@@ -0,0 +1,566 @@
+"""
+Module for interacting with midi input and output.
+
+The midi module can send output to midi devices, and get input
+from midi devices.  It can also list midi devices on the system.
+
+Including real midi devices, and virtual ones.
+
+It uses the portmidi library.  Is portable to which ever platforms
+portmidi supports (currently windows, OSX, and linux).
+"""
+
+import atexit
+
+
+
+_init = False
+_pypm = None
+
+
+__all__ = [ "Input",
+            "MidiException",
+            "Output",
+            "get_count",
+            "get_default_input_id",
+            "get_default_output_id",
+            "get_device_info",
+            "init",
+            "quit",
+            "time",
+           ]
+
+__theclasses__ = ["Input", "Output"]
+
+
+def init():
+    """initialize the midi module
+    pyportmidi.init(): return None
+    
+    Call the initialisation function before using the midi module.
+    
+    It is safe to call this more than once.
+    """
+    global _init, _pypm
+    if not _init:
+        import pyportmidi._pyportmidi
+        _pypm = pyportmidi._pyportmidi
+
+        _pypm.Initialize()
+        _init = True
+        atexit.register(quit)
+
+
+def quit():
+    """uninitialize the midi module
+    pyportmidi.quit(): return None
+
+
+    Called automatically atexit if you don't call it.
+
+    It is safe to call this function more than once.
+    """
+    global _init, _pypm
+    if _init:
+        # TODO: find all Input and Output classes and close them first?
+        _pypm.Terminate()
+        _init = False
+        del _pypm
+
+def _check_init():
+    if not _init:
+        raise RuntimeError("pyportmidi not initialised.")
+
+def get_count():
+    """gets the number of devices.
+    pyportmidi.get_count(): return num_devices
+
+
+    Device ids range from 0 to get_count() -1
+    """
+    _check_init()
+    return _pypm.CountDevices()
+
+
+
+
+def get_default_input_id():
+    """gets default input device number
+    pyportmidi.get_default_input_id(): return default_id
+    
+    
+    Return the default device ID or -1 if there are no devices.
+    The result can be passed to the Input()/Ouput() class.
+    
+    On the PC, the user can specify a default device by
+    setting an environment variable. For example, to use device #1.
+    
+        set PM_RECOMMENDED_INPUT_DEVICE=1
+    
+    The user should first determine the available device ID by using
+    the supplied application "testin" or "testout".
+    
+    In general, the registry is a better place for this kind of info,
+    and with USB devices that can come and go, using integers is not
+    very reliable for device identification. Under Windows, if
+    PM_RECOMMENDED_OUTPUT_DEVICE (or PM_RECOMMENDED_INPUT_DEVICE) is
+    *NOT* found in the environment, then the default device is obtained
+    by looking for a string in the registry under:
+        HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Input_Device
+    and HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Output_Device
+    for a string. The number of the first device with a substring that
+    matches the string exactly is returned. For example, if the string
+    in the registry is "USB", and device 1 is named
+    "In USB MidiSport 1x1", then that will be the default
+    input because it contains the string "USB".
+    
+    In addition to the name, get_device_info() returns "interf", which
+    is the interface name. (The "interface" is the underlying software
+    system or API used by PortMidi to access devices. Examples are
+    MMSystem, DirectX (not implemented), ALSA, OSS (not implemented), etc.)
+    At present, the only Win32 interface is "MMSystem", the only Linux
+    interface is "ALSA", and the only Max OS X interface is "CoreMIDI".
+    To specify both the interface and the device name in the registry,
+    separate the two with a comma and a space, e.g.:
+        MMSystem, In USB MidiSport 1x1
+    In this case, the string before the comma must be a substring of
+    the "interf" string, and the string after the space must be a
+    substring of the "name" name string in order to match the device.
+    
+    Note: in the current release, the default is simply the first device
+    (the input or output device with the lowest PmDeviceID).
+    """
+    return _pypm.GetDefaultInputDeviceID()
+
+
+
+
+def get_default_output_id():
+    """gets default output device number
+    pyportmidi.get_default_output_id(): return default_id
+    
+    
+    Return the default device ID or -1 if there are no devices.
+    The result can be passed to the Input()/Ouput() class.
+    
+    On the PC, the user can specify a default device by
+    setting an environment variable. For example, to use device #1.
+    
+        set PM_RECOMMENDED_OUTPUT_DEVICE=1
+    
+    The user should first determine the available device ID by using
+    the supplied application "testin" or "testout".
+    
+    In general, the registry is a better place for this kind of info,
+    and with USB devices that can come and go, using integers is not
+    very reliable for device identification. Under Windows, if
+    PM_RECOMMENDED_OUTPUT_DEVICE (or PM_RECOMMENDED_INPUT_DEVICE) is
+    *NOT* found in the environment, then the default device is obtained
+    by looking for a string in the registry under:
+        HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Input_Device
+    and HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Output_Device
+    for a string. The number of the first device with a substring that
+    matches the string exactly is returned. For example, if the string
+    in the registry is "USB", and device 1 is named
+    "In USB MidiSport 1x1", then that will be the default
+    input because it contains the string "USB".
+    
+    In addition to the name, get_device_info() returns "interf", which
+    is the interface name. (The "interface" is the underlying software
+    system or API used by PortMidi to access devices. Examples are
+    MMSystem, DirectX (not implemented), ALSA, OSS (not implemented), etc.)
+    At present, the only Win32 interface is "MMSystem", the only Linux
+    interface is "ALSA", and the only Max OS X interface is "CoreMIDI".
+    To specify both the interface and the device name in the registry,
+    separate the two with a comma and a space, e.g.:
+        MMSystem, In USB MidiSport 1x1
+    In this case, the string before the comma must be a substring of
+    the "interf" string, and the string after the space must be a
+    substring of the "name" name string in order to match the device.
+    
+    Note: in the current release, the default is simply the first device
+    (the input or output device with the lowest PmDeviceID).
+    """
+    _check_init()
+    return _pypm.GetDefaultOutputDeviceID()
+
+
+def get_device_info(an_id):
+    """ returns information about a midi device
+    pyportmidi.get_device_info(an_id): return (interf, name, input, output, opened) 
+
+    interf - a text string describing the device interface, eg 'ALSA'.
+    name - a text string for the name of the device, eg 'Midi Through Port-0'
+    input - 0, or 1 if the device is an input device.
+    output - 0, or 1 if the device is an output device.
+    opened - 0, or 1 if the device is opened.
+
+    If the id is out of range, the function returns None.
+    """
+    _check_init()
+    return _pypm.GetDeviceInfo(an_id) 
+
+
+class Input(object):
+    """Input is used to get midi input from midi devices.
+    Input(device_id)
+    Input(device_id, buffer_size)
+
+    buffer_size -the number of input events to be buffered waiting to 
+      be read using Input.read() 
+    """
+
+    def __init__(self, device_id, buffer_size=4096):
+        """
+        The buffer_size specifies the number of input events to be buffered 
+        waiting to be read using Input.read().
+        """
+        _check_init()
+ 
+        if device_id == -1:
+            raise MidiException("Device id is -1, not a valid output id.  -1 usually means there were no default Output devices.")
+            
+        try:
+            r = get_device_info(device_id)
+        except TypeError:
+            raise TypeError("an integer is required")
+        except OverflowError:
+            raise OverflowError("long int too large to convert to int")
+
+        # and now some nasty looking error checking, to provide nice error 
+        #   messages to the kind, lovely, midi using people of whereever.
+        if r:
+            interf, name, input, output, opened = r
+            if input:
+                try:
+                    self._input = _pypm.Input(device_id, buffer_size)
+                except TypeError:
+                    raise TypeError("an integer is required")
+                self.device_id = device_id
+
+            elif output:
+                raise MidiException("Device id given is not a valid input id, it is an output id.")
+            else:
+                raise MidiException("Device id given is not a valid input id.")
+        else:
+            raise MidiException("Device id invalid, out of range.")
+
+
+
+
+    def _check_open(self):
+        if self._input is None:
+            raise MidiException("midi not open.")
+
+
+
+    def close(self):
+        """ closes a midi stream, flushing any pending buffers.
+        Input.close(): return None
+
+        PortMidi attempts to close open streams when the application
+        exits -- this is particularly difficult under Windows.
+        """
+        _check_init()
+        if not (self._input is None):
+            self._input.Close()
+        self._input = None
+
+
+
+    def read(self, num_events):
+        """reads num_events midi events from the buffer.
+        Input.read(num_events): return midi_event_list
+
+        Reads from the Input buffer and gives back midi events.
+        [[[status,data1,data2,data3],timestamp],
+         [[status,data1,data2,data3],timestamp],...]
+        """
+        _check_init()
+        self._check_open()
+        return self._input.Read(num_events)
+
+
+    def poll(self):
+        """returns true if there's data, or false if not.
+        Input.poll(): return Bool
+
+        raises a MidiException on error.
+        """
+        _check_init()
+        self._check_open()
+
+        r = self._input.Poll()
+        if r == _pypm.TRUE:
+            return True
+        elif r == _pypm.FALSE:
+            return False
+        else:
+            err_text = GetErrorText(r)
+            raise MidiException( (r, err_text) )
+
+
+
+
+class Output(object):
+    """Output is used to send midi to an output device
+    Output(device_id)
+    Output(device_id, latency = 0)
+    Output(device_id, buffer_size = 4096)
+    Output(device_id, latency, buffer_size)
+
+    The buffer_size specifies the number of output events to be 
+    buffered waiting for output.  (In some cases -- see below -- 
+    PortMidi does not buffer output at all and merely passes data 
+    to a lower-level API, in which case buffersize is ignored.)
+
+    latency is the delay in milliseconds applied to timestamps to determine
+    when the output should actually occur. (If latency is < 0, 0 is 
+    assumed.)
+
+    If latency is zero, timestamps are ignored and all output is delivered
+    immediately. If latency is greater than zero, output is delayed until
+    the message timestamp plus the latency. (NOTE: time is measured 
+    relative to the time source indicated by time_proc. Timestamps are 
+    absolute, not relative delays or offsets.) In some cases, PortMidi 
+    can obtain better timing than your application by passing timestamps 
+    along to the device driver or hardware. Latency may also help you 
+    to synchronize midi data to audio data by matching midi latency to 
+    the audio buffer latency.
+
+    """
+
+    def __init__(self, device_id, latency = 0, buffer_size = 4096):
+        """Output(device_id)
+        Output(device_id, latency = 0)
+        Output(device_id, buffer_size = 4096)
+        Output(device_id, latency, buffer_size)
+
+        The buffer_size specifies the number of output events to be 
+        buffered waiting for output.  (In some cases -- see below -- 
+        PortMidi does not buffer output at all and merely passes data 
+        to a lower-level API, in which case buffersize is ignored.)
+
+        latency is the delay in milliseconds applied to timestamps to determine
+        when the output should actually occur. (If latency is < 0, 0 is 
+        assumed.)
+
+        If latency is zero, timestamps are ignored and all output is delivered
+        immediately. If latency is greater than zero, output is delayed until
+        the message timestamp plus the latency. (NOTE: time is measured 
+        relative to the time source indicated by time_proc. Timestamps are 
+        absolute, not relative delays or offsets.) In some cases, PortMidi 
+        can obtain better timing than your application by passing timestamps 
+        along to the device driver or hardware. Latency may also help you 
+        to synchronize midi data to audio data by matching midi latency to 
+        the audio buffer latency.
+        """
+     
+        _check_init()
+        self._aborted = 0
+
+        if device_id == -1:
+            raise MidiException("Device id is -1, not a valid output id.  -1 usually means there were no default Output devices.")
+            
+        try:
+            r = get_device_info(device_id)
+        except TypeError:
+            raise TypeError("an integer is required")
+        except OverflowError:
+            raise OverflowError("long int too large to convert to int")
+
+        # and now some nasty looking error checking, to provide nice error 
+        #   messages to the kind, lovely, midi using people of whereever.
+        if r:
+            interf, name, input, output, opened = r
+            if output:
+                try:
+                    self._output = _pypm.Output(device_id, latency)
+                except TypeError:
+                    raise TypeError("an integer is required")
+                self.device_id = device_id
+
+            elif input:
+                raise MidiException("Device id given is not a valid output id, it is an input id.")
+            else:
+                raise MidiException("Device id given is not a valid output id.")
+        else:
+            raise MidiException("Device id invalid, out of range.")
+
+    def _check_open(self):
+        if self._output is None:
+            raise MidiException("midi not open.")
+
+        if self._aborted:
+            raise MidiException("midi aborted.")
+
+
+    def close(self):
+        """ closes a midi stream, flushing any pending buffers.
+        Output.close(): return None
+
+        PortMidi attempts to close open streams when the application
+        exits -- this is particularly difficult under Windows.
+        """
+        _check_init()
+        if not (self._output is None):
+            self._output.Close()
+        self._output = None
+
+    def abort(self):
+        """terminates outgoing messages immediately
+        Output.abort(): return None
+
+        The caller should immediately close the output port;
+        this call may result in transmission of a partial midi message.
+        There is no abort for Midi input because the user can simply
+        ignore messages in the buffer and close an input device at
+        any time.
+        """
+
+        _check_init()
+        if self._output:
+            self._output.Abort()
+        self._aborted = 1
+
+
+
+
+
+    def write(self, data):
+        """writes a list of midi data to the Output
+        Output.write(data)
+
+        writes series of MIDI information in the form of a list:
+             write([[[status <,data1><,data2><,data3>],timestamp],
+                    [[status <,data1><,data2><,data3>],timestamp],...])
+        <data> fields are optional
+        example: choose program change 1 at time 20000 and
+        send note 65 with velocity 100 500 ms later.
+             write([[[0xc0,0,0],20000],[[0x90,60,100],20500]])
+        notes:
+          1. timestamps will be ignored if latency = 0.
+          2. To get a note to play immediately, send MIDI info with
+             timestamp read from function Time.
+          3. understanding optional data fields:
+               write([[[0xc0,0,0],20000]]) is equivalent to
+               write([[[0xc0],20000]])
+
+        Can send up to 1024 elements in your data list, otherwise an 
+         IndexError exception is raised.
+        """
+        _check_init()
+        self._check_open()
+
+        self._output.Write(data)
+
+
+    def write_short(self, status, data1 = 0, data2 = 0):
+        """write_short(status <, data1><, data2>)
+        Output.write_short(status)
+        Output.write_short(status, data1 = 0, data2 = 0)
+
+        output MIDI information of 3 bytes or less.
+        data fields are optional
+        status byte could be:
+             0xc0 = program change
+             0x90 = note on
+             etc.
+             data bytes are optional and assumed 0 if omitted
+        example: note 65 on with velocity 100
+             write_short(0x90,65,100)
+        """
+        _check_init()
+        self._check_open()
+        self._output.WriteShort(status, data1, data2)
+
+
+    def write_sys_ex(self, when, msg):
+        """writes a timestamped system-exclusive midi message.
+        Output.write_sys_ex(when, msg)
+
+        msg - can be a *list* or a *string*
+        when - a timestamp in miliseconds
+        example:
+          (assuming o is an onput MIDI stream)
+            o.write_sys_ex(0,'\\xF0\\x7D\\x10\\x11\\x12\\x13\\xF7')
+          is equivalent to
+            o.write_sys_ex(pyportmidi.time(),
+                           [0xF0,0x7D,0x10,0x11,0x12,0x13,0xF7])
+        """
+        _check_init()
+        self._check_open()
+        self._output.WriteSysEx(when, msg)
+
+
+    def note_on(self, note, velocity=None, channel = 0):
+        """turns a midi note on.  Note must be off.
+        Output.note_on(note, velocity=None, channel = 0)
+
+        Turn a note on in the output stream.  The note must already
+        be off for this to work correctly.
+        """
+        if velocity is None:
+            velocity = 0
+
+        if not (0 <= channel <= 15):
+            raise ValueError("Channel not between 0 and 15.")
+
+        self.write_short(0x90+channel, note, velocity)
+
+    def note_off(self, note, velocity=None, channel = 0):
+        """turns a midi note off.  Note must be on.
+        Output.note_off(note, velocity=None, channel = 0)
+
+        Turn a note off in the output stream.  The note must already
+        be on for this to work correctly.
+        """
+        if velocity is None:
+            velocity = 0
+
+        if not (0 <= channel <= 15):
+            raise ValueError("Channel not between 0 and 15.")
+
+        self.write_short(0x80 + channel, note, velocity)
+
+
+    def set_instrument(self, instrument_id, channel = 0):
+        """select an instrument, with a value between 0 and 127
+        Output.set_instrument(instrument_id, channel = 0)
+
+        """
+        if not (0 <= instrument_id <= 127):
+            raise ValueError("Undefined instrument id: %d" % instrument_id)
+
+        if not (0 <= channel <= 15):
+            raise ValueError("Channel not between 0 and 15.")
+
+        self.write_short(0xc0+channel, instrument_id)
+
+
+
+def time():
+    """returns the current time in ms of the PortMidi timer
+    pyportmidi.time(): return time
+
+    The time is reset to 0, when the module is inited.
+    """
+    return _pypm.Time()
+
+
+
+
+
+
+
+
+class MidiException(Exception):
+    """MidiException(errno) that can be raised.
+    """
+    def __init__(self, value):
+        self.parameter = value
+    def __str__(self):
+        return repr(self.parameter)
+
+
+
diff --git a/pd/portmidi/pm_python/setup.py b/pd/portmidi/pm_python/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..14ab1c758afb8aefa3cd3d9e338cfb4a59dce463
--- /dev/null
+++ b/pd/portmidi/pm_python/setup.py
@@ -0,0 +1,185 @@
+import sys
+import os
+import logging
+
+from distutils.core import setup, Command
+from distutils.extension import Extension
+try:
+    from Cython.Distutils import build_ext
+except ImportError:
+    logging.warn("Cython is preferred over pyrex for python3 compatibility.")
+    from Pyrex.Distutils import build_ext
+
+
+
+
+
+DESCRIPTION = open('README_PYTHON.txt').read()
+CHANGES = open('CHANGES.txt').read()
+TODO = open('TODO.txt').read()
+
+EXTRAS = {}
+
+long_description = DESCRIPTION + CHANGES + TODO
+#import sys
+#if "checkdocs" in sys.argv:
+#    print long_description
+
+
+METADATA = {
+    'name':             'pyportmidi',
+    'version':          '0.0.7',
+    'license':          'MIT License',
+    'url':              'http://pypi.python.org/pyportmidi/',
+    'author':           'John Harrison, Roger B. Dannenberg, Rene Dudfield, others...',
+    'author_email':     'renesd@gmail.com',
+    'maintainer':       'Rene Dudfield',
+    'maintainer_email': 'renesd@gmail.com',
+    'description':      'Python Wrappings for PortMidi #python.  CHANGES: new package layout.',
+    'long_description': long_description,
+    'classifiers':      [
+            'Development Status :: 2 - Pre-Alpha',
+            'Intended Audience :: Developers',
+            'Intended Audience :: Information Technology',
+            'License :: OSI Approved :: BSD License',
+            'Operating System :: MacOS :: MacOS X',
+            'Operating System :: Microsoft :: Windows',
+            'Operating System :: POSIX :: Linux',
+            'Programming Language :: Cython',
+            'Programming Language :: C',
+            'Programming Language :: Python :: 2',
+            'Programming Language :: Python :: 2.5',
+            'Programming Language :: Python :: 2.6',
+            'Programming Language :: Python :: 2.7',
+            'Programming Language :: Python :: 3',
+            'Programming Language :: Python :: 3.0',
+            'Programming Language :: Python :: 3.1',
+            'Programming Language :: Python :: 3.2',
+            'Topic :: Multimedia :: Sound/Audio :: MIDI',
+            'Topic :: Software Development :: Libraries',
+    ],
+}
+
+
+if "bdist_msi" in sys.argv:
+    # hack the version name to a format msi doesn't have trouble with
+    METADATA["version"] = METADATA["version"].replace("pre", "a0")
+    METADATA["version"] = METADATA["version"].replace("rc", "b0")
+    METADATA["version"] = METADATA["version"].replace("release", "")
+
+
+
+
+
+# allow optionally using setuptools for bdist_egg.
+using_setuptools = False
+
+if "-setuptools" in sys.argv:
+    using_setuptools = True
+
+    from setuptools import setup, Command
+    sys.argv.remove ("-setuptools")
+
+    EXTRAS.update({'include_package_data': True,
+                   'install_requires': [],
+                   'zip_safe': False,
+                   'test_suite' : 'pyportmidi.tests',
+                   }
+    )
+
+
+# test command.  For doing 'python setup.py test'
+class TestCommand(Command):
+    user_options = [ ]
+
+    def initialize_options(self):
+        self._dir = os.getcwd()
+
+    def finalize_options(self):
+        pass
+
+    def run(self):
+        '''
+        runs the tests with default options.
+        '''
+        import pyportmidi.tests
+        pyportmidi.tests.main()
+
+        #import subprocess
+        #return subprocess.call([sys.executable, "run_tests.py"])
+
+
+cmdclass = {'build_ext': build_ext}
+
+# we use our test command.
+if not using_setuptools:
+    import os
+    cmdclass['test'] = TestCommand
+
+
+
+scripts = []
+
+PACKAGEDATA = {
+    'cmdclass':    cmdclass,
+
+    'package_dir': {'pyportmidi': 'pyportmidi',
+                    #'pyportmidi.tests': 'test',
+                    #'pyportmidi.docs': 'docs',
+                    #'pyportmidi.examples': 'examples',
+
+                   },
+    'packages': ['pyportmidi',
+                 'pyportmidi.tests', 
+                ],
+    'scripts': scripts,
+}
+
+
+PACKAGEDATA.update(METADATA)
+PACKAGEDATA.update(EXTRAS)
+
+
+
+if sys.platform == 'win32':
+    print "Found Win32 platform"
+    EXTENSION = dict(
+        ext_modules=[ 
+            Extension("pyportmidi._pyportmidi", [os.path.join("pyportmidi", "_pyportmidi.pyx")],
+                      library_dirs = ["../Release"],
+                      libraries = ["portmidi", "winmm"],
+                      include_dirs = ["../porttime"],
+#                  define_macros = [("_WIN32_", None)]) # needed by portmidi.h
+                      extra_compile_args = ["/DWIN32"]) # needed by portmidi.h
+        ]
+    )
+elif sys.platform == 'darwin':
+    print "Found darwin (OS X) platform"
+    library_dirs = ["/usr/local/lib"]
+    include_dirs = ["/usr/local/include"]
+    EXTENSION = dict(
+        ext_modules=[ 
+            Extension("pyportmidi._pyportmidi", [os.path.join("pyportmidi", "_pyportmidi.pyx")],
+                      library_dirs = library_dirs,
+                      include_dirs = include_dirs,
+                      libraries = ["portmidi"],
+                      extra_link_args=["-framework", "CoreFoundation",
+                                       "-framework", "CoreMIDI",
+                                       "-framework", "CoreAudio"])
+        ]
+    )
+else:
+    print "Assuming Linux platform"
+    EXTENSION = dict(
+        ext_modules=[ 
+            Extension("pyportmidi._pyportmidi", [os.path.join("pyportmidi", "_pyportmidi.pyx")],
+                      library_dirs=["./linux"],
+                      libraries = ["portmidi", "asound", "pthread"]
+                      )
+        ]
+       
+    )
+
+PACKAGEDATA.update(EXTENSION)
+
+setup(**PACKAGEDATA)
diff --git a/pd/portmidi/pm_qt/README_QT.txt b/pd/portmidi/pm_qt/README_QT.txt
new file mode 100644
index 0000000000000000000000000000000000000000..613f4a19eee7e8fe7fca24400aa2a85b8f4e151a
--- /dev/null
+++ b/pd/portmidi/pm_qt/README_QT.txt
@@ -0,0 +1,15 @@
+README_QT.txt for PortMidi
+Richard Starfield
+20 Sep 2010
+
+This is a QtCreator build file for PortMidi.
+
+To build PortMidi on Windows with QtCreator:
+
+Move portmidi/pm_qt/portmidi.pro to portmidi/portmidi.pro
+
+Open portmidi.pro in QtCreator, change to the release build option and build all to compile the static library.
+
+This has been tested in Windows. The project file does include Linux build switches but they haven't been tested yet.
+
+To compile a DLL instead of a static library change line 11 from "CONFIG += staticlib" to "CONFIG += DLL"
diff --git a/pd/portmidi/pm_qt/portmidi.pro b/pd/portmidi/pm_qt/portmidi.pro
new file mode 100644
index 0000000000000000000000000000000000000000..886eec8f081bdf33509e69e36afb973fb143419c
--- /dev/null
+++ b/pd/portmidi/pm_qt/portmidi.pro
@@ -0,0 +1,47 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2010-09-02T12:50:47
+#
+#-------------------------------------------------
+
+QT       -= core gui
+
+TARGET = portmidi
+TEMPLATE = lib
+CONFIG += staticlib # replace this with DLL for dynamic link on Windows
+
+INCLUDEPATH = pm_common/ porttime/
+
+win32 {
+	INCLUDEPATH += pm_win/
+	LIBS += -lwinmm
+	SOURCES += pm_win/pmwinmm.c \
+	    pm_win/pmwin.c
+	HEADERS += pm_win/pmwinmm.h
+}
+
+# this build hasn't been tested on Linux yet
+unix {
+	DEFINES += PMALSA
+	INCLUDEPATH += pm_linux/
+	LIBS += -lasound
+	SOURCES += pm_linux/finddefault.c \
+	    pm_linux/pmlinux.c \
+	    pm_linux/pmlinuxalsa.c
+	HEADERS += pm_linux/pmlinux.h pm_linux/pmlinuxalsa.h
+}
+
+
+DEFINES -= UNICODE
+
+SOURCES += \
+    pm_common/portmidi.c \
+    pm_common/pmutil.c \
+    porttime/porttime.c \
+    porttime/ptwinmm.c
+
+HEADERS += \
+    pm_common/pmutil.h \
+    pm_common/pminternal.h \
+    pm_common/portmidi.h \
+    porttime/porttime.h
diff --git a/pd/portmidi/pm_test/CMakeLists.txt b/pd/portmidi/pm_test/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b89074b0bd5fcccd42776caccde57460710b8666
--- /dev/null
+++ b/pd/portmidi/pm_test/CMakeLists.txt
@@ -0,0 +1,26 @@
+# pm_test
+
+# set the build directory to be in portmidi, not in portmidi/pm_test
+# this is required for Xcode:
+if(APPLE)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+endif(APPLE)
+
+if(WIN32)
+include(../pm_win/static.cmake)
+endif(WIN32)
+
+macro(make_a_test name)
+  add_executable(${name} ${name}.c)
+  target_link_libraries(${name} portmidi-static ${PM_NEEDED_LIBS})
+  add_dependencies(${name} portmidi-static)
+endmacro(make_a_test)
+
+make_a_test(test)
+make_a_test(midithread)
+make_a_test(midithru)
+make_a_test(sysex)
+make_a_test(latency)
+make_a_test(mm)
+make_a_test(midiclock)
+make_a_test(qtest)
diff --git a/pd/portmidi/pm_test/latency.c b/pd/portmidi/pm_test/latency.c
new file mode 100755
index 0000000000000000000000000000000000000000..507648c1286c6ff0b20484fc1bcc90737015402a
--- /dev/null
+++ b/pd/portmidi/pm_test/latency.c
@@ -0,0 +1,290 @@
+/* latency.c -- measure latency of OS */
+
+#include "porttime.h"
+#include "portmidi.h"
+#include "stdlib.h"
+#include "stdio.h"
+#include "string.h"
+#include "assert.h"
+
+/* Latency is defined here to mean the time starting when a
+   process becomes ready to run, and ending when the process
+   actually runs. Latency is due to contention for the
+   processor, usually due to other processes, OS activity
+   including device drivers handling interrupts, and
+   waiting for the scheduler to suspend the currently running
+   process and activate the one that is waiting.
+
+   Latency can affect PortMidi applications: if a process fails
+   to wake up promptly, MIDI input may sit in the input buffer
+   waiting to be handled, and MIDI output may not be generated
+   with accurate timing. Using the latency parameter when 
+   opening a MIDI output port allows the caller to defer timing
+   to PortMidi, which in most implementations will pass the
+   data on to the OS. By passing timestamps and data to the
+   OS kernel, device driver, or even hardware, there are fewer
+   sources of latency that can affect the ultimate timing of
+   the data. On the other hand, the application must generate
+   and deliver the data ahead of the timestamp. The amount by 
+   which data is computed early must be at least as large as
+   the worst-case latency to avoid timing problems.
+
+   Latency is even more important in audio applications. If an
+   application lets an audio output buffer underflow, an audible
+   pop or click is produced. Audio input buffers can overflow,
+   causing data to be lost. In general the audio buffers must
+   be large enough to buffer the worst-case latency that the
+   application will encounter.
+
+   This program measures latency by recording the difference
+   between the scheduled callback time and the current real time.
+   We do not really know the scheduled callback time, so we will
+   record the differences between the real time of each callback
+   and the real time of the previous callback. Differences that
+   are larger than the scheduled difference are recorded. Smaller
+   differences indicate the system is recovering from an earlier
+   latency, so these are ignored.
+   Since printing by the callback process can cause all sorts of
+   delays, this program records latency observations in a
+   histogram. When the program is stopped, the histogram is
+   printed to the console.
+
+   Optionally the system can be tested under a load of MIDI input,
+   MIDI output, or both.  If MIDI input is selected, the callback
+   thread will read any waiting MIDI events each iteration.  You
+   must generate events on this interface for the test to actually
+   put any appreciable load on PortMidi.  If MIDI output is
+   selected, alternating note on and note off events are sent each
+   X iterations, where you specify X.  For example, with a timer
+   callback period of 2ms and X=1, a MIDI event is sent every 2ms.
+
+
+   INTERPRETING RESULTS: Time is quantized to 1ms, so there is
+   some uncertainty due to rounding. A microsecond latency that
+   spans the time when the clock is incremented will be reported
+   as a latency of 1. On the other hand, a latency of almost
+   1ms that falls between two clock ticks will be reported as 
+   zero. In general, if the highest nonzero bin is numbered N,
+   then the maximum latency is N+1.
+
+CHANGE LOG
+
+18-Jul-03 Mark Nelson -- Added code to generate MIDI or receive
+            MIDI during test, and made period user-settable.
+ */
+
+#define HIST_LEN 21 /* how many 1ms bins in the histogram */
+
+#define STRING_MAX 80 /* used for console input */
+
+#define INPUT_BUFFER_SIZE 100
+#define OUTPUT_BUFFER_SIZE 0
+
+#ifndef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef min
+#define min(a, b) ((a) <= (b) ? (a) : (b))
+#endif
+
+int get_number(char *prompt);
+
+PtTimestamp previous_callback_time = 0;
+
+int period;            /* milliseconds per callback */
+
+int histogram[HIST_LEN];
+int max_latency = 0;  /* worst latency observed */
+int out_of_range = 0; /* how many points outside of HIST_LEN? */
+
+int test_in, test_out; /* test MIDI in and/or out? */
+int output_period;     /* output MIDI every __ iterations if test_out true */
+int iteration = 0;
+PmStream *in, *out;
+int note_on = 0;       /* is the note currently on? */
+
+/* callback function for PortTime -- computes histogram */
+void pt_callback(PtTimestamp timestamp, void *userData)
+{
+    PtTimestamp difference = timestamp - previous_callback_time - period;
+    previous_callback_time = timestamp;
+
+    /* allow 5 seconds for the system to settle down */
+    if (timestamp < 5000) return;
+
+    iteration++;
+    /* send a note on/off if user requested it */
+    if (test_out && (iteration % output_period == 0)) {
+        PmEvent buffer[1];
+        buffer[0].timestamp = Pt_Time(NULL);
+        if (note_on) {
+            /* note off */
+            buffer[0].message = Pm_Message(0x90, 60, 0);
+            note_on = 0;
+        } else {
+            /* note on */
+            buffer[0].message = Pm_Message(0x90, 60, 100);
+            note_on = 1;
+        }
+        Pm_Write(out, buffer, 1);
+        iteration = 0;
+    }
+
+    /* read all waiting events (if user requested) */
+    if (test_in) {
+       PmError status;
+       PmEvent buffer[1];
+       do {
+          status = Pm_Poll(in);
+          if (status == TRUE) {
+              Pm_Read(in,buffer,1);
+          }
+       } while (status == TRUE);
+    }
+
+    if (difference < 0) return; /* ignore when system is "catching up" */
+
+    /* update the histogram */
+    if (difference < HIST_LEN) {
+        histogram[difference]++;
+    } else {
+        out_of_range++;
+    }
+
+    if (max_latency < difference) max_latency = difference;
+}
+
+
+int main()
+{
+    char line[STRING_MAX];
+    int i;
+    int len;
+    int choice;
+    PtTimestamp stop;
+    printf("Latency histogram.\n");
+    period = 0;
+    while (period < 1) {
+        period = get_number("Choose timer period (in ms, >= 1): ");
+    }
+    printf("Benchmark with:\n\t%s\n\t%s\n\t%s\n\t%s\n",
+           "1. No MIDI traffic",
+           "2. MIDI input",
+           "3. MIDI output",
+           "4. MIDI input and output");
+    choice = get_number("? ");
+    switch (choice) {
+      case 1: test_in = 0; test_out = 0; break;
+      case 2: test_in = 1; test_out = 0; break;
+      case 3: test_in = 0; test_out = 1; break;
+      case 4: test_in = 1; test_out = 1; break;
+      default: assert(0);
+    }
+    if (test_in || test_out) {
+        /* list device information */
+        for (i = 0; i < Pm_CountDevices(); i++) {
+            const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+            if ((test_in && info->input) ||
+                (test_out && info->output)) {
+                printf("%d: %s, %s", i, info->interf, info->name);
+                if (info->input) printf(" (input)");
+                if (info->output) printf(" (output)");
+                printf("\n");
+            }
+        }
+        /* open stream(s) */
+        if (test_in) {
+            int i = get_number("MIDI input device number: ");
+            Pm_OpenInput(&in, 
+                  i,
+                  NULL, 
+                  INPUT_BUFFER_SIZE, 
+                  (PmTimestamp (*)(void *)) Pt_Time, 
+                  NULL);
+            /* turn on filtering; otherwise, input might overflow in the 
+               5-second period before timer callback starts reading midi */
+            Pm_SetFilter(in, PM_FILT_ACTIVE | PM_FILT_CLOCK);
+        }
+        if (test_out) {
+            int i = get_number("MIDI output device number: ");
+            PmEvent buffer[1];
+            Pm_OpenOutput(&out, 
+                  i,
+                  NULL,
+                  OUTPUT_BUFFER_SIZE,
+                  (PmTimestamp (*)(void *)) Pt_Time,
+                  NULL, 
+                  0); /* no latency scheduling */
+
+            /* send a program change to force a status byte -- this fixes
+               a problem with a buggy linux MidiSport driver, and shouldn't
+               hurt anything else
+             */
+            buffer[0].timestamp = 0;
+            buffer[0].message = Pm_Message(0xC0, 0, 0); /* program change */
+            Pm_Write(out, buffer, 1);
+
+            output_period = get_number(
+                "MIDI out should be sent every __ callback iterations: ");
+
+            assert(output_period >= 1);
+        }
+    }
+
+    printf("%s%s", "Latency measurements will start in 5 seconds. ",
+                   "Type return to stop: ");
+    Pt_Start(period, &pt_callback, 0);
+    fgets(line, STRING_MAX, stdin);
+    stop = Pt_Time();
+    Pt_Stop();
+
+    /* courteously turn off the last note, if necessary */
+    if (note_on) {
+       PmEvent buffer[1];
+       buffer[0].timestamp = Pt_Time(NULL);
+       buffer[0].message = Pm_Message(0x90, 60, 0);
+       Pm_Write(out, buffer, 1);
+    }
+
+    /* print the histogram */
+    printf("Duration of test: %g seconds\n\n", max(0, stop - 5000) * 0.001);
+    printf("Latency(ms)  Number of occurrences\n");
+    /* avoid printing beyond last non-zero histogram entry */
+    len = min(HIST_LEN, max_latency + 1);
+    for (i = 0; i < len; i++) {
+        printf("%2d      %10d\n", i, histogram[i]);
+    }
+    printf("Number of points greater than %dms: %d\n", 
+           HIST_LEN - 1, out_of_range);
+    printf("Maximum latency: %d milliseconds\n", max_latency);
+    printf("\nNote that due to rounding, actual latency can be 1ms higher\n");
+    printf("than the numbers reported here.\n");
+    printf("Type return to exit...");
+    fgets(line, STRING_MAX, stdin);
+
+	if(choice == 2)
+		Pm_Close(in);
+	else if(choice == 3)
+		Pm_Close(out);
+	else if(choice == 4)
+	{
+		Pm_Close(in);
+		Pm_Close(out);
+	}
+    return 0;
+}
+
+
+/* read a number from console */
+int get_number(char *prompt)
+{
+    char line[STRING_MAX];
+    int n = 0, i;
+    printf(prompt);
+    while (n != 1) {
+        n = scanf("%d", &i);
+        fgets(line, STRING_MAX, stdin);
+
+    }
+    return i;
+}
diff --git a/pd/portmidi/pm_test/latency.vcproj b/pd/portmidi/pm_test/latency.vcproj
new file mode 100755
index 0000000000000000000000000000000000000000..afefed735f767b54ae0696151c1bc810c95de782
--- /dev/null
+++ b/pd/portmidi/pm_test/latency.vcproj
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="latency"
+	ProjectGUID="{41D78CBF-B04B-4561-BA4A-AC238C40633D}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="latency.dir\Debug"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				BasicRuntimeChecks="3"
+				CompileAs="1"
+				DebugInformationFormat="3"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="0"
+				Optimization="0"
+				RuntimeLibrary="1"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Debug/latency.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Debug\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Debug\latency.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Debug/latency.pdb"
+				GenerateDebugInformation="TRUE"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Debug\latency.lib"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="latency.dir\Release"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				CompileAs="1"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="2"
+				Optimization="2"
+				RuntimeLibrary="0"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Release/latency.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Release\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Release\latency.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Release/latency.pdb"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Release\latency.lib"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="">
+			<File
+				RelativePath="..\pm_test\latency.c">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_test/midiclock.c b/pd/portmidi/pm_test/midiclock.c
new file mode 100644
index 0000000000000000000000000000000000000000..60fcf7a9aaddf7b396f5e6fa0c2ee2f86fbe9a6e
--- /dev/null
+++ b/pd/portmidi/pm_test/midiclock.c
@@ -0,0 +1,287 @@
+/* miditime.c -- a test program that sends midi clock and MTC */
+
+#include "portmidi.h"
+#include "porttime.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+#ifndef false
+#define false 0
+#define true 1
+#endif
+
+#define private static
+typedef int boolean;
+
+#define MIDI_TIME_CLOCK 0xf8
+#define MIDI_START      0xfa
+#define MIDI_CONTINUE	0xfb
+#define MIDI_STOP       0xfc
+#define MIDI_Q_FRAME	0xf1
+
+#define OUTPUT_BUFFER_SIZE 0
+#define DRIVER_INFO NULL
+#define TIME_PROC ((int32_t (*)(void *)) Pt_Time)
+#define TIME_INFO NULL
+#define LATENCY 0
+#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
+
+#define STRING_MAX 80 /* used for console input */
+
+/* to determine ms per clock:
+ *    time per beat in seconds =  60 / tempo
+ *    multiply by 1000 to get time per beat in ms: 60000 / tempo
+ *    divide by 24 CLOCKs per beat: (60000/24) / tempo
+ *    simplify: 2500 / tempo
+ */
+#define TEMPO_TO_CLOCK 2500.0
+
+boolean done = false;
+PmStream *midi;
+/* shared flags to control callback output generation: */
+boolean clock_running = false;
+boolean send_start_stop = false;
+boolean time_code_running = false;
+boolean active = false; /* tells callback to do its thing */
+float tempo = 60.0F;
+/* protocol for handing off portmidi to callback thread:
+    main owns portmidi
+    main sets active = true: ownership transfers to callback
+    main sets active = false: main requests ownership
+    callback sees active == false, yields ownership back to main
+    main waits 2ms to make sure callback has a chance to yield
+       (stop making PortMidi calls), then assumes it can close
+       PortMidi
+ */
+
+/* timer_poll -- the timer callback function */
+/*
+ * All MIDI sends take place here
+ */
+void timer_poll(PtTimestamp timestamp, void *userData)
+{
+    static int callback_owns_portmidi = false;
+    static PmTimestamp clock_start_time = 0;
+    static double next_clock_time = 0;
+    /* SMPTE time */
+    static int frames = 0;
+    static int seconds = 0;
+    static int minutes = 0;
+    static int hours = 0;
+    static int mtc_count = 0; /* where are we in quarter frame sequence? */
+    static int smpte_start_time = 0;
+    static double next_smpte_time = 0;
+    #define QUARTER_FRAME_PERIOD (1.0 / 120.0) /* 30fps, 1/4 frame */
+
+    if (callback_owns_portmidi && !active) {
+        /* main is requesting (by setting active to false) that we shut down */
+        callback_owns_portmidi = false;
+        return;
+    }
+    if (!active) return; /* main still getting ready or it's closing down */
+    callback_owns_portmidi = true; /* main is ready, we have portmidi */
+    if (send_start_stop) {
+        if (clock_running) {
+            Pm_WriteShort(midi, 0, MIDI_STOP);
+        } else {
+            Pm_WriteShort(midi, 0, MIDI_START);
+            clock_start_time = timestamp;
+            next_clock_time = TEMPO_TO_CLOCK / tempo;
+        }
+        clock_running = !clock_running;
+        send_start_stop = false; /* until main sets it again */
+        /* note that there's a slight race condition here: main could
+           set send_start_stop asynchronously, but we assume user is 
+           typing slower than the clock rate */
+    }
+    if (clock_running) {
+        if ((timestamp - clock_start_time) > next_clock_time) {
+            Pm_WriteShort(midi, 0, MIDI_TIME_CLOCK);
+            next_clock_time += TEMPO_TO_CLOCK / tempo;
+        }
+    }
+    if (time_code_running) {
+        int data = 0; // initialization avoids compiler warning
+        if ((timestamp - smpte_start_time) < next_smpte_time) 
+            return;
+        switch (mtc_count) {
+        case 0: /* frames low nibble */
+            data = frames;
+            break;
+        case 1: /* frames high nibble */
+            data = frames >> 4;
+            break;
+        case 2: /* frames seconds low nibble */
+            data = seconds;
+            break;
+        case 3: /* frames seconds high nibble */
+            data = seconds >> 4;
+            break;
+        case 4: /* frames minutes low nibble */
+            data = minutes;
+            break;
+        case 5: /* frames minutes high nibble */
+            data = minutes >> 4;
+            break;
+        case 6: /* hours low nibble */
+            data = hours;
+            break;
+        case 7: /* hours high nibble */
+            data = hours >> 4;
+            break;
+        }
+        data &= 0xF; /* take only 4 bits */
+        Pm_WriteShort(midi, 0, 
+                      Pm_Message(MIDI_Q_FRAME, (mtc_count << 4) + data, 0));
+        mtc_count = (mtc_count + 1) & 7; /* wrap around */
+        if (mtc_count == 0) { /* update time by two frames */
+            frames += 2;
+            if (frames >= 30) {
+                frames = 0;
+                seconds++;
+                if (seconds >= 60) {
+                    seconds = 0;
+                    minutes++;
+                    if (minutes >= 60) {
+                        minutes = 0;
+                        hours++;
+                        /* just let hours wrap if it gets that far */
+                    }
+                }
+            }
+        }
+        next_smpte_time += QUARTER_FRAME_PERIOD;
+    } else { /* time_code_running is false */
+        smpte_start_time = timestamp;
+        /* so that when it finally starts, we'll be in sync */
+    }
+}
+
+
+/* read a number from console */
+/**/
+int get_number(char *prompt)
+{
+    char line[STRING_MAX];
+    int n = 0, i;
+    printf(prompt);
+    while (n != 1) {
+        n = scanf("%d", &i);
+        fgets(line, STRING_MAX, stdin);
+
+    }
+    return i;
+}
+
+/****************************************************************************
+*               showhelp
+* Effect: print help text
+****************************************************************************/
+
+private void showhelp()
+{
+    printf("\n");
+    printf("t toggles sending MIDI Time Code (MTC)\n");
+    printf("c toggles sending MIDI CLOCK (initially on)\n");
+    printf("m to set tempo (from 1bpm to 300bpm)\n");
+    printf("q quits\n");
+    printf("\n");
+}
+
+/****************************************************************************
+*               doascii
+* Inputs:
+*    char c: input character
+* Effect: interpret to control output
+****************************************************************************/
+
+private void doascii(char c)
+{
+    if (isupper(c)) c = tolower(c);
+    if (c == 'q') done = true;
+    else if (c == 'c') {
+        printf("%s MIDI CLOCKs\n", (clock_running ? "Stopping" : "Starting"));
+        send_start_stop = true;
+    } else if (c == 't') {
+        printf("%s MIDI Time Code\n", 
+               (time_code_running ? "Stopping" : "Starting"));
+        time_code_running = !time_code_running;
+    } else if (c == 'm') {
+        int input_tempo = get_number("Enter new tempo (bpm): ");
+        if (input_tempo >= 1 && input_tempo <= 300) {
+            printf("Changing tempo to %d\n", input_tempo);
+            tempo = (float) input_tempo;
+        } else {
+            printf("Tempo range is 1 to 300, current tempo is %g bpm\n", 
+                   tempo);
+        }
+    } else {
+        showhelp();
+    }
+}
+
+
+/* main - prompt for parameters, start processing */
+/*
+ * Prompt user to type return.
+ * Then send START and MIDI CLOCK for 60 beats/min.
+ * Commands:
+ *     t - toggle sending MIDI Time Code (MTC)
+ *     c - toggle sending MIDI CLOCK
+ *     m - set tempo
+ *     q - quit
+ */
+int main(int argc, char **argv)
+{
+    char s[STRING_MAX]; /* console input */
+    int outp;
+    PmError err;
+    int i;
+    if (argc > 1) { 
+        printf("Warning: command line arguments ignored\n");
+    }
+    showhelp();
+    /* use porttime callback to send midi */
+    Pt_Start(1, timer_poll, 0);
+    /* list device information */
+    printf("MIDI output devices:\n");
+    for (i = 0; i < Pm_CountDevices(); i++) {
+        const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+        if (info->output) printf("%d: %s, %s\n", i, info->interf, info->name);
+    }
+    outp = get_number("Type output device number: ");
+    err = Pm_OpenOutput(&midi, outp, DRIVER_INFO, OUTPUT_BUFFER_SIZE, 
+                        TIME_PROC, TIME_INFO, LATENCY);
+    if (err) {
+        printf(Pm_GetErrorText(err));
+        goto error_exit_no_device;
+    }
+    active = true;
+
+    printf("Type RETURN to start MIDI CLOCK:\n");
+    if (!fgets(s, STRING_MAX, stdin)) goto error_exit;
+    send_start_stop = true; /* send START and then CLOCKs */
+
+    while (!done) {
+        if (fgets(s, STRING_MAX, stdin)) {
+            doascii(s[0]);
+        }
+    }
+
+ error_exit:
+    active = false;
+    Pt_Sleep(2); /* this is to allow callback to complete -- it's
+                    real time, so it's either ok and it runs on
+                    time, or there's no point to synchronizing
+                    with it */
+    /* now we "own" portmidi again */
+    Pm_Close(midi);
+ error_exit_no_device:
+    Pt_Stop();
+    Pm_Terminate();
+    exit(0);
+}
+
diff --git a/pd/portmidi/pm_test/midiclock.vcproj b/pd/portmidi/pm_test/midiclock.vcproj
new file mode 100644
index 0000000000000000000000000000000000000000..b66e302305259f8c35e085023a79eee3e3d4c709
--- /dev/null
+++ b/pd/portmidi/pm_test/midiclock.vcproj
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="midiclock"
+	ProjectGUID="{9B448D22-EC7E-4BD8-A552-B268D843CC3C}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="midiclock.dir\Debug"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				BasicRuntimeChecks="3"
+				CompileAs="1"
+				DebugInformationFormat="3"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="0"
+				Optimization="0"
+				RuntimeLibrary="1"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Debug/midiclock.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Debug\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Debug\midiclock.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Debug/midiclock.pdb"
+				GenerateDebugInformation="TRUE"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Debug\midiclock.lib"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="midiclock.dir\Release"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				CompileAs="1"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="2"
+				Optimization="2"
+				RuntimeLibrary="0"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Release/midiclock.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Release\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Release\midiclock.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Release/midiclock.pdb"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Release\midiclock.lib"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="">
+			<File
+				RelativePath="..\pm_test\midiclock.c">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_test/midithread.c b/pd/portmidi/pm_test/midithread.c
new file mode 100755
index 0000000000000000000000000000000000000000..fab9794f2daececf1ba1a17db1ff81ba0233fdde
--- /dev/null
+++ b/pd/portmidi/pm_test/midithread.c
@@ -0,0 +1,329 @@
+/* midithread.c -- example program showing how to do midi processing 
+                   in a preemptive thread
+
+  Notes: if you handle midi I/O from your main program, there will be
+  some delay before handling midi messages whenever the program is
+  doing something like file I/O, graphical interface updates, etc.
+
+  To handle midi with minimal delay, you should do all midi processing
+  in a separate, high priority thread. A convenient way to get a high
+  priority thread in windows is to use the timer callback provided by
+  the PortTime library. That is what we show here.
+
+  If the high priority thread writes to a file, prints to the console,
+  or does just about anything other than midi processing, this may 
+  create delays, so all this processing should be off-loaded to the
+  "main" process or thread. Communication between threads can be tricky.
+  If one thread is writing at the same time the other is reading, very
+  tricky race conditions can arise, causing programs to behave
+  incorrectly, but only under certain timing conditions -- a terrible
+  thing to debug. Advanced programmers know this as a synchronization
+  problem. See any operating systems textbook for the complete story.
+
+  To avoid synchronization problems, a simple, reliable approach is
+  to communicate via messages. PortMidi offers a message queue as a
+  datatype, and operations to insert and remove messages. Use two 
+  queues as follows: midi_to_main transfers messages from the midi
+  thread to the main thread, and main_to_midi transfers messages from
+  the main thread to the midi thread. Queues are safe for use between
+  threads as long as ONE thread writes and ONE thread reads. You must 
+  NEVER allow two threads to write to the same queue.
+
+  This program transposes incoming midi data by an amount controlled
+  by the main program. To change the transposition, type an integer
+  followed by return. The main program sends this via a message queue
+  to the midi thread. To quit, type 'q' followed by return.
+
+  The midi thread can also send a pitch to the main program on request.
+  Type 'm' followed by return to wait for the next midi message and
+  print the pitch.
+
+  This program illustrates:
+    Midi processing in a high-priority thread.
+    Communication with a main process via message queues.
+
+ */
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "assert.h"
+#include "portmidi.h"
+#include "pmutil.h"
+#include "porttime.h"
+
+/* if INPUT_BUFFER_SIZE is 0, PortMidi uses a default value */
+#define INPUT_BUFFER_SIZE 0
+
+#define OUTPUT_BUFFER_SIZE 100
+#define DRIVER_INFO NULL
+#define TIME_PROC NULL
+#define TIME_INFO NULL
+/* use zero latency because we want output to be immediate */
+#define LATENCY 0
+
+#define STRING_MAX 80
+
+/**********************************/
+/* DATA USED ONLY BY process_midi */
+/* (except during initialization) */
+/**********************************/
+
+int active = FALSE;
+int monitor = FALSE;
+int midi_thru = TRUE;
+
+int transpose;
+PmStream *midi_in;
+PmStream *midi_out;
+
+/****************************/
+/* END OF process_midi DATA */
+/****************************/
+
+/* shared queues */
+PmQueue *midi_to_main;
+PmQueue *main_to_midi;
+
+#define QUIT_MSG 1000
+#define MONITOR_MSG 1001
+#define THRU_MSG 1002
+
+/* timer interrupt for processing midi data */
+void process_midi(PtTimestamp timestamp, void *userData)
+{
+    PmError result;
+    PmEvent buffer; /* just one message at a time */
+    int32_t msg;
+
+    /* do nothing until initialization completes */
+    if (!active) 
+        return;
+
+    /* check for messages */
+    do { 
+        result = Pm_Dequeue(main_to_midi, &msg); 
+        if (result) {
+            if (msg >= -127 && msg <= 127) 
+                transpose = msg;
+            else if (msg == QUIT_MSG) {
+                /* acknowledge receipt of quit message */
+                Pm_Enqueue(midi_to_main, &msg);
+                active = FALSE;
+                return;
+            } else if (msg == MONITOR_MSG) {
+                /* main has requested a pitch. monitor is a flag that
+                 * records the request:
+                 */
+                monitor = TRUE;
+            } else if (msg == THRU_MSG) {
+                /* toggle Thru on or off */
+                midi_thru = !midi_thru;
+            }
+        }
+    } while (result);         
+    
+    /* see if there is any midi input to process */
+    do {
+		result = Pm_Poll(midi_in);
+        if (result) {
+            int status, data1, data2;
+            if (Pm_Read(midi_in, &buffer, 1) == pmBufferOverflow) 
+                continue;
+            if (midi_thru) 
+                Pm_Write(midi_out, &buffer, 1);
+            /* unless there was overflow, we should have a message now */
+            status = Pm_MessageStatus(buffer.message);
+            data1 = Pm_MessageData1(buffer.message);
+            data2 = Pm_MessageData2(buffer.message);
+            if ((status & 0xF0) == 0x90 ||
+                (status & 0xF0) == 0x80) {
+                
+                /* this is a note-on or note-off, so transpose and send */
+                data1 += transpose;
+                
+                /* keep within midi pitch range, keep proper pitch class */
+                while (data1 > 127) 
+                    data1 -= 12;
+                while (data1 < 0) 
+                    data1 += 12;
+                
+                /* send the message */
+                buffer.message = Pm_Message(status, data1, data2);
+                Pm_Write(midi_out, &buffer, 1);
+                
+                /* if monitor is set, send the pitch to the main thread */
+                if (monitor) {
+                    Pm_Enqueue(midi_to_main, &data1);
+                    monitor = FALSE; /* only send one pitch per request */
+                }
+            }
+        }
+    } while (result);
+}
+
+void exit_with_message(char *msg)
+{
+    char line[STRING_MAX];
+    printf("%s\n", msg);
+    fgets(line, STRING_MAX, stdin);
+    exit(1);
+}
+
+int main()
+{
+    int id;
+    int32_t n;
+    const PmDeviceInfo *info;
+    char line[STRING_MAX];
+    int spin;
+    int done = FALSE;
+
+    /* determine what type of test to run */
+    printf("begin PortMidi multithread test...\n");
+	
+    /* note that it is safe to call PortMidi from the main thread for
+       initialization and opening devices. You should not make any
+       calls to PortMidi from this thread once the midi thread begins.
+       to make PortMidi calls.
+     */
+
+    /* make the message queues */
+    /* messages can be of any size and any type, but all messages in
+     * a given queue must have the same size. We'll just use int32_t's
+     * for our messages in this simple example
+     */
+    midi_to_main = Pm_QueueCreate(32, sizeof(int32_t));
+    assert(midi_to_main != NULL);
+    main_to_midi = Pm_QueueCreate(32, sizeof(int32_t));
+    assert(main_to_midi != NULL);
+
+    /* a little test of enqueue and dequeue operations. Ordinarily, 
+     * you would call Pm_Enqueue from one thread and Pm_Dequeue from
+     * the other. Since the midi thread is not running, this is safe.
+     */
+    n = 1234567890;
+    Pm_Enqueue(midi_to_main, &n);
+    n = 987654321;
+    Pm_Enqueue(midi_to_main, &n);
+	Pm_Dequeue(midi_to_main, &n);
+	if (n != 1234567890) {
+        exit_with_message("Pm_Dequeue produced unexpected result.");
+    }
+    Pm_Dequeue(midi_to_main, &n);
+	if(n != 987654321) {
+        exit_with_message("Pm_Dequeue produced unexpected result.");
+    }
+
+    /* always start the timer before you start midi */
+    Pt_Start(1, &process_midi, 0); /* start a timer with millisecond accuracy */
+    /* the timer will call our function, process_midi() every millisecond */
+    
+	Pm_Initialize();
+
+    id = Pm_GetDefaultOutputDeviceID();
+    info = Pm_GetDeviceInfo(id);
+    if (info == NULL) {
+        printf("Could not open default output device (%d).", id);
+        exit_with_message("");
+    }
+    printf("Opening output device %s %s\n", info->interf, info->name);
+
+    /* use zero latency because we want output to be immediate */
+    Pm_OpenOutput(&midi_out, 
+                  id, 
+                  DRIVER_INFO,
+                  OUTPUT_BUFFER_SIZE,
+                  TIME_PROC,
+                  TIME_INFO,
+                  LATENCY);
+
+    id = Pm_GetDefaultInputDeviceID();
+    info = Pm_GetDeviceInfo(id);
+    if (info == NULL) {
+        printf("Could not open default input device (%d).", id);
+        exit_with_message("");
+    }
+    printf("Opening input device %s %s\n", info->interf, info->name);
+    Pm_OpenInput(&midi_in, 
+                 id, 
+                 DRIVER_INFO,
+                 INPUT_BUFFER_SIZE,
+                 TIME_PROC,
+                 TIME_INFO);
+
+    active = TRUE; /* enable processing in the midi thread -- yes, this
+                      is a shared variable without synchronization, but
+                      this simple assignment is safe */
+
+    printf("Enter midi input; it will be transformed as specified by...\n");
+    printf("%s\n%s\n%s\n",
+           "Type 'q' to quit, 'm' to monitor next pitch, t to toggle thru or",
+           "type a number to specify transposition.",
+		   "Must terminate with [ENTER]");
+
+    while (!done) {
+        int32_t msg;
+        int input;
+        int len;
+        fgets(line, STRING_MAX, stdin);
+        /* remove the newline: */
+        len = strlen(line);
+        if (len > 0) line[len - 1] = 0; /* overwrite the newline char */
+        if (strcmp(line, "q") == 0) {
+            msg = QUIT_MSG;
+            Pm_Enqueue(main_to_midi, &msg);
+            /* wait for acknowlegement */
+            do {
+                spin = Pm_Dequeue(midi_to_main, &msg);
+            } while (spin == 0); /* spin */ ;
+            done = TRUE; /* leave the command loop and wrap up */
+        } else if (strcmp(line, "m") == 0) {
+            msg = MONITOR_MSG;
+            Pm_Enqueue(main_to_midi, &msg);
+            printf("Waiting for note...\n");
+            do {
+                spin = Pm_Dequeue(midi_to_main, &msg);
+            } while (spin == 0); /* spin */ ;
+            // convert int32_t to long for safe printing
+            printf("... pitch is %ld\n", (long) msg);
+        } else if (strcmp(line, "t") == 0) {
+            /* reading midi_thru asynchronously could give incorrect results,
+               e.g. if you type "t" twice before the midi thread responds to
+               the first one, but we'll do it this way anyway. Perhaps a more
+               correct way would be to wait for an acknowledgement message
+               containing the new state. */
+            printf("Setting THRU %s\n", (midi_thru ? "off" : "on"));
+            msg = THRU_MSG;
+            Pm_Enqueue(main_to_midi, &msg);
+        } else if (sscanf(line, "%d", &input) == 1) {
+            if (input >= -127 && input <= 127) {
+                /* send transposition value, make sur */
+                printf("Transposing by %d\n", input);
+                msg = (int32_t) input;
+                Pm_Enqueue(main_to_midi, &msg);
+            } else {
+                printf("Transposition must be within -127...127\n");
+            }
+        } else {
+            printf("%s\n%s\n",
+              "Type 'q[ENTER]' to quit, 'm[ENTER]' to monitor next pitch, or",
+              "enter a number to specify transposition.");
+        }
+    }
+
+    /* at this point, midi thread is inactive and we need to shut down
+     * the midi input and output
+     */
+    Pt_Stop(); /* stop the timer */
+    Pm_QueueDestroy(midi_to_main);
+    Pm_QueueDestroy(main_to_midi);
+
+    /* Belinda! if close fails here, some memory is deleted, right??? */
+    Pm_Close(midi_in);
+    Pm_Close(midi_out);
+    
+    printf("finished portMidi multithread test...enter any character to quit [RETURN]...");
+    fgets(line, STRING_MAX, stdin);
+    return 0;
+}
diff --git a/pd/portmidi/pm_test/midithread.vcproj b/pd/portmidi/pm_test/midithread.vcproj
new file mode 100755
index 0000000000000000000000000000000000000000..b09d8a8585f53188187bd8b13037887228e59da0
--- /dev/null
+++ b/pd/portmidi/pm_test/midithread.vcproj
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="midithread"
+	ProjectGUID="{EED7440D-04E3-4948-92DB-C85B4ADB1D82}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="midithread.dir\Debug"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				BasicRuntimeChecks="3"
+				CompileAs="1"
+				DebugInformationFormat="3"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="0"
+				Optimization="0"
+				RuntimeLibrary="1"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Debug/midithread.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Debug\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Debug\midithread.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Debug/midithread.pdb"
+				GenerateDebugInformation="TRUE"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Debug\midithread.lib"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="midithread.dir\Release"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				CompileAs="1"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="2"
+				Optimization="2"
+				RuntimeLibrary="0"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Release/midithread.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Release\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Release\midithread.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Release/midithread.pdb"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Release\midithread.lib"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="">
+			<File
+				RelativePath="..\pm_test\midithread.c">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_test/midithru.c b/pd/portmidi/pm_test/midithru.c
new file mode 100755
index 0000000000000000000000000000000000000000..41d350a4334b2296b3f9e0fafeba6918a89fa60e
--- /dev/null
+++ b/pd/portmidi/pm_test/midithru.c
@@ -0,0 +1,366 @@
+/* midithru.c -- example program implementing background thru processing */
+
+/* suppose you want low-latency midi-thru processing, but your application
+   wants to take advantage of the input buffer and timestamped data so that
+   it does not have to operate with very low latency.
+
+   This program illustrates how to use a timer callback from PortTime to 
+   implement a low-latency process that handles midi thru, including correctly
+   merging midi data from the application with midi data from the input port.
+
+   The main application, which runs in the main program thread, will use an
+   interface similar to that of PortMidi, but since PortMidi does not allow
+   concurrent threads to share access to a stream, the application will
+   call private methods that transfer MIDI messages to and from the timer 
+   thread. All PortMidi API calls are made from the timer thread.
+ */
+
+/* DESIGN
+
+All setup will be done by the main thread. Then, all direct access to 
+PortMidi will be handed off to the timer callback thread.
+
+After this hand-off, the main thread will get/send messages via a queue.
+
+The goal is to send incoming messages to the midi output while merging
+any midi data generated by the application. Sysex is a problem here
+because you cannot insert (merge) a midi message while a sysex is in
+progress. There are at least three ways to implement midi thru with 
+sysex messages:
+
+1) Turn them off. If your application does not need them, turn them off
+   with Pm_SetFilter(midi_in, PM_FILT_ACTIVE | PM_FILT_SYSEX). You will
+   not receive sysex (or active sensing messages), so you will not have 
+   to handle them.
+
+2) Make them atomic. As you receive sysex messages, copy the data into
+   a (big) buffer. Ideally, expand the buffer as needed -- sysex messages
+   do not have any maximum length. Even more ideally, use a list structure
+   and real-time memory allocation to avoid latency in the timer thread.
+   When a full sysex message is received, send it to the midi output all
+   at once.
+
+3) Process sysex incrementally. Send sysex data to midi output as it
+   arrives. Block any non-real-time messages from the application until
+   the sysex message completes. There is the risk that an incomplete
+   sysex message will block messages forever, so implement a 5-second
+   timeout: if no sysex data is seen for 5 seconds, release the block,
+   possibly losing the rest of the sysex message. 
+
+   Application messages must be processed similarly: once started, a
+   sysex message will block MIDI THRU processing. We will assume that
+   the application will not abort a sysex message, so timeouts are not
+   necessary here.
+
+This code implements (3).
+
+Latency is also an issue. PortMidi requires timestamps to be in 
+non-decreasing order. Since we'll be operating with a low-latency
+timer thread, we can just set the latency to zero meaning timestamps
+are ignored by PortMidi. This will allow thru to go through with
+minimal latency. The application, however, needs to use timestamps
+because we assume it is high latency (the whole purpose of this
+example is to illustrate how to get low-latency thru with a high-latency
+application.) So the callback thread will implement midi timing by
+observing timestamps. The current timestamp will be available in the
+global variable current_timestamp.
+
+*/
+
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "assert.h"
+#include "portmidi.h"
+#include "pmutil.h"
+#include "porttime.h"
+
+#define MIDI_SYSEX 0xf0
+#define MIDI_EOX 0xf7
+
+/* active is set true when midi processing should start */
+int active = FALSE;
+/* process_midi_exit_flag is set when the timer thread shuts down */
+int process_midi_exit_flag;
+
+PmStream *midi_in;
+PmStream *midi_out;
+
+/* shared queues */
+#define IN_QUEUE_SIZE 1024
+#define OUT_QUEUE_SIZE 1024
+PmQueue *in_queue;
+PmQueue *out_queue;
+PmTimestamp current_timestamp = 0;
+int thru_sysex_in_progress = FALSE;
+int app_sysex_in_progress = FALSE;
+PmTimestamp last_timestamp = 0;
+
+
+/* time proc parameter for Pm_MidiOpen */
+PmTimestamp midithru_time_proc(void *info)
+{
+    return current_timestamp;
+}
+
+
+/* timer interrupt for processing midi data.
+   Incoming data is delivered to main program via in_queue.
+   Outgoing data from main program is delivered via out_queue.
+   Incoming data from midi_in is copied with low latency to  midi_out.
+   Sysex messages from either source block messages from the other.
+ */
+void process_midi(PtTimestamp timestamp, void *userData)
+{
+    PmError result;
+    PmEvent buffer; /* just one message at a time */
+
+    current_timestamp++; /* update every millisecond */
+    /* if (current_timestamp % 1000 == 0) 
+        printf("time %d\n", current_timestamp); */
+
+    /* do nothing until initialization completes */
+    if (!active) {
+        /* this flag signals that no more midi processing will be done */
+        process_midi_exit_flag = TRUE;
+        return;
+    }
+
+    /* see if there is any midi input to process */
+    if (!app_sysex_in_progress) {
+        do {
+            result = Pm_Poll(midi_in);
+            if (result) {
+                int status;
+                PmError rslt = Pm_Read(midi_in, &buffer, 1);
+                if (rslt == pmBufferOverflow) 
+                    continue;
+                assert(rslt == 1);
+
+                /* record timestamp of most recent data */
+                last_timestamp = current_timestamp;
+
+                /* the data might be the end of a sysex message that
+                   has timed out, in which case we must ignore it.
+                   It's a continuation of a sysex message if status
+                   is actually a data byte (high-order bit is zero). */
+                status = Pm_MessageStatus(buffer.message);
+                if (((status & 0x80) == 0) && !thru_sysex_in_progress) {
+                    continue; /* ignore this data */
+                }
+
+                /* implement midi thru */
+                /* note that you could output to multiple ports or do other
+                   processing here if you wanted
+                 */
+                /* printf("thru: %x\n", buffer.message); */
+                Pm_Write(midi_out, &buffer, 1);
+
+                /* send the message to the application */
+                /* you might want to filter clock or active sense messages here
+                   to avoid sending a bunch of junk to the application even if
+                   you want to send it to MIDI THRU
+                 */
+                Pm_Enqueue(in_queue, &buffer);
+
+                /* sysex processing */
+                if (status == MIDI_SYSEX) thru_sysex_in_progress = TRUE;
+                else if ((status & 0xF8) != 0xF8) {
+                    /* not MIDI_SYSEX and not real-time, so */
+                    thru_sysex_in_progress = FALSE;
+                }
+                if (thru_sysex_in_progress && /* look for EOX */
+                    (((buffer.message & 0xFF) == MIDI_EOX) ||
+                     (((buffer.message >> 8) & 0xFF) == MIDI_EOX) ||
+                     (((buffer.message >> 16) & 0xFF) == MIDI_EOX) ||
+                     (((buffer.message >> 24) & 0xFF) == MIDI_EOX))) {
+                    thru_sysex_in_progress = FALSE;
+                }
+            }
+        } while (result);
+    }
+
+
+    /* see if there is application midi data to process */
+    while (!Pm_QueueEmpty(out_queue)) {
+        /* see if it is time to output the next message */
+        PmEvent *next = (PmEvent *) Pm_QueuePeek(out_queue);
+        assert(next); /* must be non-null because queue is not empty */
+        if (next->timestamp <= current_timestamp) {
+            /* time to send a message, first make sure it's not blocked */
+            int status = Pm_MessageStatus(next->message);
+            if ((status & 0xF8) == 0xF8) {
+                ; /* real-time messages are not blocked */
+            } else if (thru_sysex_in_progress) {
+                /* maybe sysex has timed out (output becomes unblocked) */
+                if (last_timestamp + 5000 < current_timestamp) {
+                    thru_sysex_in_progress = FALSE;
+                } else break; /* output is blocked, so exit loop */
+            }
+            Pm_Dequeue(out_queue, &buffer);
+            Pm_Write(midi_out, &buffer, 1);
+
+            /* inspect message to update app_sysex_in_progress */
+            if (status == MIDI_SYSEX) app_sysex_in_progress = TRUE;
+            else if ((status & 0xF8) != 0xF8) {
+                /* not MIDI_SYSEX and not real-time, so */
+                app_sysex_in_progress = FALSE;
+            }
+            if (app_sysex_in_progress && /* look for EOX */
+                (((buffer.message & 0xFF) == MIDI_EOX) ||
+                 (((buffer.message >> 8) & 0xFF) == MIDI_EOX) ||
+                 (((buffer.message >> 16) & 0xFF) == MIDI_EOX) ||
+                 (((buffer.message >> 24) & 0xFF) == MIDI_EOX))) {
+                app_sysex_in_progress = FALSE;
+            }
+        } else break; /* wait until indicated timestamp */
+    }
+}
+
+
+void exit_with_message(char *msg)
+{
+#define STRING_MAX 80
+    char line[STRING_MAX];
+    printf("%s\nType ENTER...", msg);
+    fgets(line, STRING_MAX, stdin);
+    exit(1);
+}
+
+
+void initialize()
+/* set up midi processing thread and open midi streams */
+{
+    /* note that it is safe to call PortMidi from the main thread for
+       initialization and opening devices. You should not make any
+       calls to PortMidi from this thread once the midi thread begins.
+       to make PortMidi calls.
+     */
+
+    /* note that this routine provides minimal error checking. If
+       you use the PortMidi library compiled with PM_CHECK_ERRORS,
+       then error messages will be printed and the program will exit
+       if an error is encountered. Otherwise, you should add some
+       error checking to this code.
+     */
+
+    const PmDeviceInfo *info;
+    int id;
+
+    /* make the message queues */
+    in_queue = Pm_QueueCreate(IN_QUEUE_SIZE, sizeof(PmEvent));
+    assert(in_queue != NULL);
+    out_queue = Pm_QueueCreate(OUT_QUEUE_SIZE, sizeof(PmEvent));
+    assert(out_queue != NULL);
+
+    /* always start the timer before you start midi */
+    Pt_Start(1, &process_midi, 0); /* start a timer with millisecond accuracy */
+    /* the timer will call our function, process_midi() every millisecond */
+    
+    Pm_Initialize();
+
+    id = Pm_GetDefaultOutputDeviceID();
+    info = Pm_GetDeviceInfo(id);
+    if (info == NULL) {
+        printf("Could not open default output device (%d).", id);
+        exit_with_message("");
+    }
+    printf("Opening output device %s %s\n", info->interf, info->name);
+
+    /* use zero latency because we want output to be immediate */
+    Pm_OpenOutput(&midi_out, 
+                  id, 
+                  NULL /* driver info */,
+                  OUT_QUEUE_SIZE,
+                  &midithru_time_proc,
+                  NULL /* time info */,
+                  0 /* Latency */);
+
+    id = Pm_GetDefaultInputDeviceID();
+    info = Pm_GetDeviceInfo(id);
+    if (info == NULL) {
+        printf("Could not open default input device (%d).", id);
+        exit_with_message("");
+    }
+    printf("Opening input device %s %s\n", info->interf, info->name);
+    Pm_OpenInput(&midi_in, 
+                 id, 
+                 NULL /* driver info */,
+                 0 /* use default input size */,
+                 &midithru_time_proc,
+                 NULL /* time info */);
+    /* Note: if you set a filter here, then this will filter what goes
+       to the MIDI THRU port. You may not want to do this.
+     */
+    Pm_SetFilter(midi_in, PM_FILT_ACTIVE | PM_FILT_CLOCK);
+
+    active = TRUE; /* enable processing in the midi thread -- yes, this
+                      is a shared variable without synchronization, but
+                      this simple assignment is safe */
+
+}
+
+
+void finalize()
+{
+    /* the timer thread could be in the middle of accessing PortMidi stuff */
+    /* to detect that it is done, we first clear process_midi_exit_flag and
+       then wait for the timer thread to set it
+     */
+    process_midi_exit_flag = FALSE;
+    active = FALSE;
+    /* busy wait for flag from timer thread that it is done */
+    while (!process_midi_exit_flag) ;
+    /* at this point, midi thread is inactive and we need to shut down
+     * the midi input and output
+     */
+    Pt_Stop(); /* stop the timer */
+    Pm_QueueDestroy(in_queue);
+    Pm_QueueDestroy(out_queue);
+
+    Pm_Close(midi_in);
+    Pm_Close(midi_out);
+
+    Pm_Terminate();    
+}
+
+
+int main(int argc, char *argv[])
+{
+    PmTimestamp last_time = 0;
+    PmEvent buffer;
+
+    /* determine what type of test to run */
+    printf("begin PortMidi midithru program...\n");
+
+    initialize(); /* set up and start midi processing */
+	
+    printf("%s\n%s\n",
+           "This program will run for 60 seconds, or until you play middle C,",
+           "echoing all input with a 2 second delay.");
+
+    while (current_timestamp < 60000) {
+        /* just to make the point that this is not a low-latency process,
+           spin until half a second has elapsed */
+        last_time = last_time + 500;
+        while (last_time > current_timestamp) ;
+
+        /* now read data and send it after changing timestamps */
+        while (Pm_Dequeue(in_queue, &buffer) == 1) {
+            /* printf("timestamp %d\n", buffer.timestamp); */
+            /* printf("message %x\n", buffer.message); */
+            buffer.timestamp = buffer.timestamp + 2000; /* delay */
+            Pm_Enqueue(out_queue, &buffer);
+            /* play middle C to break out of loop */
+            if (Pm_MessageStatus(buffer.message) == 0x90 &&
+                Pm_MessageData1(buffer.message) == 60) {
+                goto quit_now;
+            }
+        }
+    }
+quit_now:
+    finalize();
+    exit_with_message("finished PortMidi midithru program.");
+    return 0; /* never executed, but keeps the compiler happy */
+}
diff --git a/pd/portmidi/pm_test/midithru.vcproj b/pd/portmidi/pm_test/midithru.vcproj
new file mode 100755
index 0000000000000000000000000000000000000000..4eb8ed4dbe1c0fe128539a14fcde88480f1c77b8
--- /dev/null
+++ b/pd/portmidi/pm_test/midithru.vcproj
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="midithru"
+	ProjectGUID="{80193DD1-2C02-4A4C-BDF8-49623AD6F556}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="midithru.dir\Debug"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				BasicRuntimeChecks="3"
+				CompileAs="1"
+				DebugInformationFormat="3"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="0"
+				Optimization="0"
+				RuntimeLibrary="1"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Debug/midithru.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Debug\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Debug\midithru.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Debug/midithru.pdb"
+				GenerateDebugInformation="TRUE"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Debug\midithru.lib"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="midithru.dir\Release"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				CompileAs="1"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="2"
+				Optimization="2"
+				RuntimeLibrary="0"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Release/midithru.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Release\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Release\midithru.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Release/midithru.pdb"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Release\midithru.lib"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="">
+			<File
+				RelativePath="..\pm_test\midithru.c">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_test/mm.c b/pd/portmidi/pm_test/mm.c
new file mode 100755
index 0000000000000000000000000000000000000000..209ff74eeaed26fdba74a9a783baa08da729f556
--- /dev/null
+++ b/pd/portmidi/pm_test/mm.c
@@ -0,0 +1,572 @@
+/* mm.c -- midi monitor */
+
+/*****************************************************************************
+*       Change Log
+*  Date | Change
+*-----------+-----------------------------------------------------------------
+*  7-Apr-86 | Created changelog
+* 31-Jan-90 | GWL : use new cmdline
+*  5-Apr-91 | JDW : Further changes
+* 16-Feb-92 | GWL : eliminate label mmexit:; add error recovery
+* 18-May-92 | GWL : continuous clocks, etc.
+* 17-Jan-94 | GWL : option to display notes
+* 20-Nov-06 | RBD : port mm.c from CMU Midi Toolkit to PortMidi
+*           |       mm.c -- revealing MIDI secrets for over 20 years!
+*****************************************************************************/
+
+#include "stdlib.h"
+#include "ctype.h"
+#include "string.h"
+#include "stdio.h"
+#include "porttime.h"
+#include "portmidi.h"
+
+#define STRING_MAX 80
+
+#define MIDI_CODE_MASK  0xf0
+#define MIDI_CHN_MASK   0x0f
+/*#define MIDI_REALTIME   0xf8
+  #define MIDI_CHAN_MODE  0xfa */
+#define MIDI_OFF_NOTE   0x80
+#define MIDI_ON_NOTE    0x90
+#define MIDI_POLY_TOUCH 0xa0
+#define MIDI_CTRL       0xb0
+#define MIDI_CH_PROGRAM 0xc0
+#define MIDI_TOUCH      0xd0
+#define MIDI_BEND       0xe0
+
+#define MIDI_SYSEX      0xf0
+#define MIDI_Q_FRAME	0xf1
+#define MIDI_SONG_POINTER 0xf2
+#define MIDI_SONG_SELECT 0xf3
+#define MIDI_TUNE_REQ	0xf6
+#define MIDI_EOX        0xf7
+#define MIDI_TIME_CLOCK 0xf8
+#define MIDI_START      0xfa
+#define MIDI_CONTINUE	0xfb
+#define MIDI_STOP       0xfc
+#define MIDI_ACTIVE_SENSING 0xfe
+#define MIDI_SYS_RESET  0xff
+
+#define MIDI_ALL_SOUND_OFF 0x78
+#define MIDI_RESET_CONTROLLERS 0x79
+#define MIDI_LOCAL	0x7a
+#define MIDI_ALL_OFF	0x7b
+#define MIDI_OMNI_OFF	0x7c
+#define MIDI_OMNI_ON	0x7d
+#define MIDI_MONO_ON	0x7e
+#define MIDI_POLY_ON	0x7f
+
+
+#define private static
+
+#ifndef false
+#define false 0
+#define true 1
+#endif
+
+typedef int boolean;
+
+int debug = false;	/* never set, but referenced by userio.c */
+PmStream *midi_in;      /* midi input */
+boolean active = false;     /* set when midi_in is ready for reading */
+boolean in_sysex = false;   /* we are reading a sysex message */
+boolean inited = false;     /* suppress printing during command line parsing */
+boolean done = false;       /* when true, exit */
+boolean notes = true;       /* show notes? */
+boolean controls = true;    /* show continuous controllers */
+boolean bender = true;      /* record pitch bend etc.? */
+boolean excldata = true;    /* record system exclusive data? */
+boolean verbose = true;     /* show text representation? */
+boolean realdata = true;    /* record real time messages? */
+boolean clksencnt = true;   /* clock and active sense count on */
+boolean chmode = true;      /* show channel mode messages */
+boolean pgchanges = true;   /* show program changes */
+boolean flush = false;	    /* flush all pending MIDI data */
+
+uint32_t filter = 0;            /* remember state of midi filter */
+
+uint32_t clockcount = 0;        /* count of clocks */
+uint32_t actsensecount = 0;     /* cout of active sensing bytes */
+uint32_t notescount = 0;        /* #notes since last request */
+uint32_t notestotal = 0;        /* total #notes */
+
+char val_format[] = "    Val %d\n";
+
+/*****************************************************************************
+*    Imported variables
+*****************************************************************************/
+
+extern  int     abort_flag;
+
+/*****************************************************************************
+*    Routines local to this module
+*****************************************************************************/
+
+private    void    mmexit(int code);
+private    void    output(PmMessage data);
+private    int     put_pitch(int p);
+private    void    showhelp();
+private    void    showbytes(PmMessage data, int len, boolean newline);
+private    void    showstatus(boolean flag);
+private    void    doascii(char c);
+private    int     get_number(char *prompt);
+
+
+/* read a number from console */
+/**/
+int get_number(char *prompt)
+{
+    char line[STRING_MAX];
+    int n = 0, i;
+    printf(prompt);
+    while (n != 1) {
+        n = scanf("%d", &i);
+        fgets(line, STRING_MAX, stdin);
+
+    }
+    return i;
+}
+
+
+void receive_poll(PtTimestamp timestamp, void *userData)
+{
+    PmEvent event;
+    int count;
+    if (!active) return;
+    while ((count = Pm_Read(midi_in, &event, 1))) {
+        if (count == 1) output(event.message);
+        else            printf(Pm_GetErrorText(count));
+    }
+}
+
+
+/****************************************************************************
+*               main
+* Effect: prompts for parameters, starts monitor
+****************************************************************************/
+
+int main(int argc, char **argv)
+{
+    char *argument;
+    int inp;
+    PmError err;
+    int i;
+    if (argc > 1) { /* first arg can change defaults */
+        argument = argv[1];
+        while (*argument) doascii(*argument++);
+    }
+    showhelp();
+    /* use porttime callback to empty midi queue and print */
+    Pt_Start(1, receive_poll, 0);
+    /* list device information */
+    printf("MIDI input devices:\n");
+    for (i = 0; i < Pm_CountDevices(); i++) {
+        const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+        if (info->input) printf("%d: %s, %s\n", i, info->interf, info->name);
+    }
+    inp = get_number("Type input device number: ");
+    err = Pm_OpenInput(&midi_in, inp, NULL, 512, NULL, NULL);
+    if (err) {
+        printf(Pm_GetErrorText(err));
+        Pt_Stop();
+        mmexit(1);
+    }
+    Pm_SetFilter(midi_in, filter);
+    inited = true; /* now can document changes, set filter */
+    printf("Midi Monitor ready.\n");
+    active = true;
+    while (!done) {
+        char s[100];
+        if (fgets(s, 100, stdin)) {
+            doascii(s[0]);
+        }
+    }
+    active = false;
+    Pm_Close(midi_in);
+    Pt_Stop();
+    Pm_Terminate();
+    mmexit(0);
+    return 0; // make the compiler happy be returning a value
+}
+
+
+/****************************************************************************
+*               doascii
+* Inputs:
+*    char c: input character
+* Effect: interpret to revise flags
+****************************************************************************/
+
+private void doascii(char c)
+{
+    if (isupper(c)) c = tolower(c);
+    if (c == 'q') done = true;
+    else if (c == 'b') {
+        bender = !bender;
+        filter ^= PM_FILT_PITCHBEND;
+        if (inited)
+            printf("Pitch Bend, etc. %s\n", (bender ? "ON" : "OFF"));
+    } else if (c == 'c') {
+        controls = !controls;
+        filter ^= PM_FILT_CONTROL;
+        if (inited)
+            printf("Control Change %s\n", (controls ? "ON" : "OFF"));
+    } else if (c == 'h') {
+        pgchanges = !pgchanges;
+        filter ^= PM_FILT_PROGRAM;
+        if (inited)
+            printf("Program Changes %s\n", (pgchanges ? "ON" : "OFF"));
+    } else if (c == 'n') {
+        notes = !notes;
+        filter ^= PM_FILT_NOTE;
+        if (inited)
+            printf("Notes %s\n", (notes ? "ON" : "OFF"));
+    } else if (c == 'x') {
+        excldata = !excldata;
+        filter ^= PM_FILT_SYSEX;
+        if (inited)
+            printf("System Exclusive data %s\n", (excldata ? "ON" : "OFF"));
+    } else if (c == 'r') {
+        realdata = !realdata;
+        filter ^= (PM_FILT_PLAY | PM_FILT_RESET | PM_FILT_TICK | PM_FILT_UNDEFINED);
+        if (inited)
+            printf("Real Time messages %s\n", (realdata ? "ON" : "OFF"));
+    } else if (c == 'k') {
+        clksencnt = !clksencnt;
+        filter ^= PM_FILT_CLOCK;
+        if (inited)
+            printf("Clock and Active Sense Counting %s\n", (clksencnt ? "ON" : "OFF"));
+        if (!clksencnt) clockcount = actsensecount = 0;
+    } else if (c == 's') {
+        if (clksencnt) {
+            if (inited)
+                printf("Clock Count %ld\nActive Sense Count %ld\n", 
+                        (long) clockcount, (long) actsensecount);
+        } else if (inited) {
+            printf("Clock Counting not on\n");
+        }
+    } else if (c == 't') {
+        notestotal+=notescount;
+        if (inited)
+            printf("This Note Count %ld\nTotal Note Count %ld\n",
+                    (long) notescount, (long) notestotal);
+        notescount=0;
+    } else if (c == 'v') {
+        verbose = !verbose;
+        if (inited)
+            printf("Verbose %s\n", (verbose ? "ON" : "OFF"));
+    } else if (c == 'm') {
+        chmode = !chmode;
+        if (inited)
+            printf("Channel Mode Messages %s", (chmode ? "ON" : "OFF"));
+    } else {
+        if (inited) {
+            if (c == ' ') {
+                PmEvent event;
+                while (Pm_Read(midi_in, &event, 1)) ;	/* flush midi input */
+                printf("...FLUSHED MIDI INPUT\n\n");
+            } else showhelp();
+        }
+    }
+    if (inited) Pm_SetFilter(midi_in, filter);
+}
+
+
+
+private void mmexit(int code)
+{
+    /* if this is not being run from a console, maybe we should wait for
+     * the user to read error messages before exiting
+     */
+    exit(code);
+}
+
+
+/****************************************************************************
+*               output
+* Inputs:
+*    data: midi message buffer holding one command or 4 bytes of sysex msg
+* Effect: format and print  midi data
+****************************************************************************/
+
+char vel_format[] = "    Vel %d\n";
+
+private void output(PmMessage data)
+{
+    int command;    /* the current command */
+    int chan;   /* the midi channel of the current event */
+    int len;    /* used to get constant field width */
+
+    /* printf("output data %8x; ", data); */
+
+    command = Pm_MessageStatus(data) & MIDI_CODE_MASK;
+    chan = Pm_MessageStatus(data) & MIDI_CHN_MASK;
+
+    if (in_sysex || Pm_MessageStatus(data) == MIDI_SYSEX) {
+#define sysex_max 16
+        int i;
+        PmMessage data_copy = data;
+        in_sysex = true;
+        /* look for MIDI_EOX in first 3 bytes 
+         * if realtime messages are embedded in sysex message, they will
+         * be printed as if they are part of the sysex message
+         */
+        for (i = 0; (i < 4) && ((data_copy & 0xFF) != MIDI_EOX); i++) 
+            data_copy >>= 8;
+        if (i < 4) {
+            in_sysex = false;
+            i++; /* include the EOX byte in output */
+        }
+        showbytes(data, i, verbose);
+        if (verbose) printf("System Exclusive\n");
+    } else if (command == MIDI_ON_NOTE && Pm_MessageData2(data) != 0) {
+        notescount++;
+        if (notes) {
+            showbytes(data, 3, verbose);
+            if (verbose) {
+                printf("NoteOn  Chan %2d Key %3d ", chan, Pm_MessageData1(data));
+                len = put_pitch(Pm_MessageData1(data));
+                printf(vel_format + len, Pm_MessageData2(data));
+            }
+        }
+    } else if ((command == MIDI_ON_NOTE /* && Pm_MessageData2(data) == 0 */ ||
+               command == MIDI_OFF_NOTE) && notes) {
+        showbytes(data, 3, verbose);
+        if (verbose) {
+            printf("NoteOff Chan %2d Key %3d ", chan, Pm_MessageData1(data));
+            len = put_pitch(Pm_MessageData1(data));
+            printf(vel_format + len, Pm_MessageData2(data));
+        }
+    } else if (command == MIDI_CH_PROGRAM && pgchanges) {
+        showbytes(data, 2, verbose);
+        if (verbose) {
+            printf("  ProgChg Chan %2d Prog %2d\n", chan, Pm_MessageData1(data) + 1);
+        }
+    } else if (command == MIDI_CTRL) {
+               /* controls 121 (MIDI_RESET_CONTROLLER) to 127 are channel
+                * mode messages. */
+        if (Pm_MessageData1(data) < MIDI_ALL_SOUND_OFF) {
+            showbytes(data, 3, verbose);
+            if (verbose) {
+                printf("CtrlChg Chan %2d Ctrl %2d Val %2d\n",
+                       chan, Pm_MessageData1(data), Pm_MessageData2(data));
+            }
+        } else /* channel mode */ if (chmode) {
+            showbytes(data, 3, verbose);
+            if (verbose) {
+                switch (Pm_MessageData1(data)) {
+                  case MIDI_ALL_SOUND_OFF:
+                      printf("All Sound Off, Chan %2d\n", chan);
+                    break;
+                  case MIDI_RESET_CONTROLLERS:
+                    printf("Reset All Controllers, Chan %2d\n", chan);
+                    break;
+                  case MIDI_LOCAL:
+                    printf("LocCtrl Chan %2d %s\n",
+                            chan, Pm_MessageData2(data) ? "On" : "Off");
+                    break;
+                  case MIDI_ALL_OFF:
+                    printf("All Off Chan %2d\n", chan);
+                    break;
+                  case MIDI_OMNI_OFF:
+                    printf("OmniOff Chan %2d\n", chan);
+                    break;
+                  case MIDI_OMNI_ON:
+                    printf("Omni On Chan %2d\n", chan);
+                    break;
+                  case MIDI_MONO_ON:
+                    printf("Mono On Chan %2d\n", chan);
+                    if (Pm_MessageData2(data))
+                        printf(" to %d received channels\n", Pm_MessageData2(data));
+                    else
+                        printf(" to all received channels\n");
+                    break;
+                  case MIDI_POLY_ON:
+                    printf("Poly On Chan %2d\n", chan);
+                    break;
+                }
+            }
+        }
+    } else if (command == MIDI_POLY_TOUCH && bender) {
+        showbytes(data, 3, verbose);
+        if (verbose) {
+            printf("P.Touch Chan %2d Key %2d ", chan, Pm_MessageData1(data));
+            len = put_pitch(Pm_MessageData1(data));
+            printf(val_format + len, Pm_MessageData2(data));
+        }
+    } else if (command == MIDI_TOUCH && bender) {
+        showbytes(data, 2, verbose);
+        if (verbose) {
+            printf("  A.Touch Chan %2d Val %2d\n", chan, Pm_MessageData1(data));
+        }
+    } else if (command == MIDI_BEND && bender) {
+        showbytes(data, 3, verbose);
+        if (verbose) {
+            printf("P.Bend  Chan %2d Val %2d\n", chan,
+                    (Pm_MessageData1(data) + (Pm_MessageData2(data)<<7)));
+        }
+    } else if (Pm_MessageStatus(data) == MIDI_SONG_POINTER) {
+        showbytes(data, 3, verbose);
+        if (verbose) {
+            printf("    Song Position %d\n",
+                    (Pm_MessageData1(data) + (Pm_MessageData2(data)<<7)));
+        }
+    } else if (Pm_MessageStatus(data) == MIDI_SONG_SELECT) {
+        showbytes(data, 2, verbose);
+        if (verbose) {
+            printf("    Song Select %d\n", Pm_MessageData1(data));
+        }
+    } else if (Pm_MessageStatus(data) == MIDI_TUNE_REQ) {
+        showbytes(data, 1, verbose);
+        if (verbose) {
+            printf("    Tune Request\n");
+        }
+    } else if (Pm_MessageStatus(data) == MIDI_Q_FRAME && realdata) {
+        showbytes(data, 2, verbose);
+        if (verbose) {
+            printf("    Time Code Quarter Frame Type %d Values %d\n",
+                    (Pm_MessageData1(data) & 0x70) >> 4, Pm_MessageData1(data) & 0xf);
+        }
+    } else if (Pm_MessageStatus(data) == MIDI_START && realdata) {
+        showbytes(data, 1, verbose);
+        if (verbose) {
+            printf("    Start\n");
+        }
+    } else if (Pm_MessageStatus(data) == MIDI_CONTINUE && realdata) {
+        showbytes(data, 1, verbose);
+        if (verbose) {
+            printf("    Continue\n");
+        }
+    } else if (Pm_MessageStatus(data) == MIDI_STOP && realdata) {
+        showbytes(data, 1, verbose);
+        if (verbose) {
+            printf("    Stop\n");
+        }
+    } else if (Pm_MessageStatus(data) == MIDI_SYS_RESET && realdata) {
+        showbytes(data, 1, verbose);
+        if (verbose) {
+            printf("    System Reset\n");
+        }
+    } else if (Pm_MessageStatus(data) == MIDI_TIME_CLOCK) {
+        if (clksencnt) clockcount++;
+        else if (realdata) {
+            showbytes(data, 1, verbose);
+            if (verbose) {
+                printf("    Clock\n");
+            }
+        }
+    } else if (Pm_MessageStatus(data) == MIDI_ACTIVE_SENSING) {
+        if (clksencnt) actsensecount++;
+        else if (realdata) {
+            showbytes(data, 1, verbose);
+            if (verbose) {
+                printf("    Active Sensing\n");
+            }
+        }
+    } else showbytes(data, 3, verbose);
+    fflush(stdout);
+}
+
+
+/****************************************************************************
+*               put_pitch
+* Inputs:
+*    int p: pitch number
+* Effect: write out the pitch name for a given number
+****************************************************************************/
+
+private int put_pitch(int p)
+{
+    char result[8];
+    static char *ptos[] = {
+        "c", "cs", "d", "ef", "e", "f", "fs", "g",
+        "gs", "a", "bf", "b"    };
+    /* note octave correction below */
+    sprintf(result, "%s%d", ptos[p % 12], (p / 12) - 1);
+    printf(result);
+    return strlen(result);
+}
+
+
+/****************************************************************************
+*               showbytes
+* Effect: print hex data, precede with newline if asked
+****************************************************************************/
+
+char nib_to_hex[] = "0123456789ABCDEF";
+
+private void showbytes(PmMessage data, int len, boolean newline)
+{
+    int count = 0;
+    int i;
+
+/*    if (newline) {
+        putchar('\n');
+        count++;
+    } */
+    for (i = 0; i < len; i++) {
+        putchar(nib_to_hex[(data >> 4) & 0xF]);
+        putchar(nib_to_hex[data & 0xF]);
+        count += 2;
+        if (count > 72) {
+            putchar('.');
+            putchar('.');
+            putchar('.');
+            break;
+        }
+        data >>= 8;
+    }
+    putchar(' ');
+}
+
+
+
+/****************************************************************************
+*               showhelp
+* Effect: print help text
+****************************************************************************/
+
+private void showhelp()
+{
+    printf("\n");
+    printf("   Item Reported  Range     Item Reported  Range\n");
+    printf("   -------------  -----     -------------  -----\n");
+    printf("   Channels       1 - 16    Programs       1 - 128\n");
+    printf("   Controllers    0 - 127   After Touch    0 - 127\n");
+    printf("   Loudness       0 - 127   Pitch Bend     0 - 16383, center = 8192\n");
+    printf("   Pitches        0 - 127, 60 = c4 = middle C\n");
+    printf(" \n");
+    printf("n toggles notes");
+    showstatus(notes);
+    printf("t displays noteon count since last t\n");
+    printf("b toggles pitch bend, aftertouch");
+    showstatus(bender);
+    printf("c toggles continuous control");
+    showstatus(controls);
+    printf("h toggles program changes");
+    showstatus(pgchanges);
+    printf("x toggles system exclusive");
+    showstatus(excldata);
+    printf("k toggles clock and sense counting only");
+    showstatus(clksencnt);
+    printf("r toggles other real time messages & SMPTE");
+    showstatus(realdata);
+    printf("s displays clock and sense count since last k\n");
+    printf("m toggles channel mode messages");
+    showstatus(chmode);
+    printf("v toggles verbose text");
+    showstatus(verbose);
+    printf("q quits\n");
+    printf("\n");
+}
+
+/****************************************************************************
+*               showstatus
+* Effect: print status of flag
+****************************************************************************/
+
+private void showstatus(boolean flag)
+{
+    printf(", now %s\n", flag ? "ON" : "OFF" );
+}
diff --git a/pd/portmidi/pm_test/mm.vcproj b/pd/portmidi/pm_test/mm.vcproj
new file mode 100755
index 0000000000000000000000000000000000000000..e9c5357bb894fa6e53a42f13738684e9bd42d64d
--- /dev/null
+++ b/pd/portmidi/pm_test/mm.vcproj
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="mm"
+	ProjectGUID="{EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="mm.dir\Debug"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				BasicRuntimeChecks="3"
+				CompileAs="1"
+				DebugInformationFormat="3"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="0"
+				Optimization="0"
+				RuntimeLibrary="1"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Debug/mm.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Debug\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Debug\mm.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Debug/mm.pdb"
+				GenerateDebugInformation="TRUE"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Debug\mm.lib"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="mm.dir\Release"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				CompileAs="1"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="2"
+				Optimization="2"
+				RuntimeLibrary="0"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Release/mm.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Release\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Release\mm.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Release/mm.pdb"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Release\mm.lib"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="">
+			<File
+				RelativePath="..\pm_test\mm.c">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_test/qtest.c b/pd/portmidi/pm_test/qtest.c
new file mode 100644
index 0000000000000000000000000000000000000000..14d803e871d9aee27502b01add38b2985c3c1377
--- /dev/null
+++ b/pd/portmidi/pm_test/qtest.c
@@ -0,0 +1,174 @@
+#include "portmidi.h"
+#include "pmutil.h"
+#include "stdlib.h"
+#include "stdio.h"
+
+
+/* make_msg -- make a psuedo-random message of length n whose content
+ *    is purely a function of i 
+ */
+void make_msg(long msg[], int n, int i)
+{
+    int j;
+    for (j = 0; j < n; j++) {
+        msg[j] = i % (j + 5);
+    }
+} 
+
+
+/* print_msg -- print the content of msg of length n to stdout */
+/**/
+void print_msg(long msg[], int n)
+{
+    int i;
+    for (i = 0; i < n; i++) {
+        printf(" %li", msg[i]);
+    }
+}
+
+
+/* cmp_msg -- compare two messages of length n */
+/**/
+int cmp_msg(long msg[], long msg2[], int n, int i)
+{
+    int j;
+    for (j = 0; j < n; j++) {
+        if (msg[j] != msg2[j]) {
+            printf("Received message %d doesn't match sent message\n", i);
+            printf("in: "); print_msg(msg, n); printf("\n");
+            printf("out:"); print_msg(msg2, n); printf("\n");
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+
+int main()
+{
+    int msg_len;
+    for (msg_len = 4; msg_len < 100; msg_len += 5) {
+        PmQueue *queue = Pm_QueueCreate(100, msg_len * sizeof(long));
+        int i;
+        long msg[100];
+        long msg2[100];
+
+	printf("msg_len = %d\n", msg_len);
+        if (!queue) {
+            printf("Could not allocate queue\n");
+            return 1;
+        }
+    
+        /* insert/remove 1000 messages */
+        printf("test 1\n");
+        for (i = 0; i < 1357; i++) {
+            make_msg(msg, msg_len, i);
+            if (Pm_Enqueue(queue, msg)) {
+                printf("Pm_Enqueue error\n");
+                return 1;
+            }
+            if (Pm_Dequeue(queue, msg2) != 1) {
+                printf("Pm_Dequeue error\n");
+                return 1;
+            }
+            if (!cmp_msg(msg, msg2, msg_len, i)) {
+                return 1;
+            }
+        }
+    
+        /* make full */
+        printf("test 2\n");
+        for (i = 0; i < 100; i++) {
+            make_msg(msg, msg_len, i);
+            if (Pm_Enqueue(queue, msg)) {
+                printf("Pm_Enqueue error\n");
+                return 1;
+            }
+        }
+    
+        /* alternately remove and insert */
+        for (i = 100; i < 1234; i++) {
+            make_msg(msg, msg_len, i - 100); /* what we expect */
+            if (Pm_Dequeue(queue, msg2) != 1) {
+                printf("Pm_Dequeue error\n");
+                return 1;
+            }
+            if (!cmp_msg(msg, msg2, msg_len, i)) {
+                return 1;
+            }
+            make_msg(msg, msg_len, i);
+            if (Pm_Enqueue(queue, msg)) {
+                printf("Pm_Enqueue error\n");
+                return 1;
+            }
+        }
+    
+        /* remove all */
+        while (!Pm_QueueEmpty(queue)) {
+            make_msg(msg, msg_len, i - 100); /* what we expect */
+            if (Pm_Dequeue(queue, msg2) != 1) {
+                printf("Pm_Dequeue error\n");
+                return 1;
+            }
+            if (!cmp_msg(msg, msg2, msg_len, i)) {
+                return 1;
+            }
+            i++;
+        }
+        if (i != 1334) {
+            printf("Message count error\n");
+	    return 1;
+        }
+    
+        /* now test overflow */
+        printf("test 3\n");
+        for (i = 0; i < 110; i++) {
+            make_msg(msg, msg_len, i);
+            if (Pm_Enqueue(queue, msg) == pmBufferOverflow) {
+	        break; /* this is supposed to execute after 100 messages */
+            }
+        }
+        for (i = 0; i < 100; i++) {
+            make_msg(msg, msg_len, i);
+            if (Pm_Dequeue(queue, msg2) != 1) {
+                printf("Pm_Dequeue error\n");
+		return 1;
+            }
+            if (!cmp_msg(msg, msg2, msg_len, i)) {
+                return 1;
+            }
+        }
+	/* we should detect overflow after removing 100 messages */
+        if (Pm_Dequeue(queue, msg2) != pmBufferOverflow) {
+            printf("Pm_Dequeue overflow expected\n");
+	    return 1;
+        }
+    
+	/* after overflow is detected (and cleared), sender can
+	 * send again
+	 */
+        /* see if function is restored, also test peek */
+        printf("test 4\n");
+        for (i = 0; i < 1357; i++) {
+            long *peek;
+            make_msg(msg, msg_len, i);
+            if (Pm_Enqueue(queue, msg)) {
+                printf("Pm_Enqueue error\n");
+                return 1;
+            }
+            peek = (long *) Pm_QueuePeek(queue);
+            if (!cmp_msg(msg, peek, msg_len, i)) {
+	        return 1;
+            }
+            if (Pm_Dequeue(queue, msg2) != 1) {
+                printf("Pm_Dequeue error\n");
+	        return 1;
+            }
+            if (!cmp_msg(msg, msg2, msg_len, i)) {
+	        return 1;
+            }
+        }
+        Pm_QueueDestroy(queue);
+    }
+    return 0;
+}
diff --git a/pd/portmidi/pm_test/qtest.vcproj b/pd/portmidi/pm_test/qtest.vcproj
new file mode 100755
index 0000000000000000000000000000000000000000..83fa04a041d59f36c432760f7daeb423eb994064
--- /dev/null
+++ b/pd/portmidi/pm_test/qtest.vcproj
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="qtest"
+	ProjectGUID="{2204E68C-5C1F-440E-8CE6-7E273D4F6AD1}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="qtest.dir\Debug"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				BasicRuntimeChecks="3"
+				CompileAs="1"
+				DebugInformationFormat="3"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="0"
+				Optimization="0"
+				RuntimeLibrary="1"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Debug/qtest.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Debug\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Debug\qtest.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Debug/qtest.pdb"
+				GenerateDebugInformation="TRUE"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Debug\qtest.lib"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="qtest.dir\Release"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				CompileAs="1"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="2"
+				Optimization="2"
+				RuntimeLibrary="0"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Release/qtest.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Release\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Release\qtest.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Release/qtest.pdb"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Release\qtest.lib"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="">
+			<File
+				RelativePath="..\pm_test\qtest.c">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_test/sysex.c b/pd/portmidi/pm_test/sysex.c
new file mode 100755
index 0000000000000000000000000000000000000000..627a3dfa9397a2dc92271343451c1123df1efc95
--- /dev/null
+++ b/pd/portmidi/pm_test/sysex.c
@@ -0,0 +1,528 @@
+/* sysex.c -- example program showing how to send and receive sysex
+    messages
+
+   Messages are stored in a file using 2-digit hexadecimal numbers,
+   one per byte, separated by blanks, with up to 32 numbers per line:
+   F0 14 A7 4B ...
+
+ */
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "assert.h"
+#include "portmidi.h"
+#include "porttime.h"
+#include "string.h"
+#ifdef WIN32
+// need to get declaration for Sleep()
+#include "windows.h"
+#else
+#include <unistd.h>
+#define Sleep(n) usleep(n * 1000)
+#endif
+
+#define MIDI_SYSEX 0xf0
+#define MIDI_EOX 0xf7
+
+#define STRING_MAX 80
+
+#ifndef true
+#define true 1
+#define false 0
+#endif
+
+int latency = 0;
+
+/* read a number from console */
+/**/
+int get_number(char *prompt)
+{
+    char line[STRING_MAX];
+    int n = 0, i;
+    printf(prompt);
+    while (n != 1) {
+        n = scanf("%d", &i);
+        fgets(line, STRING_MAX, stdin);
+
+    }
+    return i;
+}
+
+
+/* loopback test -- send/rcv from 2 to 1000 bytes of random midi data */
+/**/
+void loopback_test()
+{
+    int outp;
+    int inp;
+    PmStream *midi_in;
+    PmStream *midi_out;
+    unsigned char msg[1024];
+    char line[80];
+    int32_t len;
+    int i;
+    int data;
+    PmEvent event;
+    int shift;
+    long total_bytes = 0;
+    int32_t begin_time;
+
+    Pt_Start(1, 0, 0);
+    
+    printf("Connect a midi cable from an output port to an input port.\n");
+    printf("This test will send random data via sysex message from output\n");
+    printf("to input and check that the correct data was received.\n");
+    outp = get_number("Type output device number: ");
+    /* Open output with 1ms latency -- when latency is non-zero, the Win32
+       implementation supports sending sysex messages incrementally in a 
+       series of buffers. This is nicer than allocating a big buffer for the
+       message, and it also seems to work better. Either way works.
+     */
+    while ((latency = get_number(
+                     "Latency in milliseconds (0 to send data immediatedly,\n"
+                     "  >0 to send timestamped messages): ")) < 0);
+    Pm_OpenOutput(&midi_out, outp, NULL, 0, NULL, NULL, latency);
+    inp = get_number("Type input device number: ");
+    /* since we are going to send and then receive, make sure the input buffer
+       is large enough for the entire message */
+    Pm_OpenInput(&midi_in, inp, NULL, 512, NULL, NULL);
+
+    srand((unsigned int) Pt_Time()); /* seed for random numbers */
+
+    begin_time = Pt_Time();
+    while (1) {
+        PmError count;
+        int32_t start_time;
+        int error_position = -1; /* 0; -1; -1 for continuous */ 
+        int expected = 0;
+        int actual = 0;
+        /* this modification will run until an error is detected */
+        /* set error_position above to 0 for interactive, -1 for */
+        /* continuous */
+        if (error_position >= 0) {
+            printf("Type return to send message, q to quit: ");
+            fgets(line, STRING_MAX, stdin);
+            if (line[0] == 'q') goto cleanup;
+        }
+
+        /* compose the message */
+        len = rand() % 998 + 2; /* len only counts data bytes */
+        msg[0] = (char) MIDI_SYSEX; /* start of SYSEX message */
+        /* data bytes go from 1 to len */
+        for (i = 0; i < len; i++) {
+/* pick whether data is sequential or random... (docs say random) */
+#define DATA_EXPR (i+1)
+// #define DATA_EXPR rand()
+            msg[i + 1] = DATA_EXPR & 0x7f; /* MIDI data */
+        }
+        /* final EOX goes in len+1, total of len+2 bytes in msg */
+        msg[len + 1] = (char) MIDI_EOX;
+
+        /* sanity check: before we send, there should be no queued data */
+        count = Pm_Read(midi_in, &event, 1);
+
+        if (count != 0) {
+            printf("Before sending anything, a MIDI message was found in\n");
+            printf("the input buffer. Please try again.\n");
+            break;
+		}
+
+        /* send the message */
+        printf("Sending %d byte sysex message.\n", len + 2);
+        Pm_WriteSysEx(midi_out, 0, msg);
+
+        /* receive the message and compare to msg[] */
+        data = 0;
+        shift = 0;
+        i = 0;
+        start_time = Pt_Time();
+        error_position = -1;
+        /* allow up to 2 seconds for transmission */
+        while (data != MIDI_EOX && start_time + 2000 > Pt_Time()) {
+            count = Pm_Read(midi_in, &event, 1);
+            if (count == 0) {
+                Sleep(1); /* be nice: give some CPU time to the system */
+                continue; /* continue polling for input */
+            }
+            
+            /* printf("read %lx ", event.message);
+               fflush(stdout); */
+            
+            /* compare 4 bytes of data until you reach an eox */
+            for (shift = 0; shift < 32 && (data != MIDI_EOX); shift += 8) {
+                data = (event.message >> shift) & 0xFF;
+                if (data != msg[i] && error_position < 0) {
+                    error_position = i;
+                    expected = msg[i];
+                    actual = data;
+                }
+                i++;
+            }
+        }
+        if (error_position >= 0) {
+            printf("Error at byte %d: sent %x recd %x.\n", error_position, 
+                   expected, actual);
+            break;
+        } else if (i != len + 2) {
+            printf("Error: byte %d not received.\n", i);
+            break;
+        } else {
+            int seconds = (Pt_Time() - begin_time) / 1000;
+	    if (seconds == 0) seconds = 1;
+            printf("Correctly received %d byte sysex message.\n", i);
+	    total_bytes += i;
+	    printf("Cummulative bytes/sec: %d\n", total_bytes / seconds);
+        }
+    }
+cleanup:
+    Pm_Close(midi_out);
+    Pm_Close(midi_in);
+    return;
+}
+
+
+/* send_multiple test -- send many sysex messages */
+/**/
+void send_multiple_test()
+{
+    int outp;
+    int length;
+    int num_msgs;
+    PmStream *midi_out;
+    unsigned char msg[1024];
+    int i;
+    PtTimestamp start_time;
+    PtTimestamp stop_time;
+
+    Pt_Start(1, 0, 0);
+    
+    printf("This is for performance testing. You should be sending to this\n");
+    printf("program running the receive multiple test. Do NOT send to\n");
+    printf("a synthesizer or you risk reprogramming it\n");
+    outp = get_number("Type output device number: ");
+    while ((latency = get_number(
+                     "Latency in milliseconds (0 to send data immediatedly,\n"
+                     "  >0 to send timestamped messages): ")) < 0);
+    Pm_OpenOutput(&midi_out, outp, NULL, 0, NULL, NULL, latency);
+    while ((length = get_number("Message length (7 - 1024): ")) < 7 ||
+           length > 1024) ;
+    while ((num_msgs = get_number("Number of messages: ")) < 1);
+    /* latency, length, and num_msgs should now all be valid */
+    /* compose the message except for sequence number in first 5 bytes */
+    msg[0] = (char) MIDI_SYSEX;
+    for (i = 6; i < length - 1; i++) {
+        msg[i] = i % 128; /* this is just filler */
+    }
+    msg[length - 1] = (char) MIDI_EOX;
+
+    start_time = Pt_Time();
+    /* send the messages */
+    for (i = num_msgs; i > 0; i--) {
+        /* insert sequence number into first 5 data bytes */
+        /* sequence counts down to zero */
+        int j;
+        int count = i;
+        /* 7 bits of message count i goes into each data byte */
+        for (j = 1; j <= 5; j++) {
+            msg[j] = count & 127;
+            count >>= 7;
+        }
+        /* send the message */
+        Pm_WriteSysEx(midi_out, 0, msg);
+    }
+    stop_time = Pt_Time();
+    Pm_Close(midi_out);
+    return;
+}
+
+#define MAX_MSG_LEN 1024
+static unsigned char receive_msg[MAX_MSG_LEN];
+static int receive_msg_index;
+static int receive_msg_length;
+static int receive_msg_count;
+static int receive_msg_error;
+static int receive_msg_messages;
+static PmStream *receive_msg_midi_in;
+static int receive_poll_running;
+
+/* receive_poll -- callback function to check for midi input */
+/**/
+void receive_poll(PtTimestamp timestamp, void *userData)
+{
+    PmError count;
+    PmEvent event;
+    int shift;
+    int data = 0;
+    int i;
+    
+    if (!receive_poll_running) return; /* wait until midi device is opened */
+    shift = 0;
+    while (data != MIDI_EOX) {
+        count = Pm_Read(receive_msg_midi_in, &event, 1);
+        if (count == 0) return;
+
+        /* compare 4 bytes of data until you reach an eox */
+        for (shift = 0; shift < 32 && (data != MIDI_EOX); shift += 8) {
+            receive_msg[receive_msg_index++] = data = 
+                (event.message >> shift) & 0xFF;
+            if (receive_msg_index >= MAX_MSG_LEN) {
+                printf("error: incoming sysex too long\n");
+                goto error;
+            }
+        }
+    }
+    /* check the message */
+    if (receive_msg_length == 0) {
+        receive_msg_length = receive_msg_index;
+    }
+    if (receive_msg_length != receive_msg_index) {
+        printf("error: incoming sysex wrong length\n");
+        goto error;
+    }
+    if (receive_msg[0] != MIDI_SYSEX) {
+        printf("error: incoming sysex missing status byte\n");
+        goto error;
+    }
+    /* get and check the count */
+    count = 0;
+    for (i = 0; i < 5; i++) {
+        count += receive_msg[i + 1] << (7 * i);
+    }
+    if (receive_msg_count == -1) {
+        receive_msg_count = count;
+        receive_msg_messages = count;
+    }
+    if (receive_msg_count != count) {
+        printf("error: incoming sysex has wrong count\n");
+        goto error;
+    }
+    for (i = 6; i < receive_msg_index - 1; i++) {
+        if (receive_msg[i] != i % 128) {
+            printf("error: incoming sysex has bad data\n");
+            goto error;
+        }
+    }
+    if (receive_msg[receive_msg_length - 1] != MIDI_EOX) goto error;
+    receive_msg_index = 0; /* get ready for next message */
+    receive_msg_count--;
+    return;
+ error:
+    receive_msg_error = 1;
+    return;
+}
+
+
+/* receive_multiple_test -- send/rcv from 2 to 1000 bytes of random midi data */
+/**/
+void receive_multiple_test()
+{
+    PmError err;
+    int inp;
+    
+    printf("This test expects to receive data sent by the send_multiple test\n");
+    printf("The test will check that correct data is received.\n");
+
+    /* Important: start PortTime first -- if it is not started first, it will
+       be started by PortMidi, and then our attempt to open again will fail */
+    receive_poll_running = false;
+    if ((err = Pt_Start(1, receive_poll, 0))) {
+        printf("PortTime error code: %d\n", err);
+        goto cleanup;
+    }
+    inp = get_number("Type input device number: ");
+    Pm_OpenInput(&receive_msg_midi_in, inp, NULL, 512, NULL, NULL);
+    receive_msg_index = 0;
+    receive_msg_length = 0;
+    receive_msg_count = -1;
+    receive_msg_error = 0;
+    receive_poll_running = true;
+    while ((!receive_msg_error) && (receive_msg_count != 0)) {
+#ifdef WIN32
+        Sleep(1000);
+#else
+        sleep(1); /* block and wait */
+#endif
+    }
+    if (receive_msg_error) {
+        printf("Receive_multiple test encountered an error\n");
+    } else {
+        printf("Receive_multiple test successfully received %d sysex messages\n", 
+               receive_msg_messages);
+    }
+cleanup:
+    receive_poll_running = false;
+    Pm_Close(receive_msg_midi_in);
+    Pt_Stop();
+    return;
+}
+
+
+#define is_real_time_msg(msg) ((0xF0 & Pm_MessageStatus(msg)) == 0xF8)
+
+
+void receive_sysex()
+{
+    char line[80];
+    FILE *f;
+    PmStream *midi;
+    int shift = 0;
+    int data = 0;
+    int bytes_on_line = 0;
+    PmEvent msg;
+
+    /* determine which output device to use */
+    int i = get_number("Type input device number: ");
+
+    /* open input device */
+    Pm_OpenInput(&midi, i, NULL, 512, NULL, NULL);
+    printf("Midi Input opened, type file for sysex data: ");
+
+    /* open file */
+    fgets(line, STRING_MAX, stdin);
+    /* remove the newline character */
+    if (strlen(line) > 0) line[strlen(line) - 1] = 0;
+    f = fopen(line, "w");
+    if (!f) {
+        printf("Could not open %s\n", line);
+        Pm_Close(midi);
+        return;
+    }
+
+    printf("Ready to receive a sysex message\n");
+
+    /* read data and write to file */
+    while (data != MIDI_EOX) {
+        PmError count;
+        count = Pm_Read(midi, &msg, 1);
+        /* CAUTION: this causes busy waiting. It would be better to 
+           be in a polling loop to avoid being compute bound. PortMidi
+           does not support a blocking read since this is so seldom
+           useful.
+         */
+        if (count == 0) continue;
+        /* ignore real-time messages */
+        if (is_real_time_msg(Pm_MessageStatus(msg.message))) continue;
+
+        /* write 4 bytes of data until you reach an eox */
+        for (shift = 0; shift < 32 && (data != MIDI_EOX); shift += 8) {
+            data = (msg.message >> shift) & 0xFF;
+            /* if this is a status byte that's not MIDI_EOX, the sysex
+               message is incomplete and there is no more sysex data */
+            if (data & 0x80 && data != MIDI_EOX) break;
+            fprintf(f, "%2x ", data);
+            if (++bytes_on_line >= 16) {
+                fprintf(f, "\n");
+                bytes_on_line = 0;
+            }
+        }
+    }
+    fclose(f);
+    Pm_Close(midi);
+}
+
+
+void send_sysex()
+{
+    char line[80];
+    FILE *f;
+    PmStream *midi;
+    int data;
+    int shift = 0;
+    PmEvent msg;
+
+	/* determine which output device to use */
+    int i = get_number("Type output device number: ");
+    while ((latency = get_number(
+                     "Latency in milliseconds (0 to send data immediatedly,\n"
+                     "  >0 to send timestamped messages): ")) < 0);
+
+    msg.timestamp = 0; /* no need for timestamp */
+
+	/* open output device */
+    Pm_OpenOutput(&midi, i, NULL, 0, NULL, NULL, latency);
+	printf("Midi Output opened, type file with sysex data: ");
+
+    /* open file */
+    fgets(line, STRING_MAX, stdin);
+    /* remove the newline character */
+    if (strlen(line) > 0) line[strlen(line) - 1] = 0;
+    f = fopen(line, "r");
+    if (!f) {
+        printf("Could not open %s\n", line);
+        Pm_Close(midi);
+        return;
+    }
+
+    /* read file and send data */
+    msg.message = 0;
+    while (1) {
+        /* get next byte from file */
+
+        if (fscanf(f, "%x", &data) == 1) {
+            /* printf("read %x, ", data); */
+            /* OR byte into message at proper offset */
+            msg.message |= (data << shift);
+            shift += 8;
+        }
+        /* send the message if it's full (shift == 32) or if we are at end */
+        if (shift == 32 || data == MIDI_EOX) {
+            /* this will send sysex data 4 bytes at a time -- it would
+               be much more efficient to send multiple PmEvents at once
+               but this method is simpler. See Pm_WriteSysEx for a more
+               efficient code example.
+             */
+            Pm_Write(midi, &msg, 1);
+            msg.message = 0;
+            shift = 0;
+        }
+        if (data == MIDI_EOX) { /* end of message */
+            fclose(f);
+            Pm_Close(midi);
+            return;
+        }
+    }
+}
+
+
+int main()
+{
+    int i;
+    char line[80];
+    
+    /* list device information */
+    for (i = 0; i < Pm_CountDevices(); i++) {
+        const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+        printf("%d: %s, %s", i, info->interf, info->name);
+        if (info->input) printf(" (input)");
+        if (info->output) printf(" (output)");
+        printf("\n");
+    }
+    while (1) {
+        printf("Type r to receive sysex, s to send,"
+               " l for loopback test, m to send multiple,"
+               " n to receive multiple, q to quit: ");
+        fgets(line, STRING_MAX, stdin);
+        switch (line[0]) {
+          case 'r':
+            receive_sysex();
+            break;
+          case 's':
+            send_sysex();
+            break;
+          case 'l':
+            loopback_test();
+            break;
+          case 'm':
+            send_multiple_test();
+            break;
+          case 'n':
+            receive_multiple_test();
+            break;
+          case 'q':
+            exit(0);
+          default:
+            break;
+        }
+    }
+    return 0;
+}
diff --git a/pd/portmidi/pm_test/sysex.vcproj b/pd/portmidi/pm_test/sysex.vcproj
new file mode 100755
index 0000000000000000000000000000000000000000..d5bfd97b470e8b0a0d3e6f5af03598085db5db8f
--- /dev/null
+++ b/pd/portmidi/pm_test/sysex.vcproj
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="sysex"
+	ProjectGUID="{71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="sysex.dir\Debug"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				BasicRuntimeChecks="3"
+				CompileAs="1"
+				DebugInformationFormat="3"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="0"
+				Optimization="0"
+				RuntimeLibrary="1"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Debug/sysex.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Debug\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Debug\sysex.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Debug/sysex.pdb"
+				GenerateDebugInformation="TRUE"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Debug\sysex.lib"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="sysex.dir\Release"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				CompileAs="1"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="2"
+				Optimization="2"
+				RuntimeLibrary="0"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Release/sysex.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Release\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Release\sysex.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Release/sysex.pdb"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Release\sysex.lib"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="">
+			<File
+				RelativePath="..\pm_test\sysex.c">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_test/test.c b/pd/portmidi/pm_test/test.c
new file mode 100755
index 0000000000000000000000000000000000000000..03d6331adef3a43bc3906782e4bb9e2c2e55f5ea
--- /dev/null
+++ b/pd/portmidi/pm_test/test.c
@@ -0,0 +1,489 @@
+#include "portmidi.h"
+#include "porttime.h"
+#include "stdlib.h"
+#include "stdio.h"
+#include "string.h"
+#include "assert.h"
+
+#define INPUT_BUFFER_SIZE 100
+#define OUTPUT_BUFFER_SIZE 0
+#define DRIVER_INFO NULL
+#define TIME_PROC ((int32_t (*)(void *)) Pt_Time)
+#define TIME_INFO NULL
+#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
+
+#define STRING_MAX 80 /* used for console input */
+
+int32_t latency = 0;
+
+/* crash the program to test whether midi ports are closed */
+/**/
+void doSomethingReallyStupid() {
+	int * tmp = NULL;
+	*tmp = 5;
+}
+
+
+/* exit the program without any explicit cleanup */
+/**/
+void doSomethingStupid() {
+	assert(0);
+}
+
+
+/* read a number from console */
+/**/
+int get_number(char *prompt)
+{
+    char line[STRING_MAX];
+    int n = 0, i;
+    printf(prompt);
+    while (n != 1) {
+        n = scanf("%d", &i);
+        fgets(line, STRING_MAX, stdin);
+
+    }
+    return i;
+}
+
+
+/*
+ * the somethingStupid parameter can be set to simulate a program crash.
+ * We want PortMidi to close Midi ports automatically in the event of a
+ * crash because Windows does not (and this may cause an OS crash)
+ */
+void main_test_input(unsigned int somethingStupid) {
+    PmStream * midi;
+    PmError status, length;
+    PmEvent buffer[1];
+    int num = 10;
+    int i = get_number("Type input number: ");
+    /* It is recommended to start timer before Midi; otherwise, PortMidi may
+       start the timer with its (default) parameters
+     */
+    TIME_START;
+
+    /* open input device */
+    Pm_OpenInput(&midi, 
+                 i,
+                 DRIVER_INFO, 
+                 INPUT_BUFFER_SIZE, 
+                 TIME_PROC, 
+                 TIME_INFO);
+
+    printf("Midi Input opened. Reading %d Midi messages...\n", num);
+    Pm_SetFilter(midi, PM_FILT_ACTIVE | PM_FILT_CLOCK | PM_FILT_SYSEX);
+    /* empty the buffer after setting filter, just in case anything
+       got through */
+    while (Pm_Poll(midi)) {
+        Pm_Read(midi, buffer, 1);
+    }
+    /* now start paying attention to messages */
+    i = 0; /* count messages as they arrive */
+    while (i < num) {
+        status = Pm_Poll(midi);
+        if (status == TRUE) {
+            length = Pm_Read(midi,buffer, 1);
+            if (length > 0) {
+                printf("Got message %d: time %ld, %2lx %2lx %2lx\n",
+                       i,
+                       (long) buffer[0].timestamp,
+                       (long) Pm_MessageStatus(buffer[0].message),
+                       (long) Pm_MessageData1(buffer[0].message),
+                       (long) Pm_MessageData2(buffer[0].message));
+                i++;
+            } else {
+                assert(0);
+            }
+        }
+        /* simulate crash if somethingStupid is 1 or 2 */
+        if ((i > (num/2)) && (somethingStupid == 1)) {
+            doSomethingStupid();
+        } else if ((i > (num/2)) && (somethingStupid == 2)) {
+            doSomethingReallyStupid();
+        }
+    }
+
+    /* close device (this not explicitly needed in most implementations) */
+    printf("ready to close...");
+
+    Pm_Close(midi);
+    printf("done closing...");
+}
+
+
+
+void main_test_output() {
+    PmStream * midi;
+	char line[80];
+    int32_t off_time;
+    int chord[] = { 60, 67, 76, 83, 90 };
+    #define chord_size 5 
+    PmEvent buffer[chord_size];
+    PmTimestamp timestamp;
+
+    /* determine which output device to use */
+    int i = get_number("Type output number: ");
+
+    /* It is recommended to start timer before PortMidi */
+    TIME_START;
+
+    /* open output device -- since PortMidi avoids opening a timer
+       when latency is zero, we will pass in a NULL timer pointer
+       for that case. If PortMidi tries to access the time_proc,
+       we will crash, so this test will tell us something. */
+    Pm_OpenOutput(&midi, 
+                  i, 
+                  DRIVER_INFO,
+                  OUTPUT_BUFFER_SIZE, 
+                  (latency == 0 ? NULL : TIME_PROC),
+                  (latency == 0 ? NULL : TIME_INFO), 
+                  latency);
+    printf("Midi Output opened with %ld ms latency.\n", (long) latency);
+
+    /* output note on/off w/latency offset; hold until user prompts */
+    printf("ready to send program 1 change... (type RETURN):");
+    fgets(line, STRING_MAX, stdin);
+    /* if we were writing midi for immediate output, we could always use
+       timestamps of zero, but since we may be writing with latency, we
+       will explicitly set the timestamp to "now" by getting the time.
+       The source of timestamps should always correspond to the TIME_PROC
+       and TIME_INFO parameters used in Pm_OpenOutput(). */
+    buffer[0].timestamp = TIME_PROC(TIME_INFO);
+    /* Send a program change to increase the chances we will hear notes */
+    /* Program 0 is usually a piano, but you can change it here: */
+#define PROGRAM 0
+    buffer[0].message = Pm_Message(0xC0, PROGRAM, 0);
+    Pm_Write(midi, buffer, 1);
+
+    printf("ready to note-on... (type RETURN):");
+    fgets(line, STRING_MAX, stdin);
+    buffer[0].timestamp = TIME_PROC(TIME_INFO);
+    buffer[0].message = Pm_Message(0x90, 60, 100);
+    Pm_Write(midi, buffer, 1);
+    printf("ready to note-off... (type RETURN):");
+    fgets(line, STRING_MAX, stdin);
+    buffer[0].timestamp = TIME_PROC(TIME_INFO);
+    buffer[0].message = Pm_Message(0x90, 60, 0);
+    Pm_Write(midi, buffer, 1);
+
+    /* output short note on/off w/latency offset; hold until user prompts */
+    printf("ready to note-on (short form)... (type RETURN):");
+    fgets(line, STRING_MAX, stdin);
+    Pm_WriteShort(midi, TIME_PROC(TIME_INFO),
+                  Pm_Message(0x90, 60, 100));
+    printf("ready to note-off (short form)... (type RETURN):");
+    fgets(line, STRING_MAX, stdin);
+    Pm_WriteShort(midi, TIME_PROC(TIME_INFO),
+                  Pm_Message(0x90, 60, 0));
+
+    /* output several note on/offs to test timing. 
+       Should be 1s between notes */
+    printf("chord will arpeggiate if latency > 0\n");
+    printf("ready to chord-on/chord-off... (type RETURN):");
+    fgets(line, STRING_MAX, stdin);
+    timestamp = TIME_PROC(TIME_INFO);
+    for (i = 0; i < chord_size; i++) {
+        buffer[i].timestamp = timestamp + 1000 * i;
+        buffer[i].message = Pm_Message(0x90, chord[i], 100);
+    }
+    Pm_Write(midi, buffer, chord_size);
+
+    off_time = timestamp + 1000 + chord_size * 1000; 
+    while (TIME_PROC(TIME_INFO) < off_time) 
+		/* busy wait */;
+    for (i = 0; i < chord_size; i++) {
+        buffer[i].timestamp = timestamp + 1000 * i;
+        buffer[i].message = Pm_Message(0x90, chord[i], 0);
+    }
+    Pm_Write(midi, buffer, chord_size);    
+
+    /* close device (this not explicitly needed in most implementations) */
+    printf("ready to close and terminate... (type RETURN):");
+    fgets(line, STRING_MAX, stdin);
+	
+    Pm_Close(midi);
+    Pm_Terminate();
+    printf("done closing and terminating...\n");
+}
+
+
+void main_test_both()
+{
+    int i = 0;
+    int in, out;
+    PmStream * midi, * midiOut;
+    PmEvent buffer[1];
+    PmError status, length;
+    int num = 10;
+    
+    in = get_number("Type input number: ");
+    out = get_number("Type output number: ");
+
+    /* In is recommended to start timer before PortMidi */
+    TIME_START;
+
+    Pm_OpenOutput(&midiOut, 
+                  out, 
+                  DRIVER_INFO,
+                  OUTPUT_BUFFER_SIZE, 
+                  TIME_PROC,
+                  TIME_INFO, 
+                  latency);
+    printf("Midi Output opened with %ld ms latency.\n", (long) latency);
+    /* open input device */
+    Pm_OpenInput(&midi, 
+                 in,
+                 DRIVER_INFO, 
+                 INPUT_BUFFER_SIZE, 
+                 TIME_PROC, 
+                 TIME_INFO);
+    printf("Midi Input opened. Reading %d Midi messages...\n",num);
+    Pm_SetFilter(midi, PM_FILT_ACTIVE | PM_FILT_CLOCK);
+    /* empty the buffer after setting filter, just in case anything
+       got through */
+    while (Pm_Poll(midi)) {
+        Pm_Read(midi, buffer, 1);
+    }
+    i = 0;
+    while (i < num) {
+        status = Pm_Poll(midi);
+        if (status == TRUE) {
+            length = Pm_Read(midi,buffer,1);
+            if (length > 0) {
+                Pm_Write(midiOut, buffer, 1);
+                printf("Got message %d: time %ld, %2lx %2lx %2lx\n",
+                       i,
+                       (long) buffer[0].timestamp,
+                       (long) Pm_MessageStatus(buffer[0].message),
+                       (long) Pm_MessageData1(buffer[0].message),
+                       (long) Pm_MessageData2(buffer[0].message));
+                i++;
+            } else {
+                assert(0);
+            }
+        }
+    }
+
+    /* close midi devices */
+    Pm_Close(midi);
+    Pm_Close(midiOut);
+    Pm_Terminate(); 
+}
+
+
+/* main_test_stream exercises windows winmm API's stream mode */
+/*    The winmm stream mode is used for latency>0, and sends
+   timestamped messages. The timestamps are relative (delta) 
+   times, whereas PortMidi times are absolute. Since peculiar
+   things happen when messages are not always sent in advance,
+   this function allows us to exercise the system and test it.
+ */
+void main_test_stream() {
+    PmStream * midi;
+	char line[80];
+    PmEvent buffer[16];
+
+	/* determine which output device to use */
+    int i = get_number("Type output number: ");
+
+	latency = 500; /* ignore LATENCY for this test and
+				      fix the latency at 500ms */
+
+    /* It is recommended to start timer before PortMidi */
+    TIME_START;
+
+	/* open output device */
+    Pm_OpenOutput(&midi, 
+                  i, 
+                  DRIVER_INFO,
+                  OUTPUT_BUFFER_SIZE, 
+                  TIME_PROC,
+                  TIME_INFO, 
+                  latency);
+    printf("Midi Output opened with %ld ms latency.\n", (long) latency);
+
+    /* output note on/off w/latency offset; hold until user prompts */
+    printf("ready to send output... (type RETURN):");
+    fgets(line, STRING_MAX, stdin);
+
+    /* if we were writing midi for immediate output, we could always use
+       timestamps of zero, but since we may be writing with latency, we
+       will explicitly set the timestamp to "now" by getting the time.
+       The source of timestamps should always correspond to the TIME_PROC
+       and TIME_INFO parameters used in Pm_OpenOutput(). */
+    buffer[0].timestamp = TIME_PROC(TIME_INFO);
+    buffer[0].message = Pm_Message(0xC0, 0, 0);
+	buffer[1].timestamp = buffer[0].timestamp;
+	buffer[1].message = Pm_Message(0x90, 60, 100);
+	buffer[2].timestamp = buffer[0].timestamp + 1000;
+	buffer[2].message = Pm_Message(0x90, 62, 100);
+	buffer[3].timestamp = buffer[0].timestamp + 2000;
+	buffer[3].message = Pm_Message(0x90, 64, 100);
+	buffer[4].timestamp = buffer[0].timestamp + 3000;
+	buffer[4].message = Pm_Message(0x90, 66, 100);
+	buffer[5].timestamp = buffer[0].timestamp + 4000;
+	buffer[5].message = Pm_Message(0x90, 60, 0);
+	buffer[6].timestamp = buffer[0].timestamp + 4000;
+	buffer[6].message = Pm_Message(0x90, 62, 0);
+	buffer[7].timestamp = buffer[0].timestamp + 4000;
+	buffer[7].message = Pm_Message(0x90, 64, 0);
+	buffer[8].timestamp = buffer[0].timestamp + 4000;
+	buffer[8].message = Pm_Message(0x90, 66, 0);
+
+    Pm_Write(midi, buffer, 9);
+#ifdef SEND8
+	/* Now, we're ready for the real test.
+	   Play 4 notes at now, now+500, now+1000, and now+1500
+	   Then wait until now+2000.
+	   Play 4 more notes as before.
+	   We should hear 8 evenly spaced notes. */
+	now = TIME_PROC(TIME_INFO);
+	for (i = 0; i < 4; i++) {
+		buffer[i * 2].timestamp = now + (i * 500);
+		buffer[i * 2].message = Pm_Message(0x90, 60, 100);
+		buffer[i * 2 + 1].timestamp = now + 250 + (i * 500);
+		buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0);
+	}
+    Pm_Write(midi, buffer, 8);
+
+    while (Pt_Time() < now + 2500) 
+		/* busy wait */;
+	/* now we are 500 ms behind schedule, but since the latency
+	   is 500, the delay should not be audible */
+	now += 2000;
+	for (i = 0; i < 4; i++) {
+		buffer[i * 2].timestamp = now + (i * 500);
+		buffer[i * 2].message = Pm_Message(0x90, 60, 100);
+		buffer[i * 2 + 1].timestamp = now + 250 + (i * 500);
+		buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0);
+	}
+    Pm_Write(midi, buffer, 8);
+#endif
+    /* close device (this not explicitly needed in most implementations) */
+    printf("ready to close and terminate... (type RETURN):");
+    fgets(line, STRING_MAX, stdin);
+	
+    Pm_Close(midi);
+    Pm_Terminate();
+    printf("done closing and terminating...\n");
+}
+
+
+void show_usage()
+{
+    printf("Usage: test [-h] [-l latency-in-ms]\n");
+    exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+    int default_in;
+    int default_out;
+    int i = 0, n = 0;
+    char line[STRING_MAX];
+    int test_input = 0, test_output = 0, test_both = 0, somethingStupid = 0;
+    int stream_test = 0;
+    int latency_valid = FALSE;
+    
+    if (sizeof(void *) == 8) 
+        printf("Apparently this is a 64-bit machine.\n");
+    else if (sizeof(void *) == 4) 
+        printf ("Apparently this is a 32-bit machine.\n");
+    
+    for (i = 1; i < argc; i++) {
+        if (strcmp(argv[i], "-h") == 0) {
+            show_usage();
+        } else if (strcmp(argv[i], "-l") == 0 && (i + 1 < argc)) {
+            i = i + 1;
+            latency = atoi(argv[i]);
+            printf("Latency will be %ld\n", (long) latency);
+            latency_valid = TRUE;
+        } else {
+            show_usage();
+        }
+    }
+
+    while (!latency_valid) {
+        int lat; // declared int to match "%d"
+        printf("Latency in ms: ");
+        if (scanf("%d", &lat) == 1) {
+            latency = (int32_t) lat; // coerce from "%d" to known size
+	    latency_valid = TRUE;
+        }
+    }
+
+    /* determine what type of test to run */
+    printf("begin portMidi test...\n");
+    printf("%s%s%s%s%s",
+           "enter your choice...\n    1: test input\n",
+           "    2: test input (fail w/assert)\n",
+           "    3: test input (fail w/NULL assign)\n",
+           "    4: test output\n    5: test both\n",
+           "    6: stream test\n");
+    while (n != 1) {
+        n = scanf("%d", &i);
+        fgets(line, STRING_MAX, stdin);
+        switch(i) {
+        case 1: 
+            test_input = 1;
+            break;
+        case 2: 
+            test_input = 1;
+            somethingStupid = 1;
+            break;
+        case 3: 
+            test_input = 1;
+            somethingStupid = 2;
+            break;
+        case 4: 
+            test_output = 1;
+            break;
+        case 5:
+            test_both = 1;
+            break;
+		case 6:
+			stream_test = 1;
+			break;
+        default:
+            printf("got %d (invalid input)\n", n);
+            break;
+        }
+    }
+    
+    /* list device information */
+    default_in = Pm_GetDefaultInputDeviceID();
+    default_out = Pm_GetDefaultOutputDeviceID();
+    for (i = 0; i < Pm_CountDevices(); i++) {
+        char *deflt;
+        const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+        if (((test_input  | test_both) & info->input) |
+            ((test_output | test_both | stream_test) & info->output)) {
+            printf("%d: %s, %s", i, info->interf, info->name);
+            if (info->input) {
+                deflt = (i == default_in ? "default " : "");
+                printf(" (%sinput)", deflt);
+            }
+            if (info->output) {
+                deflt = (i == default_out ? "default " : "");
+                printf(" (%soutput)", deflt);
+            }
+            printf("\n");
+        }
+    }
+    
+    /* run test */
+    if (stream_test) {
+        main_test_stream();
+    } else if (test_input) {
+        main_test_input(somethingStupid);
+    } else if (test_output) {
+        main_test_output();
+    } else if (test_both) {
+        main_test_both();
+    }
+    
+    printf("finished portMidi test...type ENTER to quit...");
+    fgets(line, STRING_MAX, stdin);
+    return 0;
+}
diff --git a/pd/portmidi/pm_test/test.vcproj b/pd/portmidi/pm_test/test.vcproj
new file mode 100755
index 0000000000000000000000000000000000000000..95d7f4b933a6a4057719f6753a3cefc7096be5a5
--- /dev/null
+++ b/pd/portmidi/pm_test/test.vcproj
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="test"
+	ProjectGUID="{0BEACB8B-4058-41A4-A9DE-1B1FB650B21A}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="test.dir\Debug"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				BasicRuntimeChecks="3"
+				CompileAs="1"
+				DebugInformationFormat="3"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="0"
+				Optimization="0"
+				RuntimeLibrary="1"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				AssemblerListingLocation="Debug"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Debug/test.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,_DEBUG,PM_CHECK_ERRORS=1,DEBUG,CMAKE_INTDIR=\&quot;Debug\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386 /debug"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Debug\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Debug\test.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Debug/test.pdb"
+				GenerateDebugInformation="TRUE"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Debug\test.lib"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="test.dir\Release"
+			ConfigurationType="1"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="FALSE"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions=" /Zm1000"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				CompileAs="1"
+				ExceptionHandling="0"
+				InlineFunctionExpansion="2"
+				Optimization="2"
+				RuntimeLibrary="0"
+				WarningLevel="3"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				AssemblerListingLocation="Release"
+				ObjectFile="$(IntDir)\"
+				ProgramDataBaseFileName="../pm_test/Release/test.pdb"
+/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				AdditionalIncludeDirectories="..\pm_common;..\porttime;"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"/>
+			<Tool
+				Name="VCMIDLTool"
+				PreprocessorDefinitions="WIN32,_WINDOWS,NDEBUG,CMAKE_INTDIR=\&quot;Release\&quot;"
+				MkTypLibCompatible="FALSE"
+				TargetEnvironment="1"
+				GenerateStublessProxies="TRUE"
+				TypeLibraryName="$(InputName).tlb"
+				OutputDirectory="$(IntDir)"
+				HeaderFileName="$(InputName).h"
+				DLLDataFileName=""
+				InterfaceIdentifierFileName="$(InputName)_i.c"
+				ProxyFileName="$(InputName)_p.c"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions=" /STACK:10000000 /machine:I386"
+				AdditionalDependencies="$(NOINHERIT) kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  ..\Release\portmidi_s.lib winmm.lib "
+				OutputFile="..\pm_test\Release\test.exe"
+				Version="0.0"
+				GenerateManifest="TRUE"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories=""
+				ProgramDataBaseFile="../pm_test/Release/test.pdb"
+				SubSystem="1"
+				ImportLibrary="..\pm_test\Release\test.lib"/>
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="">
+			<File
+				RelativePath="..\pm_test\test.c">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/pm_test/txdata.syx b/pd/portmidi/pm_test/txdata.syx
new file mode 100755
index 0000000000000000000000000000000000000000..1e06e5a6eb9b73183a9eb925db27aacfb2eb6bf0
--- /dev/null
+++ b/pd/portmidi/pm_test/txdata.syx
@@ -0,0 +1,257 @@
+20  0 1d  4  c  6  0 34  1 4d  4  d 1f  7  3  6 
+ c 5e  4 4d  d  b 18  5  3  6  0 3d  1 4a 16 18 
+1f  8  3  6  d  0  1 63  4 13 3a 23  0  0  0  2 
+ c  2  4  0 63 32  0  0  0 32  0 47 72 61 6e 64 
+50 69 61 6e 6f 63 63 63 32 32 32  0  0  0  0  0 
+10  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f  9  9  f  c 27  2 35 37 10 1f  4  3  4 
+ d 19  4 56  5 16 1f  f  8  d  c  0 43 60  4  e 
+1f  c  3  7  e  0 43 63  5 10 3c 14  8  2 1b 56 
+ 5  2  4  0 63 32  0  0  0 32  0 4c 6f 54 69 6e 
+65 38 31 5a 20 63 63 63 32 32 32  0 7f  0  1  0 
+18  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f  e  f  e  9  0  3 43 2d  e 1f  f  5  7 
+ f 16 43 5a  0  0 1f 12  6  8  d  0  3 63  4  0 
+1f 12  6  8  f  0  2 63  4  6 34 14  0  1  2 4e 
+18  2  4  0 63 32  0 32  0 32  0 44 79 6e 6f 6d 
+69 74 65 45 50 63 63 63 32 32 32  0 70  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f  b  1  b  8 18 40 5f  a  e 1f 1f  0  a 
+ f  0 40 5f  4  0 1f 1f  0  a  f  0 40 63  5  6 
+1f 1f  0  a  f  0 40 5f  0  8 1f 20  0  3  0 5a 
+18  4  4  0 63 32 32  0  0 32  0 50 65 72 63 4f 
+72 67 61 6e 20 63 63 63 32 32 32  0  0  0  0  0 
+ 1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f  b  7  f  9  0  4 49 13 13 1f  8  7  5 
+ e  0  2 58  0  c 1f  6  4  6  f 23  3 46 10  a 
+1f  7  8  c  d  0  2 63  8  b  2 1c  0  0  0 52 
+18  4  4  0 63 32  0 32  0 32  0 54 68 69 6e 20 
+43 6c 61 76 20 63 63 63 32 32 32  0 70  0 20  0 
+10  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f  c  0  6  1  a  4 50 20  e 1f  c  0  6 
+ 1  a  4 50 1f  8 1f  b  9  5  e  0  2 63  5  e 
+1f  b  9  5  e  0  3 63  4  8  4 1a  0  0  0 52 
+1d  2  4  0 63 32  0 32  0 32  0 42 72 69 74 65 
+43 65 6c 73 74 63 63 63 32 32 32  0 20  0 26  0 
+ 1  0  8  4  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  f 1f  4  8  f  0 3a 51  4  b  e 1f  0  8 
+ f  0 22 4b  4  3  f 1a  b  8  d  0 3b 36  9  3 
+12 1f  0  8  f  0 22 5d  4  b 3a 1e 19  5  0 52 
+18  4  4  0 63 32  0  0  0 32  0 54 72 75 6d 70 
+65 74 38 31 5a 63 63 63 32 32 32  0  0  0 50  0 
+51  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  c  5  0  8  0  0  2 4a  4  b  f 1f  0  8 
+ f  0  2 3f  4  3 1f  f  0  8  0 23  3 44  b  3 
+10 1f  0  9  f  0  2 5e  4  c 3a 1f 19  7  0 52 
+18  4  4  0 63 32  0  0  0 32  0 46 6c 75 67 65 
+6c 68 6f 72 6e 63 63 63 32 32 32  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 10 1f  0  8  f  0 42 4a  0  3 11 1f  0  8 
+ f  a 43 51  0  3 11  9  0  8  d  0 42 2b 16  6 
+10 1f  0  9  f  0 42 63  4  b 3a 1e  9  9  0 5a 
+24  4  4  0 63 32 31  0  0 32  0 52 61 73 70 41 
+6c 74 6f 20 20 63 63 63 32 32 32  0 10  0 20  0 
+54  0 20  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 10  9  2  6  d  0 41 3e  4 15  c  b  2  3 
+ e  0 41 4f  4 12  c  e  2  8  d  0 42 4b  a 1c 
+ d  b  1  9  e  0  3 63  a 14  0 23  f  2 1b 5e 
+18  4  5  0 63 28 50 32  0 32  0 48 61 72 6d 6f 
+6e 69 63 61 20 63 63 63 32 32 32  0 50 10 50  0 
+50  0 10  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1c  2  0  4  e 63  0 4e  4  3  d  5  0  6 
+ e 63  1 56  a  8 12  7  0  6  9 63  2 47 1b  e 
+ a  a  0  5  f  0  1 63  4  b 32 1a  8  d  0 52 
+ c  4  4  0 63 32  0  0  0 32  0 44 6f 75 62 6c 
+65 42 61 73 73 63 63 63 32 32 32  0 10  0  0  0 
+ 3  0  0  5  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  b  4  0  4  f 14  2 49  9  6  a  7  0  4 
+ f 14  2 51  a  0  8 1f  0  5  f  0  1 63  9  6 
+ a 1f  0  5  f  0  1 63  a  0 3c 1f  6  9  0 52 
+ 5  4  4  0 63 32  0  0  0 32  0 48 69 53 74 72 
+69 6e 67 20 31 63 63 63 32 32 32  0  2  0 30  0 
+32  0 10  5  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 10 13  f  4  a  0  3 3b 14 14 1f  e  8  7 
+ 9  0  2 42  5  e 18 13  d  9  c  0  2 3c 13  8 
+1f 11  7  4  f  0 42 63  4 10 3a 1b  0  0  0 52 
+1d  4  4  0 63 32  0  0  0 32  0 48 61 72 70 20 
+20 20 20 20 20 63 63 63 32 32 32  8  0  0 21  0 
+ 0  0  8  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f  6  6  4  f  0 40 48  5  0  c  8  7  5 
+ f  5  0 52  4  0  f  7  3  7  e  8  3 63  4  6 
+ f  8  4  5  f  0  3 63  4  6 7c 1f  0  6  0 4a 
+11  2  4  0 63 32  0  0  0 32  0 46 61 6e 66 61 
+72 54 70 74 73 63 63 63 32 32 32  6  1  0 38  0 
+ 8  0 48  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  d  b  0  1  c  0  2 2c 3d  3  d  7  0  1 
+ c  0  2 1f 3c  3  d 1f  0  5  f  0  2 63  5  6 
+ d 1f  0  5  f  0  2 63  4  0 3c 63  0 2f  0 53 
+11  4  4  0 63 32  0  0  0 32  0 42 72 65 61 74 
+68 4f 72 67 6e 63 63 63 32 32 32  4 30  5 50  0 
+11  0 18  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f  9  0  6  0 27  2 51 19  b 1c  6  0  8 
+ 0 37  2 47  a  3 1f  a  0  9  0 3d  2 4d  a  e 
+1f 12  8  8  f  0  3 61  4  b 28 1f  0  3  0 52 
+ c  3  4  0 63 32  1 32  0 32  0 4e 79 6c 6f 6e 
+47 75 69 74 20 63 63 63 32 32 32  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f  e  e  f  f  0  3 48 2d  6 1f  f  4  f 
+ f 25  3 5b  0  0 1f 12  6  c  e 1c  3 55  0 10 
+1f 13  7  8  e  6  4 62  4  e 3b 14  0  0  0 42 
+18  2  4  0 63 32  0 32  0 32  0 47 75 69 74 61 
+72 20 23 31 20 63 63 63 32 32 32  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f 19  8  a  3  0  3 63 10 18 1f  c  5  b 
+ 5  0  3 52  0  b 1f 19  6  b  5  0  3 63  a 16 
+1f  f 11  9  7  0  4 63  4  3 3a 14  0  0  0 42 
+18  2  4  0 63 32  0 32  0 32  0 46 75 6e 6b 79 
+20 50 69 63 6b 63 63 63 32 32 32  0 30  0  0  0 
+ 0  0  0  7  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f  1  0  8  4  0  3 3d  a 1e 1f  1  0  8 
+ 0  0  0 43  0 10 1f  9  6  8  c 1b  7 46 1c 1e 
+1f  9  0  9  9  0  1 63  4  3 3a 1c  0  0  0 52 
+ c  4  5  0 63 4b  0  0  0 32  0 45 6c 65 63 42 
+61 73 73 20 31 63 63 63 32 32 32  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f  f  f  e  9  0  3 46 1d 16 1f  f  5  e 
+ e  d  3 63  0  b 1f 13  6  5  d 1c  3 63  0  0 
+1f 13  6  8  f  0  4 63  4  6 3b 1f  0  0  0 42 
+ c  4  4  0 63 32  0 32  0 32  0 53 79 6e 46 75 
+6e 6b 42 61 73 63 63 63 32 32 32  d 6c  0  0  0 
+70  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f 10  7  8  3  0  3 4f  4  3 1f  9  0  8 
+ 0  0  1 4a  0  b 1f 11  0  8  0  0  1 47  4  8 
+1f  9  0  8  0  0  0 63  0  b 39 19  0  7  0 52 
+ c  2  4  0 63 32  0 32  0 32  0 4c 61 74 65 6c 
+79 42 61 73 73 63 63 63 32 32 32  2  0  0  0  0 
+40  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 13 12  0  9  d 22  0 51  0  b 1f 14  0  5 
+ 8 24 40 5c  0  3 1f 11  0  6  c 2c  0 53  9  0 
+10 1f  0  b  f  0  0 5c  a  e 3a 22 11  e 1e 5e 
+18  7  4  0 63 32  0 32  0 32  0 53 79 6e 63 20 
+4c 65 61 64 20 63 63 63 32 32 32  0 70  0 40  0 
+ 2  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 13 1e  0  9  e  0  0 63 3f  b 1f 14  0  5 
+ e 24  1 51  4  3 1f 14  0  f  1  0 41 4d  8  3 
+ f 1f  0  b  f  0  2 63  4  b 3b 20 11 12 33 56 
+18  4  4  0 63 37  e  0  0 32  0 4a 61 7a 7a 20 
+46 6c 75 74 65 63 63 63 32 32 32  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 15 13  d  3  d 1e  2 50 18  e 15 14  9  4 
+ c 1e  2 56 11  8 1b 1f  f  7  f  0  1 63  4  6 
+1a 1f  e  6  f  0  2 63  4  0 7c  b  0  8  0 62 
+18  4  4  0 63 32  0  0  0 32  0 4a 61 76 61 20 
+4a 69 76 65 20 63 63 63 32 32 32  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f  0  0  4  f  0 40 63 3c  0  b  8  7  7 
+ f  5  0 63  4  6  f  5  3  7  f  8  0 3b  5  6 
+ e  8  4  5  f  0  3 63  3  0 7e 1d  6  f  0 4a 
+11  0  4  0 63 32  0  0  0 32  0 42 61 61 64 42 
+72 65 61 74 68 63 63 63 32 32 32  6 30  0 38  0 
+ 1  0 46  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f  0  0  4  f  0 40 47 2f  0  e  8  7  7 
+ f  5  0 4c  0  6 13 1c  d  c  6  8  0 63  5  6 
+14 11  d  b  0  0  3 63  4  0 7a 10  0 51  0 68 
+17  0  4  0 63 32  0  0  0 32  0 56 6f 63 61 6c 
+4e 75 74 73 20 63 63 63 32 32 32  6 30  0 30  0 
+ 1  0 10  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f 1f  0  5  f  0  0 41 32  3 1f 14 10  5 
+ 5  1  2 63  7  3 1f  b 12  8  f  0  1 63  c  3 
+1f 1f  f  8  f  0  1 63  4  3 39 23  0  0  0 62 
+18  7  4  0 63 32  0  0  0 32  0 57 61 74 65 72 
+47 6c 61 73 73 63 63 63 32 32 32  0  0  0  0  0 
+ 0  0  0  7  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 16  2  0  4  6  9  1 4f  8  0 19  e  1  4 
+ 0 20  1 43 19  0 1f 12 10  6  7  0  0 54 3d  3 
+16  d  6  6  2 1e  3 61  8  e 3a 20  1 14  0 42 
+ c  2  4  2 63 63 63  0  0 32  0 46 75 7a 7a 79 
+20 4b 6f 74 6f 63 63 63 32 32 32  0  0  0  0  b 
+50  0  0  5  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1c  8  0  3  e  0  1 55 12  3 1c  7  0  1 
+ e 2e  1 58 27  b  e  4  0  2  a  0  2 63  4  a 
+ d  9  0  2  c  1  2 63 10  b  4 54  0 47  0 53 
+18  7  4  0 63 32  0  0  0 32  0 42 72 74 68 62 
+65 6c 6c 73 20 63 63 63 32 32 32  0  4  0 40  0 
+40  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1a  4  1  1  b 16  0 47  5  3 15  e  0  1 
+ d  0  0 4c  5 16 1c  6  4  2  7  0  0 63  4 16 
+18 18  3  1  e  0  0 5e  4 10 24  7  0  4  0 62 
+24  4  4  0 63 32  0  0  0 32  0 54 75 62 65 20 
+42 65 6c 6c 73 63 63 63 32 32 32  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f 1f 13  3  0  0  0 5f 3d  6 1f 12 13  2 
+ 0  0  1 52  5  2 1f 14 13  3  0  0  1 56 28  5 
+1e  b 13  f  9  0  0 63  6  3 3b 63  0 63  0 73 
+23  7  4  0 63 32  0  0  0 32  0 4e 6f 69 73 65 
+20 53 68 6f 74 63 63 63 32 32 32  8  0  0  0  8 
+ 0  0  0  6  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 1f 16  0  3  7  0  1 50  0  3 1f 18  3  3 
+ 3 22  0 63  0 14 1d  7  6  3  6  0  1 3c  8  3 
+1f  5  7  3  0  0  1 63  4 1b 39 23  0  8  0 42 
+18  4  4  0 63 32  0  0  0 32  0 48 61 6e 64 20 
+44 72 75 6d 20 63 63 63 32 32 32  0  1  0  3  0 
+ 1  0  1  3  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 
+ 0  0 7d f7 
\ No newline at end of file
diff --git a/pd/portmidi/pm_win/README_WIN.txt b/pd/portmidi/pm_win/README_WIN.txt
old mode 100644
new mode 100755
index 3fe5ee4173753c4ecfdd174c0bbf87bc09578d6f..b161bb2740cd956ecb90ba4551e8d45076209143
--- a/pd/portmidi/pm_win/README_WIN.txt
+++ b/pd/portmidi/pm_win/README_WIN.txt
@@ -1,19 +1,23 @@
 File: PortMidi Win32 Readme
 Author: Belinda Thom, June 16 2002
-Revised by: Roger Dannenberg, June 2002, May 2004
+Revised by: Roger Dannenberg, June 2002, May 2004, June 2007, 
+            Umpei Kurokawa, June 2007
+            Roger Dannenberg Sep 2009
+
+Contents:
+        Using Portmidi
+        To Install Portmidi
+        To Compile Portmidi
+        About Cmake
+        Using other versions of Visual C++
+        To Create Your Own Portmidi Client Application
+        
+
 
 =============================================================================
 USING PORTMIDI:
 =============================================================================
 
-PortMidi has been created using a DLL because the Win32 MMedia API doesn't 
-handle midiInput properly in the debugger. Specifically, it doesn't clean up
-after itself if the user (i.e. you, a PortMidi application) hasn't explicitly
-closed all open midi input devices. This lack of cleanup can lead to much
-pain and agony, including the blue-screen-of-death. This situation becomes
-increasingly unacceptable when you are debugging your code, so a portMidi DLL
-seemed to be the most elegant solution.
-
 Using Microsoft Visual C++ project files (provided with PortMidi), there
 are two configurations of the PortMidi library. The Debug version is 
 intended for debugging, especially in a console application. The Debug
@@ -33,14 +37,14 @@ is both optimized and lacking the debugging printout code of the Debug
 version.
 
 Read the portmidi.h file for PortMidi API details on using the PortMidi API.
-See <...>\pm_dll_test\test.c or <...>\multithread\test.c for usage examples.
+See <...>\pm_test\test.c and other files in pm_test for usage examples.
 
 =============================================================================
 TO INSTALL PORTMIDI:
 =============================================================================
-1)  download portmidi.zip
+1)  get current source from the portmedia project at SourceForge.net
 
-2)  unzip portmidi.zip into directory: <...>\portmidi
+2)  copy source into directory: <...>\portmidi
 
 =============================================================================
 TO COMPILE PORTMIDI:
@@ -48,58 +52,104 @@ TO COMPILE PORTMIDI:
 
 3)  cd to or open the portmidi directory
 
-4)  start or click on the portmidi.dsw workspace
-
+4)  start or click on the portmidi.sln workspace (note, all Visual Studio
+    files are built by CMake. If you need a different version or have
+    problems with paths, try rebuilding the Visual Studio project files
+    using CMake -- See "Using other versions of visual C++" below.)
+	
 5)  the following projects exist within this workspace:
-    - portmidi (the PortMidi library)
-	- pm_dll (the dll library used to close midi ports on program exit)
-	- porttime (a small portable library implementing timer facilities)
-	- test (simple midi I/O testing)
-	- multithread (an example illustrating low-latency MIDI processing
-            using a dedicated low-latency thread)
-	- sysex (simple sysex message I/O testing)
-	- latency (uses porttime to measure system latency)
-
-6)  verify that all project settings are for Win32 Debug release:
-	- type Alt-F7
-	- highlight all three projects in left part of Project Settings window; 
-	- "Settings For" should say "Win32 Debug"
-
-7)  use Build->Batch Build ... to build everything in the project
-
-8)  The settings for these projects were distributed in the zip file, so
+    - portmidi-static, portmidi-dynamic (versions of the PortMidi library)
+    - test (simple midi I/O testing)
+    - midithread (an example illustrating low-latency MIDI processing
+        using a dedicated low-latency thread)
+    - sysex (simple sysex message I/O testing)
+    - latency (uses porttime to measure system latency)
+    - midithru (an example illustrating software MIDI THRU)
+    - qtest (a test of the new multicore-safe queue implementation)
+    - mm  (allows monitoring of midi messages)
+    - pmjni (a dll to provide an interface to PortMidi for Java)
+
+6)  set the Java SDK path using one of two methods:
+    Method 1: open portmidi/CMakeLists.txt with CMake, configure, and 
+        generate -- this should find the Java SDK path and update your
+            solution and project files
+    Method 2: (does not require CMake):
+        - open the pmjni project properties
+        - visit Configuration Properties, C/C++, General
+        - find Additional Include Directories property and open the editor (...)
+        - at the end of the list, you will find two paths mentioning Java
+        - these are absolute paths to the Java SDK; you'll need to install the
+          Java SDK (from Sun) and update these directories in order to build
+          this project.
+        - similarly, the Linker->Input->Additional Dependencies list has a
+          path to the jvm.lib file, which needs to be correct(ed).
+
+6)  use Build->Batch Build ... to build everything in the project. If a 
+    build fails, try building again. There seem to be some missing 
+    dependencies, so you may have to "ALL_BUILD" several times before
+    everything builds successfully.
+	
+7)  The settings for these projects were distributed in the zip file, so
     compile should just work.
 
-9)  IMPORTANT! PortMidi uses a DLL, pm_dll.dll, but there is no simple way
-    to set up projects to use pm_dll. THEREFORE, you need to copy DLLs
-    as follows (you can do this with <...>\portmidi\pm_win\copy-dll.bat):
-        copy <...>\portmidi\pm_win\Debug\pm_dll.dll to:
-            <...>\portmidi\pm_test\latencyDebug\pm_dll.dll
-            <...>\portmidi\pm_test\midithreadDebug\pm_dll.dll
-            <...>\portmidi\pm_test\sysexDebug\pm_dll.dll
-            <...>\portmidi\pm_test\testDebug\pm_dll.dll
-            <...>\portmidi\pm_test\midithruDebug\pm_dll.dll
-        and copy <...>\portmidi\pm_win\Release\pm_dll.dll to:
-            <...>\portmidi\pm_test\latencyRelease\pm_dll.dll
-            <...>\portmidi\pm_test\midithreadRelease\pm_dll.dll
-            <...>\portmidi\pm_test\sysexRelease\pm_dll.dll
-            <...>\portmidi\pm_test\testRelease\pm_dll.dll
-            <...>\portmidi\pm_test\midithruRelease\pm_dll.dll
-    each time you rebuild the pm_dll project, these copies must be redone!
-
-    Since Windows will look in the executable directory for DLLs, we 
-    recommend that you always install a copy of pm_dll.dll (either the
-    debug version or the release version) in the same directory as the
-    application using PortMidi. The release DLL is about 40KB. This will 
-    ensure that the application uses the correct DLL.
-
-10) run test project; use the menu that shows up from the command prompt to
+8)  run test project; use the menu that shows up from the command prompt to
     test that portMidi works on your system. tests include: 
 		- verify midi output works
 		- verify midi input works
-		- verify midi input w/midi thru works
 
-11) run other projects if you wish: sysex, latency, midithread, mm, qtest
+9) run other projects if you wish: sysex, latency, midithread, mm, 
+    qtest, midithru
+
+10) compile the java code:
+    - cd pm_java
+    - make.bat
+        + If there is a problem running javac, note that you must have
+          a path to javac.exe on your PATH environment variable. Edit
+          your path (in Vista) using Control Panel > User Accounts > 
+          User Accounts > Change my environment variables; then select
+          Path and click Edit... After changing, you will have to 
+          restart the command window to see any effect.
+        + In Vista, you may get a warning about running 
+          UpdateRsrcJavaExe.exe. This is called by make.bat, and you
+          should allow the program to run.
+        + Note that make.bat does not build pmjni\jportmidi_JPortMidiApi.h
+          because it is included in the distribution. You can rebuild it 
+          from sources as follows:
+              cd pm_java
+              javah jportmidi.JPortMidiApi
+              move jportmidi_JPortMidiApi pmjni\jportmidi_JPortMidiApi.h
+       
+11) you might wish to move pm_java/win32 to another location; run the
+    pmdefaults.exe program from the (entire) win32 directory to use 
+    PmDefaults. This program let's you select default input/output 
+    midi devices for PortMidi applications.
+
+============================================================================
+ABOUT CMAKE
+============================================================================
+
+cmake was used to generate .vcproj files. cmake embeds absolute paths
+into .vcproj files, which makes the files non-portable to other systems.
+To work around this problem, pm_win\clean_up_vcproj.bat can be used to 
+replace absolute paths with relative paths. To use it, you will need to
+install gawk and set your search path to allow you to execute gawk, e.g. 
+my path includes "C:\Program Files\GnuWin32\bin;". You will also need to
+edit pm_win\clean_up_vcproj.awk, replacing C:\Users\rbd\portmidi with
+whatever absolute path cmake uses in your vcproj files.
+
+This is not a general or robust fix, but it seems to work with the 
+vcproj files currently created by CMake.
+
+============================================================================
+USING OTHER VERSIONS OF VISUAL C++
+============================================================================
+
+You can use cmake to make Visual Studio solution and project files.
+If you do not want to use the provided Version 9 project files, install
+cmake, run it, set the "Where is the source code" box to your portmidi
+directory, and click on Configure. A menu will allow you to choose the
+Visual Studio project version you want. Click Configure once again, then
+Generate, and you should be all set to open portmidi.sln.
 
 ============================================================================
 TO CREATE YOUR OWN PORTMIDI CLIENT APPLICATION:
@@ -119,43 +169,35 @@ The easiest way is to start a new project w/in the portMidi workspace:
       in the next step)
 	- Click OK
 	- Select "An Empty Project" and click Finish
-
+	
+	In Visual C++ 2005 Express Edition, 
+	- File->New->Projects
+	- Location: <...>\portmidi\<yourProjectName>
+	- select Add to solution
+	- select CLR Empty project in CLR
+	- select Win32 Console Application in Win32
+	- select Empty project in General
+	
 2) Now this project will be the active project. Make it explicitly depend
    on PortMidi dll:
 	- Project->Dependencies
 	- Click pm_dll
 
-3) Important! in order to be able to use portMidi DLL from your new project
-   and set breakpoints,	copy following files from <...>\pm_dll\Debug into 
-   <...>\<yourProjectName>\Debug directory:
-		pm_dll.lib
-		pm_dll.dll
-    each time you rebuild pm_dll, these copies must be redone!
-
-4) add whatever files you wish to add to your new project, using portMidi
+3) add whatever files you wish to add to your new project, using portMidi
    calls as desired (see USING PORTMIDI at top of this readme)
 
-5) when you include portMidi files, do so like this:
-	- #include "..\pm_dll\portmidi.h"
+4) when you include portMidi files, do so like this:
+	- #include "..\pm_common\portmidi.h"
 	- etc.
 
-6) build and run your project
+5) build and run your project
 
 ============================================================================
 DESIGN NOTES
 ============================================================================
 
-The DLL is used so that PortMidi can (usually) close open devices when the
-program terminates. Failure to close input devices under WinNT, Win2K, and
-probably later systems causes the OS to crash.
-
-This is accomplished with a .LIB/.DLL pair, linking to the .LIB
-in order to access functions in the .DLL. 
-
-PortMidi for Win32 exists as a simple library,
+PortMidi for Win32 exists as a simple static library,
 with Win32-specific code in pmwin.c and MM-specific code in pmwinmm.c.
-pmwin.c uses a DLL in pmdll.c to call Pm_Terminate() when the program
-exits to make sure that all MIDI ports are closed.
 
 Orderly cleanup after errors are encountered is based on a fixed order of
 steps and state changes to reflect each step. Here's the order:
@@ -171,10 +213,8 @@ To open input:
         set descriptor field of PmInternal structure
         - open device
         set handle field of midiwinmm_type structure
-        - allocate buffer 1 for sysex
-        buffer is added to input port
-        - allocate buffer 2 for sysex
-        buffer is added to input port
+        - allocate buffers
+        - start device
         - return
     - return
 
@@ -287,5 +327,15 @@ part of PortMidi is allowed to directly copy sysex bytes to
 "fill_base[*fill_offset_ptr++]" until *fill_offset_ptr reaches
 fill_length. See the code for details.
 
+-----------
+
+Additional notes on using VS 2005 (maybe this is obsolete now?):
+
+1) Make sure "Configuration: All Configurations" is selected in all of the following Properties modifications!
+
+2) In my case the project defaulted to compiling all .c files with the C++ compiler, which was disastrous. I had to go to set Properties for each file, to wit: Expand Configuration Properties, Expand C/C++, Select Advanced, set the Compile As popup to Compile as C Code (/TC). (For better or worse, the project I inherited has a bunch of .c files that rely on C++ features, so I couldn't reliably set this the project properties level.)
+
+3) While you're there, make sure that the C/C++ -> General -> "Compile with Common Language Runtime support" is set to "No Common Language Runtime support" (the C compiler *can't* support CLR, but VS won't do anything useful like automatically set the two options to match)-.
+
+4) I never got VS precompiled header thing to work sensibly, so I took the path of least resistance and turned PCH's off for all my files. Properties -> Configuration Properties -> C/C++ -> Precompiled Headers -> Create/Use Precompiled Header popup set to "Not Using Precompiled Headers". The compiler is reasonably fast even if it has to parse all the header files, so unless someone wants to explain VS's PCHs to me, the hell with it, I say.
 
-  
\ No newline at end of file
diff --git a/pd/portmidi/pm_win/clean_cmake.bat b/pd/portmidi/pm_win/clean_cmake.bat
new file mode 100644
index 0000000000000000000000000000000000000000..6bf4b68e001ec58cb6de076daa405c78a18927bb
--- /dev/null
+++ b/pd/portmidi/pm_win/clean_cmake.bat
@@ -0,0 +1,6 @@
+del /Q ..\CMakeFiles
+del /Q ..\CMakeCache.txt
+del /Q ..\pm_test\CMakeFiles
+del /Q ..\pm_common\CMakeFiles
+del /Q ..\pm_dylib\CMakeFiles
+
diff --git a/pd/portmidi/pm_win/clean_up_vcproj.awk b/pd/portmidi/pm_win/clean_up_vcproj.awk
new file mode 100644
index 0000000000000000000000000000000000000000..a3eadfcb8483f83cebacf2e2de6620250afee9d7
--- /dev/null
+++ b/pd/portmidi/pm_win/clean_up_vcproj.awk
@@ -0,0 +1,70 @@
+# gawk script to convert CMake-generated Visual Studio projects into
+# stand-alone project files
+#
+# Roger Dannenberg, October 2009
+#
+# the result uses relative path names (so you can install the project on 
+# any machine and use it)
+#
+# NOTE: to run this, you must assign base_relative to the relative path
+# from the vcproj file to portmidi, e.g. base_relative=.. or base_relative=.
+
+BEGIN {
+    state = "normal";
+    #=================IMPORTANT====================
+    # change the following path to the path in which
+    # the CMakeLists.txt file resides:
+    base_path = "C:\\\\Users\\\\rbd\\\\portmedia\\\\portmidi";
+    #==============================================
+
+    base_path_2 = base_path;
+    gsub("\\\\\\\\", "/", base_path_2)
+    cmake_stuff = 0; # flag to print <file> ... </file> text
+}
+# this case removes CMake phases from project
+state == "cmakelists" {
+    # print "IN CMAKELISTS " 
+    file_text = file_text "\n" $0 # collect the <file> ... </file> section
+    if (index($0, "CMakeLists.txt") > 0) { 
+        cmake_stuff = 1 # remember to delete this <file> ... </file> section
+    }
+
+    if (index($0, "</File>") > 0) { 
+        state = "normal";
+        if (cmake_stuff == 0) {
+            gsub(base_path, base_relative, file_text)
+            gsub(base_path_2, base_relative, file_text)
+            print file_text;
+        }
+        cmake_stuff = 0;
+    };
+    next
+}
+
+# this is the normal case, not in buildPhases list
+state == "normal" {
+    # print "NOT IN BUILD PHASES"
+    # take out all the absolute paths
+    gsub(base_path, base_relative, $0); 
+    gsub(base_path_2, base_relative, $0); 
+    # special processing for <file> ... </file> text:
+    if ($0 ~ "<File$") {
+        file_text = $0;
+        cmake_stuff = 0; # innocent (keep text) until proven guilty
+        state = "cmakelists";
+        next # do not print this line
+    };
+    # THIS CODE WOULD ALLOW portmidi-static and portmidi-dynamic IN
+    # pm_commmon. I DECIDED TO TRY PUTTING THEM IN SEPARATE DIRECTORIES
+    # INSTEAD.
+    # Use static libraries for everything except portmidi-dynamic
+    #if (($0 ~ "RuntimeLibrary=") && (base_relative ~ "dynamic")) {
+    #    if ($0 ~ 2) {
+    #        $0 = "\t\t\t\tRuntimeLibrary=\"0\"";
+    #    } else if ($0 ~ 3) {
+    #        $0 = "\t\t\t\tRuntimeLibrary=\"1\"";
+    #    }
+    print $0;
+    next
+}
+
diff --git a/pd/portmidi/pm_win/clean_up_vcproj.bat b/pd/portmidi/pm_win/clean_up_vcproj.bat
new file mode 100644
index 0000000000000000000000000000000000000000..1919246d7c0bfddce687b398658b3e73a58e97a9
--- /dev/null
+++ b/pd/portmidi/pm_win/clean_up_vcproj.bat
@@ -0,0 +1,76 @@
+@echo off
+rem Start this program in portmidi\pm_win
+cd ..\pm_common
+
+rename portmidi-static.vcproj portmidi-static.vcproj-cmake
+gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. portmidi-static.vcproj-cmake > portmidi-static.vcproj
+del portmidi-static.vcproj-cmake
+echo portmidi-static
+
+rename pmjni.vcproj pmjni.vcproj-cmake
+gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. pmjni.vcproj-cmake > pmjni.vcproj
+del pmjni.vcproj-cmake
+echo pmjni
+
+cd ../pm_dylib
+
+rename portmidi-dynamic.vcproj portmidi-dynamic.vcproj-cmake
+gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. portmidi-dynamic.vcproj-cmake > portmidi-dynamic.vcproj
+del portmidi-dynamic.vcproj-cmake
+echo portmidi-dynamic
+
+cd ..\pm_test
+
+rename latency.vcproj latency.vcproj-cmake
+gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. latency.vcproj-cmake > latency.vcproj
+del latency.vcproj-cmake
+echo latency
+
+rename midiclock.vcproj midiclock.vcproj-cmake
+gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. midiclock.vcproj-cmake > midiclock.vcproj
+del midiclock.vcproj-cmake
+echo midiclock
+
+rename midithread.vcproj midithread.vcproj-cmake
+gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. midithread.vcproj-cmake > midithread.vcproj
+del midithread.vcproj-cmake
+echo midithread
+
+rename midithru.vcproj midithru.vcproj-cmake
+gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. midithru.vcproj-cmake > midithru.vcproj
+del midithru.vcproj-cmake
+echo midithru
+
+rename mm.vcproj mm.vcproj-cmake
+gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. mm.vcproj-cmake > mm.vcproj
+del mm.vcproj-cmake
+echo mm
+
+rename qtest.vcproj qtest.vcproj-cmake
+gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. qtest.vcproj-cmake > qtest.vcproj
+del qtest.vcproj-cmake
+echo qtest
+
+rename sysex.vcproj sysex.vcproj-cmake
+gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. sysex.vcproj-cmake > sysex.vcproj
+del sysex.vcproj-cmake
+echo sysex
+
+rename test.vcproj test.vcproj-cmake
+gawk -f ..\pm_win\clean_up_vcproj.awk -v base_relative=.. test.vcproj-cmake > test.vcproj
+del test.vcproj-cmake
+
+cd ..
+echo test
+
+rename ALL_BUILD.vcproj ALL_BUILD.vcproj-cmake
+gawk -f pm_win\clean_up_vcproj.awk -v base_relative=. ALL_BUILD.vcproj-cmake > ALL_BUILD.vcproj
+del ALL_BUILD.vcproj-cmake
+echo ALL_BUILD
+
+rename ZERO_CHECK.vcproj ZERO_CHECK.vcproj-cmake
+gawk -f pm_win\clean_up_vcproj.awk -v base_relative=. ZERO_CHECK.vcproj-cmake > ZERO_CHECK.vcproj
+del ZERO_CHECK.vcproj-cmake
+echo ZERO_CHECK
+
+cd pm_win
diff --git a/pd/portmidi/pm_win/copy-dll.bat b/pd/portmidi/pm_win/copy-dll.bat
deleted file mode 100644
index 7c55fff3d45d243ff7d943ffa9b4bc4e502b0bf5..0000000000000000000000000000000000000000
--- a/pd/portmidi/pm_win/copy-dll.bat
+++ /dev/null
@@ -1,17 +0,0 @@
-copy Debug\pm_dll.dll ..\pm_test\testDebug\pm_dll.dll
-copy Debug\pm_dll.dll ..\pm_test\sysexDebug\pm_dll.dll
-copy Debug\pm_dll.dll ..\pm_test\midithreadDebug\pm_dll.dll
-copy Debug\pm_dll.dll ..\pm_test\latencyDebug\pm_dll.dll
-copy Debug\pm_dll.dll ..\pm_test\midithruDebug\pm_dll.dll
-copy Debug\pm_dll.dll ..\pm_test\qtestDebug\pm_dll.dll
-copy Debug\pm_dll.dll ..\pm_test\mmDebug\pm_dll.dll
-
-copy Release\pm_dll.dll ..\pm_test\testRelease\pm_dll.dll
-copy Release\pm_dll.dll ..\pm_test\sysexRelease\pm_dll.dll
-copy Release\pm_dll.dll ..\pm_test\midithreadRelease\pm_dll.dll
-copy Release\pm_dll.dll ..\pm_test\latencyRelease\pm_dll.dll
-copy Release\pm_dll.dll ..\pm_test\midithruRelease\pm_dll.dll
-copy Release\pm_dll.dll ..\pm_test\qtestRelease\pm_dll.dll
-copy Release\pm_dll.dll ..\pm_test\mmRelease\pm_dll.dll
-
-
diff --git a/pd/portmidi/pm_win/debugging_dlls.txt b/pd/portmidi/pm_win/debugging_dlls.txt
old mode 100644
new mode 100755
diff --git a/pd/portmidi/pm_win/pm_dll.dsp b/pd/portmidi/pm_win/pm_dll.dsp
deleted file mode 100644
index 77218ccb1c44c71abb725ef780c0e5a952a4f907..0000000000000000000000000000000000000000
--- a/pd/portmidi/pm_win/pm_dll.dsp
+++ /dev/null
@@ -1,107 +0,0 @@
-# Microsoft Developer Studio Project File - Name="pm_dll" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-CFG=pm_dll - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE 
-!MESSAGE NMAKE /f "pm_dll.mak".
-!MESSAGE 
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE 
-!MESSAGE NMAKE /f "pm_dll.mak" CFG="pm_dll - Win32 Debug"
-!MESSAGE 
-!MESSAGE Possible choices for configuration are:
-!MESSAGE 
-!MESSAGE "pm_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "pm_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE 
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF  "$(CFG)" == "pm_dll - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PM_DLL_EXPORTS" /YX /FD /c
-# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PM_DLL_EXPORTS" /YX /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
-
-!ELSEIF  "$(CFG)" == "pm_dll - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 1
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PM_DLL_EXPORTS" /YX /FD /GZ /c
-# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "pm_common" /D "_WINDOWS" /D "_USRDLL" /D "PM_DLL_EXPORTS" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "USE_DLL_FOR_CLEANUP" /FR /YX /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
-
-!ENDIF 
-
-# Begin Target
-
-# Name "pm_dll - Win32 Release"
-# Name "pm_dll - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\pmdll.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\pmdll.h
-# End Source File
-# End Group
-# End Target
-# End Project
diff --git a/pd/portmidi/pm_win/pmdll.c b/pd/portmidi/pm_win/pmdll.c
deleted file mode 100644
index c3acba33e768c97e651de4d53af4b5e0f57642c9..0000000000000000000000000000000000000000
--- a/pd/portmidi/pm_win/pmdll.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-====================================================================
-DLL to perform action when program shuts down
-====================================================================
-*/
-
-#include "windows.h"
-#include "pmdll.h"
-
-static close_fn_ptr_type close_function = NULL;
-
-
-DLL_EXPORT pm_set_close_function(close_fn_ptr_type close_fn_ptr)
-{
-    close_function = close_fn_ptr;
-}
-
-
-static void Initialize( void ) {
-    return;
-}
-
-static void Terminate( void ) {
-    if (close_function) {
-        (*close_function)();
-    }
-}
-
-
-BOOL WINAPI DllMain(HINSTANCE hinstDLL, //DLL module handle
-					DWORD fdwReason,	//for calling function
-					LPVOID lbpvReserved)//reserved
-{
-	switch(fdwReason) {
-		case DLL_PROCESS_ATTACH:
-			/* when DLL starts, run this */
-			Initialize();
-			break;
-		case DLL_PROCESS_DETACH:
-			/* when DLL ends, this run (note: verified this	run */
-			Terminate();
-			break;
-		default:
-			break;
-	}
-	return TRUE;
-}
-
-
diff --git a/pd/portmidi/pm_win/pmdll.h b/pd/portmidi/pm_win/pmdll.h
deleted file mode 100644
index e5ad1c5bdca5b299d5e0f3f74ea5a0d60d828c72..0000000000000000000000000000000000000000
--- a/pd/portmidi/pm_win/pmdll.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#define DLL_EXPORT __declspec( dllexport )
-
-typedef void (*close_fn_ptr_type)();
-
-DLL_EXPORT pm_set_close_function(close_fn_ptr_type close_fn_ptr);
diff --git a/pd/portmidi/pm_win/pmwin.c b/pd/portmidi/pm_win/pmwin.c
old mode 100644
new mode 100755
index 716b68fa595262046e6944c0730aea8f3740b66e..5b4dec63fce9b3963d3806ac69a8ba4cab5275ae
--- a/pd/portmidi/pm_win/pmwin.c
+++ b/pd/portmidi/pm_win/pmwin.c
@@ -9,6 +9,7 @@
    be separate from the main portmidi.c file because it is system
    dependent, and it is separate from, say, pmwinmm.c, because it
    might need to register devices for winmm, directx, and others.
+
  */
 
 #include "stdlib.h"
@@ -16,12 +17,10 @@
 #include "pmutil.h"
 #include "pminternal.h"
 #include "pmwinmm.h"
-#ifdef USE_DLL_FOR_CLEANUP
-#include "pmdll.h" /* used to close ports on exit */
-#endif
 #ifdef DEBUG
 #include "stdio.h"
 #endif
+#include <windows.h>
 
 /* pm_exit is called when the program exits.
    It calls pm_term to make sure PortMidi is properly closed.
@@ -45,20 +44,9 @@ static void pm_exit(void) {
 /* pm_init is the windows-dependent initialization.*/
 void pm_init(void)
 {
-#ifdef USE_DLL_FOR_CLEANUP
-    /* we were hoping a DLL could offer more robust cleanup after errors,
-       but the DLL does not seem to run after crashes. Thus, the atexit()
-       mechanism is just as powerful, and simpler to implement.
-     */
-    pm_set_close_function(pm_exit);
-#ifdef DEBUG
-    printf("registered pm_term with cleanup DLL\n");
-#endif
-#else
     atexit(pm_exit);
 #ifdef DEBUG
     printf("registered pm_exit with atexit()\n");
-#endif
 #endif
     pm_winmm_init();
     /* initialize other APIs (DirectX?) here */
@@ -70,37 +58,77 @@ void pm_term(void) {
 }
 
 
-PmDeviceID Pm_GetDefaultInputDeviceID() {
-    /* This routine should check the environment and the registry
-       as specified in portmidi.h, but for now, it just returns
-       the first device of the proper input/output flavor.
-     */
-    int i;
+static PmDeviceID pm_get_default_device_id(int is_input, char *key) {
+    HKEY hkey;
+#define PATTERN_MAX 256
+    char pattern[PATTERN_MAX];
+    long pattern_max = PATTERN_MAX;
+    DWORD dwType;
+    /* Find first input or device -- this is the default. */
+    PmDeviceID id = pmNoDevice;
+    int i, j;
     Pm_Initialize(); /* make sure descriptors exist! */
     for (i = 0; i < pm_descriptor_index; i++) {
-        if (descriptors[i].pub.input) {
-            return i;
+        if (descriptors[i].pub.input == is_input) {
+            id = i;
+            break;
         }
     }
-    return pmNoDevice;
+    /* Look in registry for a default device name pattern. */
+    if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &hkey) != 
+        ERROR_SUCCESS) {
+        return id;
+    }
+    if (RegOpenKeyEx(hkey, "JavaSoft", 0, KEY_READ, &hkey) !=
+        ERROR_SUCCESS) {
+        return id;
+    }
+    if (RegOpenKeyEx(hkey, "Prefs", 0, KEY_READ, &hkey) !=
+        ERROR_SUCCESS) {
+        return id;
+    }
+    if (RegOpenKeyEx(hkey, "/Port/Midi", 0, KEY_READ, &hkey) !=
+        ERROR_SUCCESS) {
+        return id;
+    }
+    if (RegQueryValueEx(hkey, key, NULL, &dwType, pattern, &pattern_max) != 
+	ERROR_SUCCESS) {
+        return id;
+    }
+
+    /* decode pattern: upper case encoded with "/" prefix */
+    i = j = 0;
+    while (pattern[i]) {
+        if (pattern[i] == '/' && pattern[i + 1]) {
+            pattern[j++] = toupper(pattern[++i]);
+	} else {
+            pattern[j++] = tolower(pattern[i]);
+	}
+        i++;
+    }
+    pattern[j] = 0; /* end of string */
+
+    /* now pattern is the string from the registry; search for match */
+    i = pm_find_default_device(pattern, is_input);
+    if (i != pmNoDevice) {
+        id = i;
+    }
+    return id;
 }
 
+
+PmDeviceID Pm_GetDefaultInputDeviceID() {
+    return pm_get_default_device_id(TRUE, 
+           "/P/M_/R/E/C/O/M/M/E/N/D/E/D_/I/N/P/U/T_/D/E/V/I/C/E");
+}
+
+
 PmDeviceID Pm_GetDefaultOutputDeviceID() {
-    /* This routine should check the environment and the registry
-       as specified in portmidi.h, but for now, it just returns
-       the first device of the proper input/output flavor.
-     */
-    int i;
-    Pm_Initialize(); /* make sure descriptors exist! */
-    for (i = 0; i < pm_descriptor_index; i++) {
-        if (descriptors[i].pub.output) {
-            return i;
-        }
-    }
-    return pmNoDevice;
-    return 0;
+  return pm_get_default_device_id(FALSE,
+          "/P/M_/R/E/C/O/M/M/E/N/D/E/D_/O/U/T/P/U/T_/D/E/V/I/C/E");
 }
 
+
 #include "stdio.h" 
 
 void *pm_alloc(size_t s) {
@@ -112,3 +140,4 @@ void pm_free(void *ptr) {
     free(ptr); 
 }
 
+
diff --git a/pd/portmidi/pm_win/pmwinmm.c b/pd/portmidi/pm_win/pmwinmm.c
old mode 100644
new mode 100755
index 395b1134cfcacd30902070925aec27eefcf3499b..ab66f80dc1c6b059c015c1aacf1b67058cb6b93c
--- a/pd/portmidi/pm_win/pmwinmm.c
+++ b/pd/portmidi/pm_win/pmwinmm.c
@@ -1,24 +1,28 @@
 /* pmwinmm.c -- system specific definitions */
 
-/* without this define, InitializeCriticalSectionAndSpinCount is undefined */
-/* this version level means "Windows 2000 and higher" */
-#define _WIN32_WINNT 0x0500
+#ifdef _MSC_VER
+ #pragma warning(disable: 4133) // stop warnings about implicit typecasts
+#endif
+
+#ifndef _WIN32_WINNT
+    /* without this define, InitializeCriticalSectionAndSpinCount is 
+     * undefined. This version level means "Windows 2000 and higher" 
+     */
+    #define _WIN32_WINNT 0x0500
+#endif
 
 #include "windows.h"
 #include "mmsystem.h"
 #include "portmidi.h"
-#ifdef NEWBUFFER
 #include "pmutil.h"
-#endif
 #include "pminternal.h"
 #include "pmwinmm.h"
-#include "string.h"
+#include <string.h>
 #include "porttime.h"
 
 /* asserts used to verify portMidi code logic is sound; later may want
     something more graceful */
 #include <assert.h>
-#define DEBUG 1
 #ifdef DEBUG
 /* this printf stuff really important for debugging client app w/host errors.
     probably want to do something else besides read/write from/to console
@@ -39,9 +43,11 @@ static void CALLBACK winmm_in_callback(HMIDIIN hMidiIn,
 static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg,
                                               DWORD dwInstance, DWORD dwParam1, 
                                               DWORD dwParam2);
+#ifdef USE_SYSEX_BUFFERS
 static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg,
                                         DWORD dwInstance, DWORD dwParam1, 
                                         DWORD dwParam2);
+#endif
 
 extern pm_fns_node pm_winmm_in_dictionary;
 extern pm_fns_node pm_winmm_out_dictionary;
@@ -158,8 +164,8 @@ static void pm_winmm_general_inputs()
     UINT i;
     WORD wRtn;
     midi_num_inputs = midiInGetNumDevs();
-    midi_in_caps = pm_alloc(sizeof(MIDIINCAPS) * midi_num_inputs);
-
+    midi_in_caps = (MIDIINCAPS *) pm_alloc(sizeof(MIDIINCAPS) * 
+                                           midi_num_inputs);
     if (midi_in_caps == NULL) {
         /* if you can't open a particular system-level midi interface
          * (such as winmm), we just consider that system or API to be
@@ -575,11 +581,12 @@ static PmError winmm_in_open(PmInternal *midi, void *driverInfo)
      */
     InitializeCriticalSectionAndSpinCount(&m->lock, 4000);
     /* open device */
-    pm_hosterror = midiInOpen(&(m->handle.in),  /* input device handle */
-                              dwDevice,  /* device ID */
-                              (DWORD) winmm_in_callback,  /* callback address */
-                              (DWORD) midi,  /* callback instance data */
-                              CALLBACK_FUNCTION); /* callback is a procedure */
+    pm_hosterror = midiInOpen(
+	    &(m->handle.in),  /* input device handle */
+	    dwDevice,  /* device ID */
+	    (DWORD_PTR) winmm_in_callback,  /* callback address */
+	    (DWORD_PTR) midi,  /* callback instance data */
+	    CALLBACK_FUNCTION); /* callback is a procedure */
     if (pm_hosterror) goto free_descriptor;
 
     if (num_input_buffers < MIN_INPUT_BUFFERS)
@@ -668,22 +675,29 @@ static void FAR PASCAL winmm_in_callback(
     PmInternal *midi = (PmInternal *) dwInstance;
     midiwinmm_type m = (midiwinmm_type) midi->descriptor;
 
-    /* if this callback is reentered with data, we're in trouble. It's hard
-     * to imagine that Microsoft would allow callbacks to be reentrant --
-     * isn't the model that this is like a hardware interrupt? -- but I've
-     * seen reentrant behavior using a debugger, so it happens.
+    /* NOTE: we do not just EnterCriticalSection() here because an
+     * MIM_CLOSE message arrives when the port is closed, but then
+     * the m->lock has been destroyed.
      */
-    EnterCriticalSection(&m->lock);
 
     switch (wMsg) {
     case MIM_DATA: {
+        /* if this callback is reentered with data, we're in trouble. 
+         * It's hard to imagine that Microsoft would allow callbacks 
+         * to be reentrant -- isn't the model that this is like a 
+         * hardware interrupt? -- but I've seen reentrant behavior 
+         * using a debugger, so it happens.
+         */
+        long new_driver_time;
+        EnterCriticalSection(&m->lock);
+
         /* dwParam1 is MIDI data received, packed into DWORD w/ 1st byte of
                 message LOB;
            dwParam2 is time message received by input device driver, specified
             in [ms] from when midiInStart called.
            each message is expanded to include the status byte */
 
-        long new_driver_time = dwParam2;
+        new_driver_time = dwParam2;
 
         if ((dwParam1 & 0x80) == 0) {
             /* not a status byte -- ignore it. This happened running the
@@ -699,13 +713,16 @@ static void FAR PASCAL winmm_in_callback(
             event.message = dwParam1;
             pm_read_short(midi, &event);
         }
+        LeaveCriticalSection(&m->lock);
         break;
     }
     case MIM_LONGDATA: {
         MIDIHDR *lpMidiHdr = (MIDIHDR *) dwParam1;
-        unsigned char *data = lpMidiHdr->lpData;
+        unsigned char *data = (unsigned char *) lpMidiHdr->lpData;
         unsigned int processed = 0;
         int remaining = lpMidiHdr->dwBytesRecorded;
+
+        EnterCriticalSection(&m->lock);
         /* printf("midi_in_callback -- lpMidiHdr %x, %d bytes, %2x...\n", 
                 lpMidiHdr, lpMidiHdr->dwBytesRecorded, *data); */
         if (midi->time_proc)
@@ -718,56 +735,30 @@ static void FAR PASCAL winmm_in_callback(
             remaining -= amt;
             processed += amt;
         }
-#ifdef DELETE_THIS
-        unsigned int i = 0;
-        long size = sizeof(MIDIHDR) + lpMidiHdr->dwBufferLength;
-
-        while (i < lpMidiHdr->dwBytesRecorded) {
-            /* optimization: if message_count == 0, we are on an (output)
-             * message boundary so we can transfer data directly to the
-             * queue
-             */
-            PmEvent event;
-            if (midi->sysex_message_count == 0 &&
-                !midi->flush &&
-                i <= lpMidiHdr->dwBytesRecorded - 4 &&
-                ((event.message = (((long) data[0]) | 
-                        (((long) data[1]) << 8) | (((long) data[2]) << 16) |
-                        (((long) data[3]) << 24))) &
-                 0x80808080) == 0) { /* all data, no status */
-                event.timestamp = dwParam2;
-                if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
-                    midi->flush = TRUE;
-                }
-                i += 4;
-                data += 4;
-            /* non-optimized: process one byte at a time. This is used to 
-             * handle any embedded SYSEX or EOX bytes and to finish */
-            } else {
-                pm_read_byte(midi, *data, dwParam2);
-                data++;
-                i++;
-            }
-        }
-#endif
+
         /* when a device is closed, the pending MIM_LONGDATA buffers are
            returned to this callback with dwBytesRecorded == 0. In this
            case, we do not want to send them back to the interface (if
            we do, the interface will not close, and Windows OS may hang). */
         if (lpMidiHdr->dwBytesRecorded > 0) {
+            MMRESULT rslt;
             lpMidiHdr->dwBytesRecorded = 0;
             lpMidiHdr->dwFlags = 0;
+			
             /* note: no error checking -- can this actually fail? */
-            assert(midiInPrepareHeader(hMidiIn, lpMidiHdr, 
-                        sizeof(MIDIHDR)) == MMSYSERR_NOERROR);
+            rslt = midiInPrepareHeader(hMidiIn, lpMidiHdr, sizeof(MIDIHDR));
+            assert(rslt == MMSYSERR_NOERROR);
             /* note: I don't think this can fail except possibly for
              * MMSYSERR_NOMEM, but the pain of reporting this
              * unlikely but probably catastrophic error does not seem
              * worth it.
              */
-            assert(midiInAddBuffer(hMidiIn, lpMidiHdr, 
-                        sizeof(MIDIHDR)) == MMSYSERR_NOERROR);
+            rslt = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR));
+            assert(rslt == MMSYSERR_NOERROR);
+            LeaveCriticalSection(&m->lock);
         } else {
+            midiInUnprepareHeader(hMidiIn,lpMidiHdr,sizeof(MIDIHDR));
+            LeaveCriticalSection(&m->lock);
             pm_free(lpMidiHdr);
         }
         break;
@@ -785,7 +776,6 @@ static void FAR PASCAL winmm_in_callback(
     default:
         break;
     }
-    LeaveCriticalSection(&m->lock);
 }
 
 /*
@@ -874,20 +864,22 @@ static PmError winmm_out_open(PmInternal *midi, void *driverInfo)
     /* open device */
     if (midi->latency == 0) {
         /* use simple midi out calls */
-        pm_hosterror = midiOutOpen((LPHMIDIOUT) & m->handle.out,  /* device Handle */
-                                   dwDevice,  /* device ID  */
-                                   /* note: same callback fn as for StreamOpen: */
-                                   (DWORD) winmm_streamout_callback, /* callback fn */
-                                   (DWORD) midi,  /* callback instance data */
-                                   CALLBACK_FUNCTION); /* callback type */
+        pm_hosterror = midiOutOpen(
+                (LPHMIDIOUT) & m->handle.out,  /* device Handle */
+		dwDevice,  /* device ID  */
+		/* note: same callback fn as for StreamOpen: */
+		(DWORD_PTR) winmm_streamout_callback, /* callback fn */
+		(DWORD_PTR) midi,  /* callback instance data */
+		CALLBACK_FUNCTION); /* callback type */
     } else {
         /* use stream-based midi output (schedulable in future) */
-        pm_hosterror = midiStreamOpen(&m->handle.stream,  /* device Handle */
-                                      (LPUINT) & dwDevice,  /* device ID pointer */
-                                      1,  /* reserved, must be 1 */
-                                      (DWORD) winmm_streamout_callback,
-                                      (DWORD) midi,  /* callback instance data */
-                                      CALLBACK_FUNCTION);
+        pm_hosterror = midiStreamOpen(
+	        &m->handle.stream,  /* device Handle */
+		(LPUINT) & dwDevice,  /* device ID pointer */
+		1,  /* reserved, must be 1 */
+		(DWORD_PTR) winmm_streamout_callback,
+		(DWORD_PTR) midi,  /* callback instance data */
+		CALLBACK_FUNCTION);
     }
     if (pm_hosterror != MMSYSERR_NOERROR) {
         goto free_descriptor;
@@ -1215,7 +1207,7 @@ static PmError winmm_write_byte(PmInternal *midi, unsigned char byte,
     if (!hdr) {
         m->hdr = hdr = get_free_output_buffer(midi);
         assert(hdr);
-        midi->fill_base = m->hdr->lpData;
+        midi->fill_base = (unsigned char *) m->hdr->lpData;
         midi->fill_offset_ptr = &(hdr->dwBytesRecorded);
         /* when buffer fills, Pm_WriteSysEx will revert to calling
          * pmwin_write_byte, which expect to have space, so leave
@@ -1319,11 +1311,15 @@ static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg,
        buffers are free, so we need to do something to flag empty buffers if
        we leave them prepared
      */
+    /*
     printf("out_callback: hdr %x, wMsg %x, MOM_DONE %x\n", 
            hdr, wMsg, MOM_DONE);
-    if (wMsg == MOM_DONE)
-    assert(midiOutUnprepareHeader(m->handle.out, hdr,
-                        sizeof(MIDIHDR)) == MMSYSERR_NOERROR);
+    */
+    if (wMsg == MOM_DONE) {
+        MMRESULT ret = midiOutUnprepareHeader(m->handle.out, hdr, 
+                                              sizeof(MIDIHDR));
+        assert(ret == MMSYSERR_NOERROR);
+    }
     /* notify waiting sender that a buffer is available */
     err = SetEvent(m->buffer_signal);
     assert(err); /* false -> error */
@@ -1345,8 +1341,9 @@ static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg,
     /* printf("streamout_callback: hdr %x, wMsg %x, MOM_DONE %x\n", 
            hdr, wMsg, MOM_DONE); */
     if (wMsg == MOM_DONE) {
-        assert(midiOutUnprepareHeader(m->handle.out, hdr, 
-                    sizeof(MIDIHDR)) == MMSYSERR_NOERROR);
+        MMRESULT ret = midiOutUnprepareHeader(m->handle.out, hdr, 
+                                              sizeof(MIDIHDR));
+        assert(ret == MMSYSERR_NOERROR);
     }
     /* signal client in case it is blocked waiting for buffer */
     err = SetEvent(m->buffer_signal);
diff --git a/pd/portmidi/pm_win/pmwinmm.h b/pd/portmidi/pm_win/pmwinmm.h
old mode 100644
new mode 100755
diff --git a/pd/portmidi/pm_win/static.cmake b/pd/portmidi/pm_win/static.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..583b713f061e054699cd91d1b47ab55238c3d005
--- /dev/null
+++ b/pd/portmidi/pm_win/static.cmake
@@ -0,0 +1,16 @@
+# static.cmake -- change flags to link with static runtime libraries
+
+if(MSVC)
+  foreach(flag_var
+    CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+    CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO
+    CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
+    CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
+    if(${flag_var} MATCHES "/MD")
+      string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+    endif(${flag_var} MATCHES "/MD")
+  endforeach(flag_var)
+ 
+  message(STATUS 
+    "Note: overriding CMAKE_*_FLAGS_* to use Visual C static multithread library")
+endif(MSVC)
diff --git a/pd/portmidi/portmidi.sln b/pd/portmidi/portmidi.sln
new file mode 100755
index 0000000000000000000000000000000000000000..d33fe7fa662801cd31cad6ef77212227989093e1
--- /dev/null
+++ b/pd/portmidi/portmidi.sln
@@ -0,0 +1,147 @@
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ALL_BUILD", ".\ALL_BUILD.vcproj", "{E1C2664B-91BB-4D4F-868C-433164F81101}"
+	ProjectSection(ProjectDependencies) = postProject
+		{28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC}
+		{41D78CBF-B04B-4561-BA4A-AC238C40633D} = {41D78CBF-B04B-4561-BA4A-AC238C40633D}
+		{9B448D22-EC7E-4BD8-A552-B268D843CC3C} = {9B448D22-EC7E-4BD8-A552-B268D843CC3C}
+		{EED7440D-04E3-4948-92DB-C85B4ADB1D82} = {EED7440D-04E3-4948-92DB-C85B4ADB1D82}
+		{80193DD1-2C02-4A4C-BDF8-49623AD6F556} = {80193DD1-2C02-4A4C-BDF8-49623AD6F556}
+		{EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF} = {EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF}
+		{87B548BD-F5CE-4D1F-9181-390966AC5855} = {87B548BD-F5CE-4D1F-9181-390966AC5855}
+		{7283FAD1-7415-4061-A19A-FF5C7BCE9306} = {7283FAD1-7415-4061-A19A-FF5C7BCE9306}
+		{2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6}
+		{2204E68C-5C1F-440E-8CE6-7E273D4F6AD1} = {2204E68C-5C1F-440E-8CE6-7E273D4F6AD1}
+		{71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD} = {71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD}
+		{0BEACB8B-4058-41A4-A9DE-1B1FB650B21A} = {0BEACB8B-4058-41A4-A9DE-1B1FB650B21A}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", ".\ZERO_CHECK.vcproj", "{28779535-7541-4FF5-AC12-FAFD66E894EC}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "latency", "pm_test\latency.vcproj", "{41D78CBF-B04B-4561-BA4A-AC238C40633D}"
+	ProjectSection(ProjectDependencies) = postProject
+		{2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6}
+		{28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "midiclock", "pm_test\midiclock.vcproj", "{9B448D22-EC7E-4BD8-A552-B268D843CC3C}"
+	ProjectSection(ProjectDependencies) = postProject
+		{2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6}
+		{28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "midithread", "pm_test\midithread.vcproj", "{EED7440D-04E3-4948-92DB-C85B4ADB1D82}"
+	ProjectSection(ProjectDependencies) = postProject
+		{2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6}
+		{28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "midithru", "pm_test\midithru.vcproj", "{80193DD1-2C02-4A4C-BDF8-49623AD6F556}"
+	ProjectSection(ProjectDependencies) = postProject
+		{2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6}
+		{28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mm", "pm_test\mm.vcproj", "{EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF}"
+	ProjectSection(ProjectDependencies) = postProject
+		{2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6}
+		{28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmjni", "pm_common\pmjni.vcproj", "{87B548BD-F5CE-4D1F-9181-390966AC5855}"
+	ProjectSection(ProjectDependencies) = postProject
+		{28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portmidi-dynamic", "pm_dylib\portmidi-dynamic.vcproj", "{7283FAD1-7415-4061-A19A-FF5C7BCE9306}"
+	ProjectSection(ProjectDependencies) = postProject
+		{28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portmidi-static", "pm_common\portmidi-static.vcproj", "{2985D5DA-D91E-44E0-924B-E612B6AA33F6}"
+	ProjectSection(ProjectDependencies) = postProject
+		{28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qtest", "pm_test\qtest.vcproj", "{2204E68C-5C1F-440E-8CE6-7E273D4F6AD1}"
+	ProjectSection(ProjectDependencies) = postProject
+		{2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6}
+		{28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sysex", "pm_test\sysex.vcproj", "{71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD}"
+	ProjectSection(ProjectDependencies) = postProject
+		{2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6}
+		{28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "pm_test\test.vcproj", "{0BEACB8B-4058-41A4-A9DE-1B1FB650B21A}"
+	ProjectSection(ProjectDependencies) = postProject
+		{2985D5DA-D91E-44E0-924B-E612B6AA33F6} = {2985D5DA-D91E-44E0-924B-E612B6AA33F6}
+		{28779535-7541-4FF5-AC12-FAFD66E894EC} = {28779535-7541-4FF5-AC12-FAFD66E894EC}
+	EndProjectSection
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{E1C2664B-91BB-4D4F-868C-433164F81101}.Debug|Win32.ActiveCfg = Debug|Win32
+		{E1C2664B-91BB-4D4F-868C-433164F81101}.Release|Win32.ActiveCfg = Release|Win32
+		{28779535-7541-4FF5-AC12-FAFD66E894EC}.Debug|Win32.ActiveCfg = Debug|Win32
+		{28779535-7541-4FF5-AC12-FAFD66E894EC}.Debug|Win32.Build.0 = Debug|Win32
+		{28779535-7541-4FF5-AC12-FAFD66E894EC}.Release|Win32.ActiveCfg = Release|Win32
+		{28779535-7541-4FF5-AC12-FAFD66E894EC}.Release|Win32.Build.0 = Release|Win32
+		{41D78CBF-B04B-4561-BA4A-AC238C40633D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{41D78CBF-B04B-4561-BA4A-AC238C40633D}.Debug|Win32.Build.0 = Debug|Win32
+		{41D78CBF-B04B-4561-BA4A-AC238C40633D}.Release|Win32.ActiveCfg = Release|Win32
+		{41D78CBF-B04B-4561-BA4A-AC238C40633D}.Release|Win32.Build.0 = Release|Win32
+		{9B448D22-EC7E-4BD8-A552-B268D843CC3C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{9B448D22-EC7E-4BD8-A552-B268D843CC3C}.Debug|Win32.Build.0 = Debug|Win32
+		{9B448D22-EC7E-4BD8-A552-B268D843CC3C}.Release|Win32.ActiveCfg = Release|Win32
+		{9B448D22-EC7E-4BD8-A552-B268D843CC3C}.Release|Win32.Build.0 = Release|Win32
+		{EED7440D-04E3-4948-92DB-C85B4ADB1D82}.Debug|Win32.ActiveCfg = Debug|Win32
+		{EED7440D-04E3-4948-92DB-C85B4ADB1D82}.Debug|Win32.Build.0 = Debug|Win32
+		{EED7440D-04E3-4948-92DB-C85B4ADB1D82}.Release|Win32.ActiveCfg = Release|Win32
+		{EED7440D-04E3-4948-92DB-C85B4ADB1D82}.Release|Win32.Build.0 = Release|Win32
+		{80193DD1-2C02-4A4C-BDF8-49623AD6F556}.Debug|Win32.ActiveCfg = Debug|Win32
+		{80193DD1-2C02-4A4C-BDF8-49623AD6F556}.Debug|Win32.Build.0 = Debug|Win32
+		{80193DD1-2C02-4A4C-BDF8-49623AD6F556}.Release|Win32.ActiveCfg = Release|Win32
+		{80193DD1-2C02-4A4C-BDF8-49623AD6F556}.Release|Win32.Build.0 = Release|Win32
+		{EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF}.Debug|Win32.ActiveCfg = Debug|Win32
+		{EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF}.Debug|Win32.Build.0 = Debug|Win32
+		{EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF}.Release|Win32.ActiveCfg = Release|Win32
+		{EAADABB5-83D6-4669-98F8-6CDBE6AFD2BF}.Release|Win32.Build.0 = Release|Win32
+		{87B548BD-F5CE-4D1F-9181-390966AC5855}.Debug|Win32.ActiveCfg = Debug|Win32
+		{87B548BD-F5CE-4D1F-9181-390966AC5855}.Debug|Win32.Build.0 = Debug|Win32
+		{87B548BD-F5CE-4D1F-9181-390966AC5855}.Release|Win32.ActiveCfg = Release|Win32
+		{87B548BD-F5CE-4D1F-9181-390966AC5855}.Release|Win32.Build.0 = Release|Win32
+		{7283FAD1-7415-4061-A19A-FF5C7BCE9306}.Debug|Win32.ActiveCfg = Debug|Win32
+		{7283FAD1-7415-4061-A19A-FF5C7BCE9306}.Debug|Win32.Build.0 = Debug|Win32
+		{7283FAD1-7415-4061-A19A-FF5C7BCE9306}.Release|Win32.ActiveCfg = Release|Win32
+		{7283FAD1-7415-4061-A19A-FF5C7BCE9306}.Release|Win32.Build.0 = Release|Win32
+		{2985D5DA-D91E-44E0-924B-E612B6AA33F6}.Debug|Win32.ActiveCfg = Debug|Win32
+		{2985D5DA-D91E-44E0-924B-E612B6AA33F6}.Debug|Win32.Build.0 = Debug|Win32
+		{2985D5DA-D91E-44E0-924B-E612B6AA33F6}.Release|Win32.ActiveCfg = Release|Win32
+		{2985D5DA-D91E-44E0-924B-E612B6AA33F6}.Release|Win32.Build.0 = Release|Win32
+		{2204E68C-5C1F-440E-8CE6-7E273D4F6AD1}.Debug|Win32.ActiveCfg = Debug|Win32
+		{2204E68C-5C1F-440E-8CE6-7E273D4F6AD1}.Debug|Win32.Build.0 = Debug|Win32
+		{2204E68C-5C1F-440E-8CE6-7E273D4F6AD1}.Release|Win32.ActiveCfg = Release|Win32
+		{2204E68C-5C1F-440E-8CE6-7E273D4F6AD1}.Release|Win32.Build.0 = Release|Win32
+		{71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD}.Debug|Win32.ActiveCfg = Debug|Win32
+		{71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD}.Debug|Win32.Build.0 = Debug|Win32
+		{71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD}.Release|Win32.ActiveCfg = Release|Win32
+		{71B9BC6E-7B40-4FBC-BC7F-4372AF03D0FD}.Release|Win32.Build.0 = Release|Win32
+		{0BEACB8B-4058-41A4-A9DE-1B1FB650B21A}.Debug|Win32.ActiveCfg = Debug|Win32
+		{0BEACB8B-4058-41A4-A9DE-1B1FB650B21A}.Debug|Win32.Build.0 = Debug|Win32
+		{0BEACB8B-4058-41A4-A9DE-1B1FB650B21A}.Release|Win32.ActiveCfg = Release|Win32
+		{0BEACB8B-4058-41A4-A9DE-1B1FB650B21A}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+	EndGlobalSection
+	GlobalSection(ExtensibilityAddIns) = postSolution
+	EndGlobalSection
+EndGlobal
diff --git a/pd/portmidi/portmidi_cdt.zip b/pd/portmidi/portmidi_cdt.zip
new file mode 100644
index 0000000000000000000000000000000000000000..eaa2d7970cb8700ffb3b5579f128cbda2108a82c
Binary files /dev/null and b/pd/portmidi/portmidi_cdt.zip differ
diff --git a/pd/portmidi/portmusic_logo.png b/pd/portmidi/portmusic_logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..17a063a6ab93ce6976acf0de8fad8c30f23e7394
Binary files /dev/null and b/pd/portmidi/portmusic_logo.png differ
diff --git a/pd/portmidi/porttime/porttime-VC8.vcproj b/pd/portmidi/porttime/porttime-VC8.vcproj
new file mode 100644
index 0000000000000000000000000000000000000000..3a5cef47429c4ffa5e572eb78a5c3a117d92596d
--- /dev/null
+++ b/pd/portmidi/porttime/porttime-VC8.vcproj
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="porttime"
+	ProjectGUID="{338224B8-D575-408D-BACF-95C557B429BE}"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory=".\Release"
+			IntermediateDirectory=".\Release"
+			ConfigurationType="4"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="false"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				InlineFunctionExpansion="1"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+				StringPooling="true"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				PrecompiledHeaderFile=".\Release/porttime.pch"
+				AssemblerListingLocation=".\Release/"
+				ObjectFile=".\Release/"
+				ProgramDataBaseFileName=".\Release/"
+				WarningLevel="3"
+				SuppressStartupBanner="true"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="NDEBUG"
+				Culture="1033"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile=".\Release\porttime.lib"
+				SuppressStartupBanner="true"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+				SuppressStartupBanner="true"
+				OutputFile=".\Release/porttime.bsc"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory=".\Debug"
+			IntermediateDirectory=".\Debug"
+			ConfigurationType="4"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="false"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				PreprocessorDefinitions="_LIB;WIN32;_DEBUG"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				PrecompiledHeaderFile=".\Debug/porttime.pch"
+				AssemblerListingLocation=".\Debug/"
+				ObjectFile=".\Debug/"
+				ProgramDataBaseFileName=".\Debug/"
+				WarningLevel="3"
+				SuppressStartupBanner="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="_DEBUG"
+				Culture="1033"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile=".\Debug\porttime.lib"
+				SuppressStartupBanner="true"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+				SuppressStartupBanner="true"
+				OutputFile=".\Debug/porttime.bsc"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+			>
+			<File
+				RelativePath="porttime.c"
+				>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="ptwinmm.c"
+				>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl"
+			>
+			<File
+				RelativePath="porttime.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/porttime/porttime.c b/pd/portmidi/porttime/porttime.c
old mode 100644
new mode 100755
diff --git a/pd/portmidi/porttime/porttime.dsp b/pd/portmidi/porttime/porttime.dsp
old mode 100644
new mode 100755
diff --git a/pd/portmidi/porttime/porttime.h b/pd/portmidi/porttime/porttime.h
old mode 100644
new mode 100755
index 029ea7779c42288b5f10eaa0775fff32ab40dfbf..ff22de9d5ab5e6e89c48cf77d4fc714fd4c8adb8
--- a/pd/portmidi/porttime/porttime.h
+++ b/pd/portmidi/porttime/porttime.h
@@ -1,36 +1,92 @@
-/* porttime.h -- portable interface to millisecond timer */
-
-/* CHANGE LOG FOR PORTTIME
-  10-Jun-03 Mark Nelson & RBD
-    boost priority of timer thread in ptlinux.c implementation
- */
-
-/* Should there be a way to choose the source of time here? */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-typedef enum {
-    ptNoError = 0,
-    ptHostError = -10000,
-    ptAlreadyStarted,
-    ptAlreadyStopped,
-    ptInsufficientMemory
-} PtError;
-
-
-typedef long PtTimestamp;
-
-typedef void (PtCallback)( PtTimestamp timestamp, void *userData );
-
-
-PtError Pt_Start(int resolution, PtCallback *callback, void *userData);
-PtError Pt_Stop();
-int Pt_Started();
-PtTimestamp Pt_Time();
-
-#ifdef __cplusplus
-}
-#endif
+/* porttime.h -- portable interface to millisecond timer */
+
+/* CHANGE LOG FOR PORTTIME
+  10-Jun-03 Mark Nelson & RBD
+    boost priority of timer thread in ptlinux.c implementation
+ */
+
+/* Should there be a way to choose the source of time here? */
+
+#ifdef WIN32
+#ifndef INT32_DEFINED
+// rather than having users install a special .h file for windows, 
+// just put the required definitions inline here. portmidi.h uses
+// these too, so the definitions are (unfortunately) duplicated there
+typedef int int32_t;
+typedef unsigned int uint32_t;
+#define INT32_DEFINED
+#endif
+#else
+#include <stdint.h> // needed for int32_t
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef PMEXPORT
+#ifdef _WINDLL
+#define PMEXPORT __declspec(dllexport)
+#else
+#define PMEXPORT 
+#endif
+#endif
+
+typedef enum {
+    ptNoError = 0,         /* success */
+    ptHostError = -10000,  /* a system-specific error occurred */
+    ptAlreadyStarted,      /* cannot start timer because it is already started */
+    ptAlreadyStopped,      /* cannot stop timer because it is already stopped */
+    ptInsufficientMemory   /* memory could not be allocated */
+} PtError;
+
+
+typedef int32_t PtTimestamp;
+
+typedef void (PtCallback)( PtTimestamp timestamp, void *userData );
+
+/*
+    Pt_Start() starts a real-time service.
+
+    resolution is the timer resolution in ms. The time will advance every
+    resolution ms.
+
+    callback is a function pointer to be called every resolution ms.
+
+    userData is passed to callback as a parameter.
+
+    return value:
+    Upon success, returns ptNoError. See PtError for other values.
+*/
+PMEXPORT PtError Pt_Start(int resolution, PtCallback *callback, void *userData);
+
+/*
+    Pt_Stop() stops the timer.
+
+    return value:
+    Upon success, returns ptNoError. See PtError for other values.
+*/
+PMEXPORT PtError Pt_Stop();
+
+/*
+    Pt_Started() returns true iff the timer is running.
+*/
+PMEXPORT int Pt_Started();
+
+/* 
+    Pt_Time() returns the current time in ms.
+*/
+PMEXPORT PtTimestamp Pt_Time();
+
+/*
+    Pt_Sleep() pauses, allowing other threads to run.
+
+    duration is the length of the pause in ms. The true duration 
+    of the pause may be rounded to the nearest or next clock tick
+    as determined by resolution in Pt_Start().
+*/
+PMEXPORT void Pt_Sleep(int32_t duration);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/pd/portmidi/porttime/porttime.vcproj b/pd/portmidi/porttime/porttime.vcproj
new file mode 100755
index 0000000000000000000000000000000000000000..374ee5094795f606bcf797a3844b9397a4624bfe
--- /dev/null
+++ b/pd/portmidi/porttime/porttime.vcproj
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="PortTime"
+	ProjectGUID="{338224B8-D575-408D-BACF-95C557B429BE}"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="false"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				InlineFunctionExpansion="1"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+				StringPooling="true"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				PrecompiledHeaderFile=".\$(OutDir)\porttime.pch"
+				AssemblerListingLocation=".\$(OutDir)\"
+				ObjectFile=".\$(OutDir)\"
+				ProgramDataBaseFileName=".\$(OutDir)\"
+				WarningLevel="3"
+				SuppressStartupBanner="true"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="NDEBUG"
+				Culture="1033"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile=".\$(OutDir)\porttime.lib"
+				SuppressStartupBanner="true"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+				SuppressStartupBanner="true"
+				OutputFile=".\$(OutDir)\porttime.bsc"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+			UseOfMFC="0"
+			ATLMinimizesCRunTimeLibraryUsage="false"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				PreprocessorDefinitions="_LIB;WIN32;_DEBUG"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				PrecompiledHeaderFile=".\$(OutDir)\porttime.pch"
+				AssemblerListingLocation=".\$(OutDir)\"
+				ObjectFile=".\$(OutDir)\"
+				ProgramDataBaseFileName=".\$(OutDir)\"
+				WarningLevel="3"
+				SuppressStartupBanner="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="_DEBUG"
+				Culture="1033"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile=".\$(OutDir)\porttime.lib"
+				SuppressStartupBanner="true"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+				SuppressStartupBanner="true"
+				OutputFile=".\$(OutDir)\porttime.bsc"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<File
+			RelativePath=".\porttime.c"
+			>
+		</File>
+		<File
+			RelativePath=".\porttime.h"
+			>
+		</File>
+		<File
+			RelativePath=".\ptwinmm.c"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/pd/portmidi/porttime/ptlinux.c b/pd/portmidi/porttime/ptlinux.c
old mode 100644
new mode 100755
index 468575aa3e7191422fbd2a79d5393ec00d9aa196..077402f54ebcd2c2ebc9eb009b5e5fd0d01a681c
--- a/pd/portmidi/porttime/ptlinux.c
+++ b/pd/portmidi/porttime/ptlinux.c
@@ -40,6 +40,7 @@ CHANGE LOG
 static int time_started_flag = FALSE;
 static struct timeb time_offset = {0, 0, 0, 0};
 static pthread_t pt_thread_pid;
+static int pt_thread_created = FALSE;
 
 /* note that this is static data -- we only need one copy */
 typedef struct {
@@ -59,7 +60,7 @@ static void *Pt_CallbackProc(void *p)
     /* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id,
            parameters->id); */
     if (geteuid() == 0) setpriority(PRIO_PROCESS, 0, -20);
-	while (pt_callback_proc_id == parameters->id) {
+    while (pt_callback_proc_id == parameters->id) {
         /* wait for a multiple of resolution ms */
         struct timeval timeout;
         int delay = mytime++ * parameters->resolution - Pt_Time();
@@ -91,6 +92,7 @@ PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
         res = pthread_create(&pt_thread_pid, NULL, 
                              Pt_CallbackProc, parms);
         if (res != 0) return ptHostError;
+        pt_thread_created = TRUE;
     }
     time_started_flag = TRUE;
     return ptNoError;
@@ -101,7 +103,10 @@ PtError Pt_Stop()
 {
     /* printf("Pt_Stop called\n"); */
     pt_callback_proc_id++;
-    pthread_join(pt_thread_pid, NULL);
+    if (pt_thread_created) {
+        pthread_join(pt_thread_pid, NULL);
+        pt_thread_created = FALSE;
+    }
     time_started_flag = FALSE;
     return ptNoError;
 }
@@ -124,4 +129,10 @@ PtTimestamp Pt_Time()
 }
 
 
+void Pt_Sleep(int32_t duration)
+{
+    usleep(duration * 1000);
+}
+
+
 
diff --git a/pd/portmidi/porttime/ptmacosx_cf.c b/pd/portmidi/porttime/ptmacosx_cf.c
old mode 100644
new mode 100755
index c0c22a32e5966cb7b1917705a706fe373747a1b6..a174c864e01299eb29e935e4b11d3ed07562d6c1
--- a/pd/portmidi/porttime/ptmacosx_cf.c
+++ b/pd/portmidi/porttime/ptmacosx_cf.c
@@ -133,3 +133,8 @@ PtTimestamp Pt_Time()
     return (PtTimestamp) ((now - startTime) * 1000.0);
 }
 
+
+void Pt_Sleep(int32_t duration)
+{
+    usleep(duration * 1000);
+}
diff --git a/pd/portmidi/porttime/ptmacosx_mach.c b/pd/portmidi/porttime/ptmacosx_mach.c
old mode 100644
new mode 100755
index 37d4318b736b5c6c6918d60c11d4b8c804d7c793..753f5832ef427fe31d14c46ba614ae46883f451e
--- a/pd/portmidi/porttime/ptmacosx_mach.c
+++ b/pd/portmidi/porttime/ptmacosx_mach.c
@@ -8,6 +8,7 @@
 #import <mach/mach_error.h>
 #import <mach/mach_time.h>
 #import <mach/clock.h>
+#include <unistd.h>
 
 #include "porttime.h"
 #include "sys/time.h"
@@ -62,7 +63,7 @@ static void *Pt_CallbackProc(void *p)
         /* wait for a multiple of resolution ms */
         UInt64 wait_time;
         int delay = mytime++ * parameters->resolution - Pt_Time();
-	long timestamp;
+	PtTimestamp timestamp;
         if (delay < 0) delay = 0;
         wait_time = AudioConvertNanosToHostTime((UInt64)delay * NSEC_PER_MSEC);
         wait_time += AudioGetCurrentHostTime();
@@ -103,6 +104,7 @@ PtError Pt_Stop()
 {
     /* printf("Pt_Stop called\n"); */
     pt_callback_proc_id++;
+    pthread_join(pt_thread_pid, NULL);
     time_started_flag = FALSE;
     return ptNoError;
 }
@@ -122,3 +124,8 @@ PtTimestamp Pt_Time()
     return (PtTimestamp)(nsec_time / NSEC_PER_MSEC);
 }
 
+
+void Pt_Sleep(int32_t duration)
+{
+    usleep(duration * 1000);
+}
diff --git a/pd/portmidi/porttime/ptwinmm.c b/pd/portmidi/porttime/ptwinmm.c
old mode 100644
new mode 100755
index bbfebb0ec35d2471d689d16978e06a80f6370fea..52046592ccc56e4cacfacb9d4d4e870d1d81960d
--- a/pd/portmidi/porttime/ptwinmm.c
+++ b/pd/portmidi/porttime/ptwinmm.c
@@ -14,14 +14,14 @@ static long time_resolution;
 static MMRESULT timer_id;
 static PtCallback *time_callback;
 
-void CALLBACK winmm_time_callback(UINT uID, UINT uMsg, DWORD dwUser, 
-                                  DWORD dw1, DWORD dw2)
+void CALLBACK winmm_time_callback(UINT uID, UINT uMsg, DWORD_PTR dwUser, 
+                                  DWORD_PTR dw1, DWORD_PTR dw2)
 {
     (*time_callback)(Pt_Time(), (void *) dwUser);
 }
  
 
-PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
+PMEXPORT PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
 {
     if (time_started_flag) return ptAlreadyStarted;
     timeBeginPeriod(resolution);
@@ -31,14 +31,14 @@ PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
     time_callback = callback;
     if (callback) {
         timer_id = timeSetEvent(resolution, 1, winmm_time_callback, 
-            (DWORD) userData, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
+            (DWORD_PTR) userData, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
         if (!timer_id) return ptHostError;
     }
     return ptNoError;
 }
 
 
-PtError Pt_Stop()
+PMEXPORT PtError Pt_Stop()
 {
     if (!time_started_flag) return ptAlreadyStopped;
     if (time_callback && timer_id) {
@@ -52,14 +52,19 @@ PtError Pt_Stop()
 }
 
 
-int Pt_Started()
+PMEXPORT int Pt_Started()
 {
     return time_started_flag;
 }
 
 
-PtTimestamp Pt_Time()
+PMEXPORT PtTimestamp Pt_Time()
 {
     return timeGetTime() - time_offset;
 }
 
+
+PMEXPORT void Pt_Sleep(int32_t duration)
+{
+    Sleep(duration);
+}