new audio engine backend for native CoreAudio audio I/O, and PortMIDI for MIDI.
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 24 Feb 2014 19:39:10 +0000 (14:39 -0500)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 24 Feb 2014 19:49:13 +0000 (14:49 -0500)
Code builds, runs and functions. Full code review still pending, and some possibly changes to organization of code within the backend is possible

84 files changed:
libs/backends/wavesaudio/portmidi/pmutil.h [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/portmidi.h [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/porttime.h [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_common/pminternal.h [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_common/pmutil.c [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_common/portmidi.c [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/Makefile.osx [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/README_MAC.txt [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/finddefault.c [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.pbxproj [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/xcuserdata/VKamyshniy.xcuserdatad/UserInterfaceState.xcuserstate [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Assemble Application.xcscheme [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Compile Java.xcscheme [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/CopyJavaSources.xcscheme [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/JPortMidiHeaders.xcscheme [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/PmDefaults.xcscheme [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/build.xml [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/find-classrefs.sh [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Info.plist [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Manifest [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.c [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.h [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pmmacosxcm.c [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/pmmacosxcm.h [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/readbinaryplist.c [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_mac/readbinaryplist.h [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_win/pmwin.c [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.c [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.h [new file with mode: 0644]
libs/backends/wavesaudio/portmidi/src/porttime/ptmacosx_mach.c [new file with mode: 0644]
libs/backends/wavesaudio/waves_audiobackend.cc [new file with mode: 0644]
libs/backends/wavesaudio/waves_audiobackend.h [new file with mode: 0644]
libs/backends/wavesaudio/waves_audiobackend.latency.cc [new file with mode: 0644]
libs/backends/wavesaudio/waves_audiobackend.midi.cc [new file with mode: 0644]
libs/backends/wavesaudio/waves_audiobackend.port_engine.cc [new file with mode: 0644]
libs/backends/wavesaudio/waves_audioport.cc [new file with mode: 0644]
libs/backends/wavesaudio/waves_audioport.h [new file with mode: 0644]
libs/backends/wavesaudio/waves_dataport.cc [new file with mode: 0644]
libs/backends/wavesaudio/waves_dataport.h [new file with mode: 0644]
libs/backends/wavesaudio/waves_midi_buffer.cc [new file with mode: 0644]
libs/backends/wavesaudio/waves_midi_buffer.h [new file with mode: 0644]
libs/backends/wavesaudio/waves_midi_device.cc [new file with mode: 0644]
libs/backends/wavesaudio/waves_midi_device.h [new file with mode: 0644]
libs/backends/wavesaudio/waves_midi_device_manager.cc [new file with mode: 0644]
libs/backends/wavesaudio/waves_midi_device_manager.h [new file with mode: 0644]
libs/backends/wavesaudio/waves_midi_event.cc [new file with mode: 0644]
libs/backends/wavesaudio/waves_midi_event.h [new file with mode: 0644]
libs/backends/wavesaudio/waves_midiport.cc [new file with mode: 0644]
libs/backends/wavesaudio/waves_midiport.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/BasicTypes/WCFourCC.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/BasicTypes/WTByteOrder.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/BasicTypes/WUComPtr.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/BasicTypes/WUDefines.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/BasicTypes/WUMathConsts.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/BasicTypes/WUTypes.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/akupara/basics.hpp [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/akupara/compiletime_functions.hpp [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/akupara/threading/atomic_ops.hpp [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/akupara/threading/atomic_ops_gcc_x86.hpp [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/devicemanager/IncludeWindows.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.cpp [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.cpp [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/miscutils/MinMaxUtilities.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.cpp [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/miscutils/WCFixedString.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/miscutils/WUErrors.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/miscutils/safe_delete.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.cpp [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.cpp [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/wavespublicapi/1.0/WavesPublicAPI_Defines.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/wavespublicapi/WTErr.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/wavespublicapi/wstdint.h [new file with mode: 0644]
libs/backends/wavesaudio/wscript [new file with mode: 0644]

diff --git a/libs/backends/wavesaudio/portmidi/pmutil.h b/libs/backends/wavesaudio/portmidi/pmutil.h
new file mode 100644 (file)
index 0000000..40dabbf
--- /dev/null
@@ -0,0 +1,127 @@
+/* pmutil.h -- some helpful utilities for building midi \r
+               applications that use PortMidi \r
+ */\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+\r
+typedef void PmQueue;\r
+\r
+/*\r
+    A single-reader, single-writer queue is created by\r
+    Pm_QueueCreate(), which takes the number of messages and\r
+    the message size as parameters. The queue only accepts\r
+    fixed sized messages. Returns NULL if memory cannot be allocated.\r
+\r
+    This queue implementation uses the "light pipe" algorithm which\r
+    operates correctly even with multi-processors and out-of-order\r
+    memory writes. (see Alexander Dokumentov, "Lock-free Interprocess\r
+    Communication," Dr. Dobbs Portal, http://www.ddj.com/, \r
+    articleID=189401457, June 15, 2006. This algorithm requires\r
+    that messages be translated to a form where no words contain\r
+    zeros. Each word becomes its own "data valid" tag. Because of\r
+    this translation, we cannot return a pointer to data still in \r
+    the queue when the "peek" method is called. Instead, a buffer \r
+    is preallocated so that data can be copied there. Pm_QueuePeek() \r
+    dequeues a message into this buffer and returns a pointer to \r
+    it. A subsequent Pm_Dequeue() will copy from this buffer.\r
+\r
+    This implementation does not try to keep reader/writer data in\r
+    separate cache lines or prevent thrashing on cache lines. \r
+    However, this algorithm differs by doing inserts/removals in\r
+    units of messages rather than units of machine words. Some\r
+    performance improvement might be obtained by not clearing data\r
+    immediately after a read, but instead by waiting for the end\r
+    of the cache line, especially if messages are smaller than\r
+    cache lines. See the Dokumentov article for explanation.\r
+\r
+    The algorithm is extended to handle "overflow" reporting. To report\r
+    an overflow, the sender writes the current tail position to a field.\r
+    The receiver must acknowlege receipt by zeroing the field. The sender\r
+    will not send more until the field is zeroed.\r
+    \r
+    Pm_QueueDestroy() destroys the queue and frees its storage.\r
+ */\r
+\r
+PMEXPORT PmQueue *Pm_QueueCreate(long num_msgs, int32_t bytes_per_msg);\r
+PMEXPORT PmError Pm_QueueDestroy(PmQueue *queue);\r
+\r
+/* \r
+    Pm_Dequeue() removes one item from the queue, copying it into msg.\r
+    Returns 1 if successful, and 0 if the queue is empty.\r
+    Returns pmBufferOverflow if what would have been the next thing\r
+    in the queue was dropped due to overflow. (So when overflow occurs,\r
+    the receiver can receive a queue full of messages before getting the\r
+    overflow report. This protocol ensures that the reader will be \r
+    notified when data is lost due to overflow.\r
+ */\r
+PMEXPORT PmError Pm_Dequeue(PmQueue *queue, void *msg);\r
+\r
+\r
+/*\r
+    Pm_Enqueue() inserts one item into the queue, copying it from msg.\r
+    Returns pmNoError if successful and pmBufferOverflow if the queue was \r
+    already full. If pmBufferOverflow is returned, the overflow flag is set.\r
+ */\r
+PMEXPORT PmError Pm_Enqueue(PmQueue *queue, void *msg);\r
+\r
+\r
+/*\r
+    Pm_QueueFull() returns non-zero if the queue is full\r
+    Pm_QueueEmpty() returns non-zero if the queue is empty\r
+\r
+    Either condition may change immediately because a parallel\r
+    enqueue or dequeue operation could be in progress. Furthermore,\r
+    Pm_QueueEmpty() is optimistic: it may say false, when due to \r
+    out-of-order writes, the full message has not arrived. Therefore,\r
+    Pm_Dequeue() could still return 0 after Pm_QueueEmpty() returns\r
+    false. On the other hand, Pm_QueueFull() is pessimistic: if it\r
+    returns false, then Pm_Enqueue() is guaranteed to succeed. \r
+\r
+    Error conditions: Pm_QueueFull() returns pmBadPtr if queue is NULL.\r
+    Pm_QueueEmpty() returns FALSE if queue is NULL.\r
+ */\r
+PMEXPORT int Pm_QueueFull(PmQueue *queue);\r
+PMEXPORT int Pm_QueueEmpty(PmQueue *queue);\r
+\r
+\r
+/*\r
+    Pm_QueuePeek() returns a pointer to the item at the head of the queue,\r
+    or NULL if the queue is empty. The item is not removed from the queue.\r
+    Pm_QueuePeek() will not indicate when an overflow occurs. If you want\r
+    to get and check pmBufferOverflow messages, use the return value of\r
+    Pm_QueuePeek() *only* as an indication that you should call \r
+    Pm_Dequeue(). At the point where a direct call to Pm_Dequeue() would\r
+    return pmBufferOverflow, Pm_QueuePeek() will return NULL but internally\r
+    clear the pmBufferOverflow flag, enabling Pm_Enqueue() to resume\r
+    enqueuing messages. A subsequent call to Pm_QueuePeek()\r
+    will return a pointer to the first message *after* the overflow. \r
+    Using this as an indication to call Pm_Dequeue(), the first call\r
+    to Pm_Dequeue() will return pmBufferOverflow. The second call will\r
+    return success, copying the same message pointed to by the previous\r
+    Pm_QueuePeek().\r
+\r
+    When to use Pm_QueuePeek(): (1) when you need to look at the message\r
+    data to decide who should be called to receive it. (2) when you need\r
+    to know a message is ready but cannot accept the message.\r
+\r
+    Note that Pm_QueuePeek() is not a fast check, so if possible, you \r
+    might as well just call Pm_Dequeue() and accept the data if it is there.\r
+ */\r
+PMEXPORT void *Pm_QueuePeek(PmQueue *queue);\r
+\r
+/*\r
+    Pm_SetOverflow() allows the writer (enqueuer) to signal an overflow\r
+    condition to the reader (dequeuer). E.g. when transfering data from \r
+    the OS to an application, if the OS indicates a buffer overrun,\r
+    Pm_SetOverflow() can be used to insure that the reader receives a\r
+    pmBufferOverflow result from Pm_Dequeue(). Returns pmBadPtr if queue\r
+    is NULL, returns pmBufferOverflow if buffer is already in an overflow\r
+    state, returns pmNoError if successfully set overflow state.\r
+ */\r
+PMEXPORT PmError Pm_SetOverflow(PmQueue *queue);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
diff --git a/libs/backends/wavesaudio/portmidi/portmidi.h b/libs/backends/wavesaudio/portmidi/portmidi.h
new file mode 100644 (file)
index 0000000..e07991e
--- /dev/null
@@ -0,0 +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://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/libs/backends/wavesaudio/portmidi/porttime.h b/libs/backends/wavesaudio/portmidi/porttime.h
new file mode 100644 (file)
index 0000000..ff22de9
--- /dev/null
@@ -0,0 +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 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/libs/backends/wavesaudio/portmidi/src/pm_common/pminternal.h b/libs/backends/wavesaudio/portmidi/src/pm_common/pminternal.h
new file mode 100644 (file)
index 0000000..f7c6270
--- /dev/null
@@ -0,0 +1,178 @@
+/* pminternal.h -- header for interface implementations */\r
+\r
+/* this file is included by files that implement library internals */\r
+/* Here is a guide to implementers:\r
+     provide an initialization function similar to pm_winmm_init()\r
+     add your initialization function to pm_init()\r
+     Note that your init function should never require not-standard\r
+         libraries or fail in any way. If the interface is not available,\r
+         simply do not call pm_add_device. This means that non-standard\r
+         libraries should try to do dynamic linking at runtime using a DLL\r
+         and return without error if the DLL cannot be found or if there\r
+         is any other failure.\r
+     implement functions as indicated in pm_fns_type to open, read, write,\r
+         close, etc.\r
+     call pm_add_device() for each input and output device, passing it a\r
+         pm_fns_type structure.\r
+     assumptions about pm_fns_type functions are given below.\r
+ */\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+extern int pm_initialized; /* see note in portmidi.c */\r
+\r
+/* these are defined in system-specific file */\r
+void *pm_alloc(size_t s);\r
+void pm_free(void *ptr);\r
+\r
+/* if an error occurs while opening or closing a midi stream, set these: */\r
+extern int pm_hosterror;\r
+extern char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];\r
\r
+struct pm_internal_struct;\r
+\r
+/* these do not use PmInternal because it is not defined yet... */\r
+typedef PmError (*pm_write_short_fn)(struct pm_internal_struct *midi, \r
+                                     PmEvent *buffer);\r
+typedef PmError (*pm_begin_sysex_fn)(struct pm_internal_struct *midi,\r
+                                     PmTimestamp timestamp);\r
+typedef PmError (*pm_end_sysex_fn)(struct pm_internal_struct *midi,\r
+                                   PmTimestamp timestamp);\r
+typedef PmError (*pm_write_byte_fn)(struct pm_internal_struct *midi,\r
+                                    unsigned char byte, PmTimestamp timestamp);\r
+typedef PmError (*pm_write_realtime_fn)(struct pm_internal_struct *midi,\r
+                                        PmEvent *buffer);\r
+typedef PmError (*pm_write_flush_fn)(struct pm_internal_struct *midi,\r
+                                     PmTimestamp timestamp);\r
+typedef PmTimestamp (*pm_synchronize_fn)(struct pm_internal_struct *midi);\r
+/* pm_open_fn should clean up all memory and close the device if any part\r
+   of the open fails */\r
+typedef PmError (*pm_open_fn)(struct pm_internal_struct *midi,\r
+                              void *driverInfo);\r
+typedef PmError (*pm_abort_fn)(struct pm_internal_struct *midi);\r
+/* pm_close_fn should clean up all memory and close the device if any\r
+   part of the close fails. */\r
+typedef PmError (*pm_close_fn)(struct pm_internal_struct *midi);\r
+typedef PmError (*pm_poll_fn)(struct pm_internal_struct *midi);\r
+typedef void (*pm_host_error_fn)(struct pm_internal_struct *midi, char * msg,\r
+                                 unsigned int len);\r
+typedef unsigned int (*pm_has_host_error_fn)(struct pm_internal_struct *midi);\r
+\r
+typedef struct {\r
+    pm_write_short_fn write_short; /* output short MIDI msg */\r
+    pm_begin_sysex_fn begin_sysex; /* prepare to send a sysex message */\r
+    pm_end_sysex_fn end_sysex; /* marks end of sysex message */\r
+    pm_write_byte_fn write_byte; /* accumulate one more sysex byte */\r
+    pm_write_realtime_fn write_realtime; /* send real-time message within sysex */\r
+    pm_write_flush_fn write_flush; /* send any accumulated but unsent data */\r
+    pm_synchronize_fn synchronize; /* synchronize portmidi time to stream time */\r
+    pm_open_fn open;   /* open MIDI device */\r
+    pm_abort_fn abort; /* abort */\r
+    pm_close_fn close; /* close device */\r
+    pm_poll_fn poll;   /* read pending midi events into portmidi buffer */\r
+    pm_has_host_error_fn has_host_error; /* true when device has had host \r
+                                            error message */\r
+    pm_host_error_fn host_error; /* provide text readable host error message\r
+                                    for device (clears and resets) */\r
+} pm_fns_node, *pm_fns_type;\r
+\r
+\r
+/* when open fails, the dictionary gets this set of functions: */\r
+extern pm_fns_node pm_none_dictionary;\r
+\r
+typedef struct {\r
+    PmDeviceInfo pub; /* some portmidi state also saved in here (for autmatic\r
+                         device closing (see PmDeviceInfo struct) */\r
+    void *descriptor; /* ID number passed to win32 multimedia API open */\r
+    void *internalDescriptor; /* points to PmInternal device, allows automatic \r
+                                 device closing */\r
+    pm_fns_type dictionary;\r
+} descriptor_node, *descriptor_type;\r
+\r
+extern int pm_descriptor_max;\r
+extern descriptor_type descriptors;\r
+extern int pm_descriptor_index;\r
+\r
+typedef uint32_t (*time_get_proc_type)(void *time_info);\r
+\r
+typedef struct pm_internal_struct {\r
+    int device_id; /* which device is open (index to descriptors) */\r
+    short write_flag; /* MIDI_IN, or MIDI_OUT */\r
+    \r
+    PmTimeProcPtr time_proc; /* where to get the time */\r
+    void *time_info; /* pass this to get_time() */\r
+    int32_t buffer_len; /* how big is the buffer or queue? */\r
+    PmQueue *queue;\r
+\r
+    int32_t latency; /* time delay in ms between timestamps and actual output */\r
+                  /* set to zero to get immediate, simple blocking output */\r
+                  /* if latency is zero, timestamps will be ignored; */\r
+                  /* if midi input device, this field ignored */\r
+    \r
+    int sysex_in_progress; /* when sysex status is seen, this flag becomes\r
+        * true until EOX is seen. When true, new data is appended to the\r
+        * stream of outgoing bytes. When overflow occurs, sysex data is \r
+        * dropped (until an EOX or non-real-timei status byte is seen) so\r
+        * that, if the overflow condition is cleared, we don't start \r
+        * sending data from the middle of a sysex message. If a sysex\r
+        * message is filtered, sysex_in_progress is false, causing the\r
+        * message to be dropped. */\r
+    PmMessage sysex_message; /* buffer for 4 bytes of sysex data */\r
+    int sysex_message_count; /* how many bytes in sysex_message so far */\r
+\r
+    int32_t filters; /* flags that filter incoming message classes */\r
+    int32_t channel_mask; /* filter incoming messages based on channel */\r
+    PmTimestamp last_msg_time; /* timestamp of last message */\r
+    PmTimestamp sync_time; /* time of last synchronization */\r
+    PmTimestamp now; /* set by PmWrite to current time */\r
+    int first_message; /* initially true, used to run first synchronization */\r
+    pm_fns_type dictionary; /* implementation functions */\r
+    void *descriptor; /* system-dependent state */\r
+    /* the following are used to expedite sysex data */\r
+    /* on windows, in debug mode, based on some profiling, these optimizations\r
+     * cut the time to process sysex bytes from about 7.5 to 0.26 usec/byte,\r
+     * but this does not count time in the driver, so I don't know if it is\r
+     * important\r
+     */\r
+    unsigned char *fill_base; /* addr of ptr to sysex data */\r
+    uint32_t *fill_offset_ptr; /* offset of next sysex byte */\r
+    int32_t fill_length; /* how many sysex bytes to write */\r
+} PmInternal;\r
+\r
+\r
+/* defined by system specific implementation, e.g. pmwinmm, used by PortMidi */\r
+void pm_init(void); \r
+void pm_term(void); \r
+\r
+/* defined by portMidi, used by pmwinmm */\r
+PmError none_write_short(PmInternal *midi, PmEvent *buffer);\r
+PmError none_write_byte(PmInternal *midi, unsigned char byte, \r
+                        PmTimestamp timestamp);\r
+PmTimestamp none_synchronize(PmInternal *midi);\r
+\r
+PmError pm_fail_fn(PmInternal *midi);\r
+PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp);\r
+PmError pm_success_fn(PmInternal *midi);\r
+PmError pm_add_device(char *interf, char *name, int input, void *descriptor,\r
+                      pm_fns_type dictionary);\r
+uint32_t pm_read_bytes(PmInternal *midi, const unsigned char *data, int len,\r
+                           PmTimestamp timestamp);\r
+void pm_read_short(PmInternal *midi, PmEvent *event);\r
+\r
+#define none_write_flush pm_fail_timestamp_fn\r
+#define none_sysex pm_fail_timestamp_fn\r
+#define none_poll pm_fail_fn\r
+#define success_poll pm_success_fn\r
+\r
+#define MIDI_REALTIME_MASK 0xf8\r
+#define is_real_time(msg) \\r
+    ((Pm_MessageStatus(msg) & MIDI_REALTIME_MASK) == MIDI_REALTIME_MASK)\r
+\r
+int pm_find_default_device(char *pattern, int is_input);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_common/pmutil.c b/libs/backends/wavesaudio/portmidi/src/pm_common/pmutil.c
new file mode 100644 (file)
index 0000000..a70fe2f
--- /dev/null
@@ -0,0 +1,284 @@
+/* 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/libs/backends/wavesaudio/portmidi/src/pm_common/portmidi.c b/libs/backends/wavesaudio/portmidi/src/pm_common/portmidi.c
new file mode 100644 (file)
index 0000000..b716170
--- /dev/null
@@ -0,0 +1,1137 @@
+#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/libs/backends/wavesaudio/portmidi/src/pm_mac/Makefile.osx b/libs/backends/wavesaudio/portmidi/src/pm_mac/Makefile.osx
new file mode 100644 (file)
index 0000000..3832554
--- /dev/null
@@ -0,0 +1,129 @@
+# MAKEFILE FOR PORTMIDI\r
+\r
+# Roger B. Dannenberg\r
+# Sep 2009\r
+\r
+# NOTE: you can use\r
+#     make -f pm_osx/Makefile.osx configuration=Release\r
+# to override the default Debug configuration\r
+configuration=Release\r
+\r
+PF=/usr/local\r
+\r
+# For debugging, define PM_CHECK_ERRORS\r
+ifeq ($(configuration),Release)\r
+    CONFIG = Release\r
+else\r
+    CONFIG = Debug\r
+endif\r
+\r
+current: all\r
+\r
+all: $(CONFIG)/CMakeCache.txt\r
+       cd $(CONFIG); make\r
+\r
+$(CONFIG)/CMakeCache.txt:\r
+       rm -f CMakeCache.txt\r
+       mkdir -p $(CONFIG)\r
+       cd $(CONFIG); cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=$(CONFIG)\r
+\r
+\r
+**** For instructions: make -f pm_mac\Makefile.osx help ****\n'\r
+\r
+help:\r
+       echo $$'\n\n\\r
+This is help for portmidi/pm_mac/Makefile.osx\n\n\\r
+Installation path for dylib is $(PF)\n\\r
+To build Release version libraries and test applications,\n        \\r
+make -f pm_mac/Makefile.osx\n\\r
+To build Debug version libraries and test applications,\n        \\r
+make -f pm_mac/Makefile.osx configuration=Debug\n\\r
+To install universal dynamic library,\n        \\r
+sudo make -f pm_mac/Makefile.osx install\n\\r
+To install universal dynamic library with xcode,\n        \\r
+make -f pm_mac/Makefile.osx install-with-xcode\n\\r
+To make PmDefaults Java application,\n        \\r
+make -f pm_mac/Makefile.osx pmdefaults\n\n        \\r
+configuration = $(configuration)\n'\r
+\r
+\r
+clean:\r
+       rm -f *.o *~ core* */*.o */*/*.o */*~ */core* pm_test/*/pm_dll.dll \r
+       rm -f *.opt *.ncb *.plg pm_win/Debug/pm_dll.lib pm_win/Release/pm_dll.lib\r
+       rm -f pm_test/*.opt pm_test/*.ncb\r
+       rm -f pm_java/pmjni/*.o pm_java/pmjni/*~ pm_java/*.h\r
+       rm -rf Release/CMakeFiles Debug/CMakeFiles\r
+       rm -rf pm_mac/pmdefaults/lib pm_mac/pmdefaults/src\r
+\r
+cleaner: clean\r
+       rm -rf pm_mac/build\r
+       rm -rf pm_mac/Debug pm_mac/Release pm_test/Debug pm_test/Release\r
+       rm -f Debug/*.dylib Release/*.dylib\r
+       rm -f pm_java/pmjni/Debug/*.jnilib\r
+       rm -f pm_java/pmjni/Release/*.jnilib\r
+\r
+cleanest: cleaner\r
+       rm -f Debug/libportmidi_s.a Release/libportmidi_s.a\r
+       rm -f pm_test/Debug/test pm_test/Debug/sysex pm_test/Debug/midithread\r
+       rm -f pm_test/Debug/latency pm_test/Debug/midithru\r
+       rm -f pm_test/Debug/qtest pm_test/Debug/mm\r
+       rm -f pm_test/Release/test pm_test/Release/sysex pm_test/Release/midithread\r
+       rm -f pm_test/Release/latency pm_test/Release/midithru\r
+       rm -f pm_test/Release/qtest pm_test/Release/mm\r
+       rm -f pm_java/*/*.class\r
+       rm -f pm_java/pmjni/jportmidi_JPortMidiApi_PortMidiStream.h\r
+\r
+backup: cleanest\r
+       cd ..; zip -r portmidi.zip portmidi\r
+\r
+install: porttime/porttime.h pm_common/portmidi.h \\r
+          $(CONFIG)/libportmidi.dylib\r
+       install porttime/porttime.h  $(PF)/include/\r
+       install pm_common/portmidi.h $(PF)/include\r
+       install $(CONFIG)/libportmidi.dylib $(PF)/lib/\r
+\r
+# note - this uses xcode to build and install portmidi universal binaries\r
+install-with-xcode:\r
+       sudo xcodebuild -project pm_mac/pm_mac.xcodeproj \\r
+               -configuration Release install DSTROOT=/\r
+\r
+##### build pmdefault ######\r
+\r
+pm_java/pmjni/jportmidi_JPortMidiApi.h: pm_java/jportmidi/JPortMidiApi.class\r
+       cd pm_java; javah jportmidi.JPortMidiApi\r
+       mv pm_java/jportmidi_JportMidiApi.h pm_java/pmjni\r
+\r
+JAVASRC = pmdefaults/PmDefaultsFrame.java \\r
+           pmdefaults/PmDefaults.java \\r
+           jportmidi/JPortMidiApi.java jportmidi/JPortMidi.java \\r
+           jportmidi/JPortMidiException.java\r
+\r
+# this compiles ALL of the java code\r
+pm_java/jportmidi/JPortMidiApi.class: $(JAVASRC:%=pm_java/%)\r
+       cd pm_java; javac $(JAVASRC)\r
+\r
+$(CONFIG)/libpmjni.dylib:\r
+       mkdir -p $(CONFIG)\r
+       cd $(CONFIG); make -f ../pm_mac/$(MAKEFILE)\r
+\r
+pmdefaults: $(CONFIG)/libpmjni.dylib pm_java/jportmidi/JPortMidiApi.class\r
+ifeq ($(CONFIG),Debug)\r
+       echo "Error: you cannot build pmdefaults in a Debug configuration \n\\r
+    You should use configuration=Release in the Makefile command line. "\r
+       @exit 2\r
+endif\r
+       xcodebuild -project pm_mac/pm_mac.xcodeproj \\r
+            -configuration Release -target PmDefaults\r
+       echo "pmdefaults java application is made"\r
+\r
+###### test plist reader #######\r
+PLHDR = pm_mac/readbinaryplist.h\r
+PLSRC = pm_mac/plisttest.c pm_mac/readbinaryplist.c\r
+pm_mac/plisttest: $(PLHDR) $(PLSRC)\r
+       cc $(VFLAGS) -Ipm_mac \\r
+           -I/Developer/Headers/FlatCarbon \\r
+           -I/System/Library/Frameworks/CoreFoundation.framework/Headers \\r
+           -I/System/Library/Frameworks/CoreServices.framework/Headers \\r
+           $(PLSRC) -o pm_mac/$(CONFIG)/plisttest \\r
+           -framework CoreFoundation -framework CoreServices\r
+\r
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/README_MAC.txt b/libs/backends/wavesaudio/portmidi/src/pm_mac/README_MAC.txt
new file mode 100644 (file)
index 0000000..6fa6938
--- /dev/null
@@ -0,0 +1,163 @@
+README_MAC.txt for PortMidi\r
+Roger Dannenberg\r
+20 nov 2009\r
+revised 20 Sep 2010 for Xcode 3.2.4 and CMake 8.2-2\r
+\r
+To build PortMidi for Mac OS X, you must install Xcode and\r
+CMake.\r
+\r
+CMake can build either command-line Makefiles or Xcode projects.\r
+These approaches are described in separate sections below.\r
+\r
+==== CLEANING UP ====\r
+(Skip this for now, but later you might want start from a clean\r
+slate.)\r
+\r
+Start in the portmedia/portmidi directory.\r
+\r
+make -f pm_mac/Makefile.osx clean\r
+\r
+will remove .o, CMakeFiles, and other intermediate files.\r
+\r
+Using "cleaner" instead of "clean" will also remove jni-related \r
+intermediate files.\r
+\r
+Using "cleanest" instead of "clean" or "cleaner" will also remove\r
+application binaries and the portmidi libraries. (It will not \r
+uninstall anything, however.)\r
+\r
+==== USING CMAKE (AND COMMAND LINE TOOLS) ====\r
+\r
+Start in the portmedia/portmidi directory.\r
+\r
+make -f pm_mac/Makefile.osx\r
+\r
+(Begin note: make will invoke cmake to build a Makefile and then make to\r
+build portmidi. This extra level allows you to correctly build \r
+both Release and Debug versions. Release is the default, so to get\r
+the Debug version, use:\r
+\r
+make -f pm_mac/Makefile.osx configuration=Debug\r
+)\r
+\r
+Release version executables and libraries are now in\r
+    portmedia/portmidi/Release\r
+\r
+Debug version executables and libraries are created in\r
+    portmedia/portmidi/Debug\r
+The Debug versions are compiled with PM_CHECK_ERRORS which\r
+prints an error message and aborts when an error code is returned\r
+by PortMidi functions. This is useful for small command line \r
+applications. Otherwise, you should check and handle error returns\r
+in your program.\r
+\r
+You can install portmidi as follows:\r
+\r
+cd Release; sudo make install\r
+\r
+This will install /usr/local/include/{portmidi.h, porttime.h}\r
+and /usr/local/lib/{libportmidi.dylib, libportmidi_s.a, libpmjni.dylib}\r
+\r
+You should now make the pmdefaults.app:\r
+\r
+make -f pm_mac/Makefile.osx pmdefaults\r
+\r
+NOTE: pmdefaults.app will be in pm_mac/Release/. \r
+\r
+Please copy pmdefaults.app to your Applications folder or wherever \r
+you would normally expect to find it.\r
+\r
+==== USING CMAKE TO BUILD Xcode PROJECT ====\r
+\r
+Before you can use Xcode, you need a portmidi.xcodeproj file.\r
+CMake builds a location-dependent Xcode project, so unfortunately\r
+it is not easy to provide an Xcode project that is ready to use.\r
+Therefore, you should make your own. Once you have it, you can\r
+use it almost like any other Xcode project, and you will not have\r
+to go back to CMake.\r
+\r
+(1) Install CMake if you do not have it already.\r
+\r
+(2) Open portmedia/portmidi/CMakeLists.txt with CMake\r
+\r
+(3) Use Configure and Generate buttons\r
+\r
+(4) This creates portmedia/portmidi/portmidi.xcodeproj.\r
+\r
+Note: You will also use pm_mac/pm_mac.xcodeproj, which\r
+is not generated by CMake.\r
+\r
+(5) Open portmidi/portmidi.xcodeproj with Xcode and \r
+build what you need. The simplest thing is to build the\r
+ALL_BUILD target. The default will be to build the Debug\r
+version, but you may want to change this to Release. \r
+\r
+NOTE: ALL_BUILD may report errors. Try simply building again\r
+or rebuilding specific targets that fail until they build\r
+without errors. There appears to be a race condition or\r
+missing dependencies in the build system.\r
+\r
+The Debug version is compiled with PM_CHECK_ERRORS, and the\r
+Release version is not. PM_CHECK_ERRORS will print an error\r
+message and exit your program if any error is returned from\r
+a call into PortMidi.\r
+\r
+CMake (currently) also creates MinSizRel and RelWithDebInfo\r
+versions, but only because I cannot figure out how to disable\r
+them.\r
+\r
+You will probably want the application PmDefaults, which sets\r
+default MIDI In and Out devices for PortMidi. You may also\r
+want to build a Java application using PortMidi. Since I have\r
+not figured out how to use CMake to make an OS X Java application,\r
+use pm_mac/pm_mac.xcodeproj as follows:\r
+\r
+(6) open pm_mac/pm_mac.xcodeproj\r
+\r
+(7) pm_java/pmjni/portmidi_JportmidiApi.h is needed\r
+by libpmjni.jnilib, the Java native interface library. Since\r
+portmidi_JportmidiApi.h is included with PortMidi, you can skip\r
+to step 8, but if you really want to rebuild everything from \r
+scratch, build the JPortMidiHeaders project first, and continue\r
+with step 8:\r
+\r
+(8) If you did not build libpmjni.dylib using portmidi.xcodeproj,\r
+do it now. (It depends on portmidi_JportmidiApi.h, and the \r
+PmDefaults project depends on libpmjni.dylib.)\r
+\r
+(9) Returning to pm_mac.xcodeproj, build the PmDefaults program.\r
+\r
+(10) If you wish, copy pm_mac/build/Deployment/PmDefaults.app to\r
+your applications folder.\r
+\r
+(11) If you want to install libportmidi.dylib, first make it with \r
+Xcode, then\r
+    sudo make -f pm_mac/Makefile.osx install\r
+This command will install /usr/local/include/{porttime.h, portmidi.h} \r
+and /usr/local/lib/libportmidi.dylib\r
+Note that the "install" function of xcode creates portmidi/Release\r
+and does not install the library to /usr/local/lib, so please use\r
+the command line installer.\r
+\r
+\r
+CHANGELOG\r
+\r
+20-Sep-2010 Roger B. Dannenberg\r
+    Adapted to Xcode 3.2.4\r
+20-Nov-2009 Roger B. Dannenberg\r
+    Added some install instructions\r
+26-Sep-2009 Roger B. Dannenberg\r
+    More changes for using CMake, Makefiles, XCode\r
+20-Sep-2009 Roger B. Dannenberg\r
+    Modifications for using CMake\r
+14-Sep-2009 Roger B. Dannenberg\r
+    Modifications for using CMake\r
+17-Jan-2007 Roger B. Dannenberg\r
+    Explicit instructions for Xcode\r
+15-Jan-2007 Roger B. Dannenberg\r
+    Changed instructions because of changes to Makefile.osx\r
+07-Oct-2006 Roger B. Dannenberg\r
+    Added directions for xcodebuild\r
+29-aug-2006 Roger B. Dannenberg\r
+    Updated this documentation.\r
\r
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/finddefault.c b/libs/backends/wavesaudio/portmidi/src/pm_mac/finddefault.c
new file mode 100644 (file)
index 0000000..59e02a1
--- /dev/null
@@ -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/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.pbxproj b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.pbxproj
new file mode 100644 (file)
index 0000000..0d06e56
--- /dev/null
@@ -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/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644 (file)
index 0000000..570e6fa
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:pm_mac.xcodeproj">
+   </FileRef>
+</Workspace>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/xcuserdata/VKamyshniy.xcuserdatad/UserInterfaceState.xcuserstate b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/xcuserdata/VKamyshniy.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644 (file)
index 0000000..104c0fe
Binary files /dev/null and b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/xcuserdata/VKamyshniy.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Assemble Application.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Assemble Application.xcscheme
new file mode 100644 (file)
index 0000000..b2051a6
--- /dev/null
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0460"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "8D1107260486CEB800E47090"
+               BuildableName = "PmDefaults.app"
+               BlueprintName = "Assemble Application"
+               ReferencedContainer = "container:pm_mac.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <Testables>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "8D1107260486CEB800E47090"
+            BuildableName = "PmDefaults.app"
+            BlueprintName = "Assemble Application"
+            ReferencedContainer = "container:pm_mac.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Debug"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "8D1107260486CEB800E47090"
+            BuildableName = "PmDefaults.app"
+            BlueprintName = "Assemble Application"
+            ReferencedContainer = "container:pm_mac.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Release"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "8D1107260486CEB800E47090"
+            BuildableName = "PmDefaults.app"
+            BlueprintName = "Assemble Application"
+            ReferencedContainer = "container:pm_mac.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Compile Java.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Compile Java.xcscheme
new file mode 100644 (file)
index 0000000..415b487
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0460"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "89D0F0480F393A6F007831A7"
+               BuildableName = "Compile Java"
+               BlueprintName = "Compile Java"
+               ReferencedContainer = "container:pm_mac.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <Testables>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Debug"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      allowLocationSimulation = "YES">
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Release"
+      debugDocumentVersioning = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/CopyJavaSources.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/CopyJavaSources.xcscheme
new file mode 100644 (file)
index 0000000..ad37276
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0460"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "3DE2142D124662AA0033C839"
+               BuildableName = "CopyJavaSources"
+               BlueprintName = "CopyJavaSources"
+               ReferencedContainer = "container:pm_mac.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <Testables>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Debug"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      allowLocationSimulation = "YES">
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Release"
+      debugDocumentVersioning = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/JPortMidiHeaders.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/JPortMidiHeaders.xcscheme
new file mode 100644 (file)
index 0000000..de0f0bc
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0460"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "3D634CAB1247805C0020F829"
+               BuildableName = "JPortMidiHeaders"
+               BlueprintName = "JPortMidiHeaders"
+               ReferencedContainer = "container:pm_mac.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <Testables>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Debug"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      allowLocationSimulation = "YES">
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Release"
+      debugDocumentVersioning = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/PmDefaults.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/PmDefaults.xcscheme
new file mode 100644 (file)
index 0000000..23d63e9
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0460"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "89D0F1C90F3B704E007831A7"
+               BuildableName = "PmDefaults"
+               BlueprintName = "PmDefaults"
+               ReferencedContainer = "container:pm_mac.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <Testables>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Debug"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      allowLocationSimulation = "YES">
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Release"
+      debugDocumentVersioning = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/xcschememanagement.plist b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..a57f870
--- /dev/null
@@ -0,0 +1,62 @@
+<?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>SchemeUserState</key>
+       <dict>
+               <key>Assemble Application.xcscheme</key>
+               <dict>
+                       <key>orderHint</key>
+                       <integer>4</integer>
+               </dict>
+               <key>Compile Java.xcscheme</key>
+               <dict>
+                       <key>orderHint</key>
+                       <integer>3</integer>
+               </dict>
+               <key>CopyJavaSources.xcscheme</key>
+               <dict>
+                       <key>orderHint</key>
+                       <integer>2</integer>
+               </dict>
+               <key>JPortMidiHeaders.xcscheme</key>
+               <dict>
+                       <key>orderHint</key>
+                       <integer>0</integer>
+               </dict>
+               <key>PmDefaults.xcscheme</key>
+               <dict>
+                       <key>orderHint</key>
+                       <integer>1</integer>
+               </dict>
+       </dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>3D634CAB1247805C0020F829</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>3DE2142D124662AA0033C839</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>89D0F0480F393A6F007831A7</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>89D0F1C90F3B704E007831A7</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>8D1107260486CEB800E47090</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/build.xml b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/build.xml
new file mode 100644 (file)
index 0000000..bd08c68
--- /dev/null
@@ -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/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/find-classrefs.sh b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/find-classrefs.sh
new file mode 100644 (file)
index 0000000..2217580
--- /dev/null
@@ -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/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf
new file mode 100644 (file)
index 0000000..18f8378
--- /dev/null
@@ -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/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings
new file mode 100644 (file)
index 0000000..c7e5600
Binary files /dev/null and b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings differ
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Info.plist b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Info.plist
new file mode 100644 (file)
index 0000000..58bedb4
--- /dev/null
@@ -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/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Manifest b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Manifest
new file mode 100644 (file)
index 0000000..5dee9b0
--- /dev/null
@@ -0,0 +1 @@
+Main-Class: pmdefaults/PmDefaults
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.c b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.c
new file mode 100644 (file)
index 0000000..13ac683
--- /dev/null
@@ -0,0 +1,59 @@
+/* pmmac.c -- PortMidi os-dependent code */\r
+\r
+/* This file only needs to implement:\r
+pm_init(), which calls various routines to register the \r
+available midi devices,\r
+Pm_GetDefaultInputDeviceID(), and\r
+Pm_GetDefaultOutputDeviceID().\r
+It is seperate from pmmacosxcm because we might want to register\r
+non-CoreMIDI devices.\r
+*/\r
+\r
+#include "stdlib.h"\r
+#include "portmidi.h"\r
+#include "pmutil.h"\r
+#include "pminternal.h"\r
+#include "pmmacosxcm.h"\r
+\r
+PmDeviceID pm_default_input_device_id = -1;\r
+PmDeviceID pm_default_output_device_id = -1;\r
+\r
+void pm_init()\r
+{\r
+    PmError err = pm_macosxcm_init();\r
+    // this is set when we return to Pm_Initialize, but we need it\r
+    // now in order to (successfully) call Pm_CountDevices()\r
+    pm_initialized = TRUE;\r
+    if (!err) {\r
+        pm_default_input_device_id = find_default_device(\r
+                "/PortMidi/PM_RECOMMENDED_INPUT_DEVICE", TRUE, \r
+                pm_default_input_device_id);\r
+        pm_default_output_device_id = find_default_device(\r
+                "/PortMidi/PM_RECOMMENDED_OUTPUT_DEVICE", FALSE, \r
+                pm_default_output_device_id);\r
+    }\r
+}\r
+\r
+\r
+void pm_term(void)\r
+{\r
+    pm_macosxcm_term();\r
+}\r
+\r
+\r
+PmDeviceID Pm_GetDefaultInputDeviceID()\r
+{\r
+    Pm_Initialize();\r
+    return pm_default_input_device_id;\r
+}\r
+\r
+PmDeviceID Pm_GetDefaultOutputDeviceID() {\r
+    Pm_Initialize();\r
+    return pm_default_output_device_id;\r
+}\r
+\r
+void *pm_alloc(size_t s) { return malloc(s); }\r
+\r
+void pm_free(void *ptr) { free(ptr); }\r
+\r
+\r
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.h b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.h
new file mode 100644 (file)
index 0000000..2d71425
--- /dev/null
@@ -0,0 +1,4 @@
+/* pmmac.h */\r
+\r
+extern PmDeviceID pm_default_input_device_id;\r
+extern PmDeviceID pm_default_output_device_id;
\ No newline at end of file
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmacosxcm.c b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmacosxcm.c
new file mode 100644 (file)
index 0000000..7851357
--- /dev/null
@@ -0,0 +1,1010 @@
+/*
+ * Platform interface to the MacOS X CoreMIDI framework
+ * 
+ * Jon Parise <jparise at cmu.edu>
+ * and subsequent work by Andrew Zeldis and Zico Kolter
+ * and Roger B. Dannenberg
+ *
+ * $Id: pmmacosx.c,v 1.17 2002/01/27 02:40:40 jon Exp $
+ */
+/* Notes:
+    since the input and output streams are represented by MIDIEndpointRef
+    values and almost no other state, we store the MIDIEndpointRef on
+    descriptors[midi->device_id].descriptor. The only other state we need
+    is for errors: we need to know if there is an error and if so, what is
+    the error text. We use a structure with two kinds of
+    host error: "error" and "callback_error". That way, asynchronous callbacks
+    do not interfere with other error information.
+    
+    OS X does not seem to have an error-code-to-text function, so we will
+    just use text messages instead of error codes.
+ */
+
+#include <stdlib.h>
+
+//#define CM_DEBUG 1
+
+#include "portmidi.h"
+#include "pmutil.h"
+#include "pminternal.h"
+#include "porttime.h"
+#include "pmmac.h"
+#include "pmmacosxcm.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#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 the minimum timestamp allowed in the next packet. 
+
+     Note that this distorts accurate timestamps somewhat.
+ */
+#define LIMIT_RATE 1
+
+#define SYSEX_BUFFER_SIZE 128
+
+#define VERBOSE_ON 1
+#define VERBOSE if (VERBOSE_ON)
+
+#define MIDI_SYSEX      0xf0
+#define MIDI_EOX        0xf7
+#define MIDI_STATUS_MASK 0x80
+
+// "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 {
+    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 in host units*/
+    int first_message;  /* tells midi_write to sychronize timestamps */
+    int sysex_mode;     /* middle of sending sysex */
+    uint32_t sysex_word; /* accumulate data when receiving sysex */
+    uint32_t sysex_byte_count; /* count how many received */
+    char error[PM_HOST_ERROR_MSG_LEN];
+    char callback_error[PM_HOST_ERROR_MSG_LEN];
+    Byte packetBuffer[PACKET_BUFFER_SIZE];
+    MIDIPacketList *packetList; /* a pointer to packetBuffer */
+    MIDIPacket *packet;
+    Byte sysex_buffer[SYSEX_BUFFER_SIZE]; /* temp storage for sysex data */
+    MIDITimeStamp sysex_timestamp; /* timestamp to use with sysex data */
+    /* allow for running status (is running status possible here? -rbd): -cpr */
+    unsigned char last_command; 
+    int32_t last_msg_length;
+    /* limit midi data rate (a CoreMidi requirement): */
+    UInt64 min_next_time; /* when can the next send take place? */
+    int byte_count; /* how many bytes in the next packet list? */
+    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 */
+MIDITimeStamp timestamp_pm_to_cm(PmTimestamp timestamp);
+PmTimestamp timestamp_cm_to_pm(MIDITimeStamp timestamp);
+
+char* cm_get_full_endpoint_name(MIDIEndpointRef endpoint);
+
+
+static int
+midi_length(int32_t msg)
+{
+    int status, high, low;
+    static int high_lengths[] = {
+        1, 1, 1, 1, 1, 1, 1, 1,         /* 0x00 through 0x70 */
+        3, 3, 3, 3, 2, 2, 3, 1          /* 0x80 through 0xf0 */
+    };
+    static int low_lengths[] = {
+        1, 2, 3, 2, 1, 1, 1, 1,         /* 0xf0 through 0xf8 */
+        1, 1, 1, 1, 1, 1, 1, 1          /* 0xf9 through 0xff */
+    };
+
+    status = msg & 0xFF;
+    high = status >> 4;
+    low = status & 15;
+
+    return (high != 0xF) ? high_lengths[high] : low_lengths[low];
+}
+
+static PmTimestamp midi_synchronize(PmInternal *midi)
+{
+    midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
+    UInt64 pm_stream_time_2 = 
+            AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
+    PmTimestamp real_time;
+    UInt64 pm_stream_time;
+    /* if latency is zero and this is an output, there is no 
+       time reference and midi_synchronize should never be called */
+    assert(midi->time_proc);
+    assert(!(midi->write_flag && midi->latency == 0));
+    do {
+         /* read real_time between two reads of stream time */
+         pm_stream_time = pm_stream_time_2;
+         real_time = (*midi->time_proc)(midi->time_info);
+         pm_stream_time_2 = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
+         /* repeat if more than 0.5 ms has elapsed */
+    } while (pm_stream_time_2 > pm_stream_time + 500000);
+    m->delta = pm_stream_time - ((UInt64) real_time * (UInt64) 1000000);
+    m->sync_time = real_time;
+    return real_time;
+}
+
+
+static void
+process_packet(MIDIPacket *packet, PmEvent *event, 
+              PmInternal *midi, midi_macosxcm_type m)
+{
+    /* handle a packet of MIDI messages from CoreMIDI */
+    /* there may be multiple short messages in one packet (!) */
+    unsigned int remaining_length = packet->length;
+    unsigned char *cur_packet_data = packet->data;
+    while (remaining_length > 0) {
+        if (cur_packet_data[0] == MIDI_SYSEX ||
+            /* are we in the middle of a sysex message? */
+            (m->last_command == 0 &&
+             !(cur_packet_data[0] & MIDI_STATUS_MASK))) {
+            m->last_command = 0; /* no running status */
+            unsigned int amt = pm_read_bytes(midi, cur_packet_data, 
+                                             remaining_length, 
+                                             event->timestamp);
+            remaining_length -= amt;
+            cur_packet_data += amt;
+        } else if (cur_packet_data[0] == MIDI_EOX) {
+            /* this should never happen, because pm_read_bytes should
+             * get and read all EOX bytes*/
+            midi->sysex_in_progress = FALSE;
+            m->last_command = 0;
+        } else if (cur_packet_data[0] & MIDI_STATUS_MASK) {
+            /* compute the length of the next (short) msg in packet */
+           unsigned int cur_message_length = midi_length(cur_packet_data[0]);
+            if (cur_message_length > remaining_length) {
+#ifdef DEBUG
+                printf("PortMidi debug msg: not enough data");
+#endif
+               /* since there's no more data, we're done */
+               return;
+           }
+           m->last_msg_length = cur_message_length;
+           m->last_command = cur_packet_data[0];
+           switch (cur_message_length) {
+           case 1:
+               event->message = Pm_Message(cur_packet_data[0], 0, 0);
+               break; 
+           case 2:
+               event->message = Pm_Message(cur_packet_data[0], 
+                                           cur_packet_data[1], 0);
+               break;
+           case 3:
+               event->message = Pm_Message(cur_packet_data[0],
+                                           cur_packet_data[1], 
+                                           cur_packet_data[2]);
+               break;
+           default:
+                /* PortMIDI internal error; should never happen */
+                assert(cur_message_length == 1);
+               return; /* give up on packet if continued after assert */
+           }
+           pm_read_short(midi, event);
+           remaining_length -= m->last_msg_length;
+           cur_packet_data += m->last_msg_length;
+       } else if (m->last_msg_length > remaining_length + 1) {
+           /* we have running status, but not enough data */
+#ifdef DEBUG
+           printf("PortMidi debug msg: not enough data in CoreMIDI packet");
+#endif
+           /* since there's no more data, we're done */
+           return;
+       } else { /* output message using running status */
+           switch (m->last_msg_length) {
+           case 1:
+               event->message = Pm_Message(m->last_command, 0, 0);
+               break;
+           case 2:
+               event->message = Pm_Message(m->last_command, 
+                                           cur_packet_data[0], 0);
+               break;
+           case 3:
+               event->message = Pm_Message(m->last_command, 
+                                           cur_packet_data[0], 
+                                           cur_packet_data[1]);
+               break;
+           default:
+               /* last_msg_length is invalid -- internal PortMIDI error */
+               assert(m->last_msg_length == 1);
+           }
+           pm_read_short(midi, event);
+           remaining_length -= (m->last_msg_length - 1);
+           cur_packet_data += (m->last_msg_length - 1);
+       }
+    }
+}
+
+
+
+/* called when MIDI packets are received */
+static void
+readProc(const MIDIPacketList *newPackets, void *refCon, void *connRefCon)
+{
+    PmInternal *midi;
+    midi_macosxcm_type m;
+    PmEvent event;
+    MIDIPacket *packet;
+    unsigned int packetIndex;
+    uint32_t now;
+    unsigned int status;
+    
+#ifdef CM_DEBUG
+    printf("readProc: numPackets %d: ", newPackets->numPackets);
+#endif
+
+    /* Retrieve the context for this connection */
+    midi = (PmInternal *) connRefCon;
+    m = (midi_macosxcm_type) midi->descriptor;
+    assert(m);
+    
+    /* synchronize time references every 100ms */
+    now = (*midi->time_proc)(midi->time_info);
+    if (m->first_message || m->sync_time + 100 /*ms*/ < now) { 
+        /* time to resync */
+        now = midi_synchronize(midi);
+        m->first_message = FALSE;
+    }
+    
+    packet = (MIDIPacket *) &newPackets->packet[0];
+    /* printf("readproc packet status %x length %d\n", packet->data[0], 
+               packet->length); */
+    for (packetIndex = 0; packetIndex < newPackets->numPackets; packetIndex++) {
+        /* Set the timestamp and dispatch this message */
+        event.timestamp = (PmTimestamp) /* explicit conversion */ (
+                (AudioConvertHostTimeToNanos(packet->timeStamp) - m->delta) / 
+                (UInt64) 1000000);
+        status = packet->data[0];
+        /* process packet as sysex data if it begins with MIDI_SYSEX, or
+           MIDI_EOX or non-status byte with no running status */
+#ifdef CM_DEBUG
+        printf(" %d", packet->length);
+#endif
+        if (status == MIDI_SYSEX || status == MIDI_EOX || 
+            ((!(status & MIDI_STATUS_MASK)) && !m->last_command)) {
+           /* previously was: !(status & MIDI_STATUS_MASK)) {
+             * but this could mistake running status for sysex data
+             */
+            /* reset running status data -cpr */
+           m->last_command = 0;
+           m->last_msg_length = 0;
+            /* printf("sysex packet length: %d\n", packet->length); */
+            pm_read_bytes(midi, packet->data, packet->length, event.timestamp);
+        } else {
+            process_packet(packet, &event, midi, m);
+       }
+        packet = MIDIPacketNext(packet);
+    }
+#ifdef CM_DEBUG
+    printf("\n");
+#endif
+}
+
+static PmError
+midi_in_open(PmInternal *midi, void *driverInfo)
+{
+    MIDIEndpointRef endpoint;
+    midi_macosxcm_type m;
+    OSStatus macHostError;
+    
+    /* insure that we have a time_proc for timing */
+    if (midi->time_proc == NULL) {
+        if (!Pt_Started()) 
+            Pt_Start(1, 0, 0);
+        /* time_get does not take a parameter, so coerce */
+        midi->time_proc = (PmTimeProcPtr) Pt_Time;
+    }
+    endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
+    if (endpoint == NULL_REF) {
+        return pmInvalidDeviceId;
+    }
+
+    m = (midi_macosxcm_type) pm_alloc(sizeof(midi_macosxcm_node)); /* create */
+    midi->descriptor = m;
+    if (!m) {
+        return pmInsufficientMemory;
+    }
+    m->error[0] = 0;
+    m->callback_error[0] = 0;
+    m->sync_time = 0;
+    m->delta = 0;
+    m->last_time = 0;
+    m->first_message = TRUE;
+    m->sysex_mode = FALSE;
+    m->sysex_word = 0;
+    m->sysex_byte_count = 0;
+    m->packetList = NULL;
+    m->packet = NULL;
+    m->last_command = 0;
+    m->last_msg_length = 0;
+
+    macHostError = MIDIPortConnectSource(portIn, endpoint, midi);
+    if (macHostError != noErr) {
+        pm_hosterror = macHostError;
+        sprintf(pm_hosterror_text, 
+                "Host error %ld: MIDIPortConnectSource() in midi_in_open()",
+                (long) macHostError);
+        midi->descriptor = NULL;
+        pm_free(m);
+        return pmHostError;
+    }
+    
+    return pmNoError;
+}
+
+static PmError
+midi_in_close(PmInternal *midi)
+{
+    MIDIEndpointRef endpoint;
+    OSStatus macHostError;
+    PmError err = pmNoError;
+    
+    midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
+    
+    if (!m) return pmBadPtr;
+
+    endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
+    if (endpoint == NULL_REF) {
+        pm_hosterror = pmBadPtr;
+    }
+    
+    /* shut off the incoming messages before freeing data structures */
+    macHostError = MIDIPortDisconnectSource(portIn, endpoint);
+    if (macHostError != noErr) {
+        pm_hosterror = macHostError;
+        sprintf(pm_hosterror_text, 
+                "Host error %ld: MIDIPortDisconnectSource() in midi_in_close()",
+                (long) macHostError);
+        err = pmHostError;
+    }
+    
+    midi->descriptor = NULL;
+    pm_free(midi->descriptor);
+    
+    return err;
+}
+
+
+static PmError
+midi_out_open(PmInternal *midi, void *driverInfo)
+{
+    midi_macosxcm_type m;
+
+    m = (midi_macosxcm_type) pm_alloc(sizeof(midi_macosxcm_node)); /* create */
+    midi->descriptor = m;
+    if (!m) {
+        return pmInsufficientMemory;
+    }
+    m->error[0] = 0;
+    m->callback_error[0] = 0;
+    m->sync_time = 0;
+    m->delta = 0;
+    m->last_time = 0;
+    m->first_message = TRUE;
+    m->sysex_mode = FALSE;
+    m->sysex_word = 0;
+    m->sysex_byte_count = 0;
+    m->packetList = (MIDIPacketList *) m->packetBuffer;
+    m->packet = NULL;
+    m->last_command = 0;
+    m->last_msg_length = 0;
+    m->min_next_time = 0;
+    m->byte_count = 0;
+    m->us_per_host_tick = 1000000.0 / AudioGetHostClockFrequency();
+    m->host_ticks_per_byte = (UInt64) (1000000.0 / 
+                                       (m->us_per_host_tick * MAX_BYTES_PER_S));
+    return pmNoError;
+}
+
+
+static PmError
+midi_out_close(PmInternal *midi)
+{
+    midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
+    if (!m) return pmBadPtr;
+    
+    midi->descriptor = NULL;
+    pm_free(midi->descriptor);
+    
+    return pmNoError;
+}
+
+static PmError
+midi_abort(PmInternal *midi)
+{
+    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;
+}
+
+
+static PmError
+midi_write_flush(PmInternal *midi, PmTimestamp timestamp)
+{
+    OSStatus macHostError;
+    midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
+    MIDIEndpointRef endpoint = 
+            (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;
+    
+send_packet_error:
+    pm_hosterror = macHostError;
+    sprintf(pm_hosterror_text, 
+            "Host error %ld: MIDISend() in midi_write()",
+            (long) macHostError);
+    return pmHostError;
+
+}
+
+
+static PmError
+send_packet(PmInternal *midi, Byte *message, unsigned int messageLength, 
+            MIDITimeStamp timestamp)
+{
+    PmError err;
+    midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
+    assert(m);
+    
+    /* 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; 
+        /* timestamp is 0 because midi_write_flush ignores timestamp since
+         * timestamps are already in packets. The timestamp parameter is here
+         * because other API's need it. midi_write_flush can be called 
+         * from system-independent code that must be cross-API.
+         */
+        if ((err = midi_write_flush(midi, 0)) != pmNoError) return err;
+        m->packet = MIDIPacketListInit(m->packetList);
+        assert(m->packet); /* if this fails, it's a programming error */
+        m->packet = MIDIPacketListAdd(m->packetList, sizeof(m->packetBuffer),
+                                      m->packet, timestamp, messageLength, 
+                                      message);
+        assert(m->packet); /* can't run out of space on first message */           
+    }
+    return pmNoError;
+}    
+
+
+static PmError
+midi_write_short(PmInternal *midi, PmEvent *event)
+{
+    PmTimestamp when = event->timestamp;
+    PmMessage what = event->message;
+    MIDITimeStamp timestamp;
+    UInt64 when_ns;
+    midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
+    Byte message[4];
+    unsigned int messageLength;
+
+    if (m->packet == NULL) {
+        m->packet = MIDIPacketListInit(m->packetList);
+        /* this can never fail, right? failure would indicate something 
+           unrecoverable */
+        assert(m->packet);
+    }
+    
+    /* compute timestamp */
+    if (when == 0) when = midi->now;
+    /* if latency == 0, midi->now is not valid. We will just set it to zero */
+    if (midi->latency == 0) when = 0;
+    when_ns = ((UInt64) (when + midi->latency) * (UInt64) 1000000) + m->delta;
+    timestamp = (MIDITimeStamp) AudioConvertNanosToHostTime(when_ns);
+
+    message[0] = Pm_MessageStatus(what);
+    message[1] = Pm_MessageData1(what);
+    message[2] = Pm_MessageData2(what);
+    messageLength = midi_length(what);
+        
+    /* make sure we go foreward in time */
+    if (timestamp < m->min_next_time) timestamp = m->min_next_time;
+
+    #ifdef LIMIT_RATE
+        if (timestamp < m->last_time)
+            timestamp = m->last_time;
+       m->last_time = timestamp + messageLength * m->host_ticks_per_byte;
+    #endif
+
+    /* Add this message to the packet list */
+    return send_packet(midi, message, messageLength, timestamp);
+}
+
+
+static PmError 
+midi_begin_sysex(PmInternal *midi, PmTimestamp when)
+{
+    UInt64 when_ns;
+    midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
+    assert(m);
+    m->sysex_byte_count = 0;
+    
+    /* compute timestamp */
+    if (when == 0) when = midi->now;
+    /* if latency == 0, midi->now is not valid. We will just set it to zero */
+    if (midi->latency == 0) when = 0;
+    when_ns = ((UInt64) (when + midi->latency) * (UInt64) 1000000) + m->delta;
+    m->sysex_timestamp = (MIDITimeStamp) AudioConvertNanosToHostTime(when_ns);
+
+    if (m->packet == NULL) {
+        m->packet = MIDIPacketListInit(m->packetList);
+        /* this can never fail, right? failure would indicate something 
+           unrecoverable */
+        assert(m->packet);
+    }
+    return pmNoError;
+}
+
+
+static PmError
+midi_end_sysex(PmInternal *midi, PmTimestamp when)
+{
+    PmError err;
+    midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
+    assert(m);
+    
+    /* 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
+    
+    /* 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;
+    if (err != pmNoError) {
+        m->packet = NULL; /* flush everything in the packet list */
+        return err;
+    }
+    return pmNoError;
+}
+
+
+static PmError
+midi_write_byte(PmInternal *midi, unsigned char byte, PmTimestamp timestamp)
+{
+    midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
+    assert(m);
+    if (m->sysex_byte_count >= SYSEX_BUFFER_SIZE) {
+        PmError err = midi_end_sysex(midi, timestamp);
+        if (err != pmNoError) return err;
+    }
+    m->sysex_buffer[m->sysex_byte_count++] = byte;
+    return pmNoError;
+}
+
+
+static PmError
+midi_write_realtime(PmInternal *midi, PmEvent *event)
+{
+    /* to send a realtime message during a sysex message, first
+       flush all pending sysex bytes into packet list */
+    PmError err = midi_end_sysex(midi, 0);
+    if (err != pmNoError) return err;
+    /* then we can just do a normal midi_write_short */
+    return midi_write_short(midi, event);
+}
+
+static unsigned int midi_has_host_error(PmInternal *midi)
+{
+    midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
+    return (m->callback_error[0] != 0) || (m->error[0] != 0);
+}
+
+
+static void midi_get_host_error(PmInternal *midi, char *msg, unsigned int len)
+{
+    midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
+    msg[0] = 0; /* initialize to empty string */
+    if (m) { /* make sure there is an open device to examine */
+        if (m->error[0]) {
+            strncpy(msg, m->error, len);
+            m->error[0] = 0; /* clear the error */
+        } else if (m->callback_error[0]) {
+            strncpy(msg, m->callback_error, len);
+            m->callback_error[0] = 0; /* clear the error */
+        }
+        msg[len - 1] = 0; /* make sure string is terminated */
+    }
+}
+
+
+MIDITimeStamp timestamp_pm_to_cm(PmTimestamp timestamp)
+{
+    UInt64 nanos;
+    if (timestamp <= 0) {
+        return (MIDITimeStamp)0;
+    } else {
+        nanos = (UInt64)timestamp * (UInt64)1000000;
+        return (MIDITimeStamp)AudioConvertNanosToHostTime(nanos);
+    }
+}
+
+PmTimestamp timestamp_cm_to_pm(MIDITimeStamp timestamp)
+{
+    UInt64 nanos;
+    nanos = AudioConvertHostTimeToNanos(timestamp);
+    return (PmTimestamp)(nanos / (UInt64)1000000);
+}
+
+
+//
+// Code taken from http://developer.apple.com/qa/qa2004/qa1374.html
+//////////////////////////////////////
+// Obtain the name of an endpoint without regard for whether it has connections.
+// The result should be released by the caller.
+CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal)
+{
+  CFMutableStringRef result = CFStringCreateMutable(NULL, 0);
+  CFStringRef str;
+  
+  // begin with the endpoint's name
+  str = NULL;
+  MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &str);
+  if (str != NULL) {
+    CFStringAppend(result, str);
+    CFRelease(str);
+  }
+  
+  MIDIEntityRef entity = NULL_REF;
+  MIDIEndpointGetEntity(endpoint, &entity);
+  if (entity == NULL_REF)
+    // probably virtual
+    return result;
+  
+  if (CFStringGetLength(result) == 0) {
+    // endpoint name has zero length -- try the entity
+    str = NULL;
+    MIDIObjectGetStringProperty(entity, kMIDIPropertyName, &str);
+    if (str != NULL) {
+      CFStringAppend(result, str);
+      CFRelease(str);
+    }
+  }
+  // now consider the device's name
+  MIDIDeviceRef device = NULL_REF;
+  MIDIEntityGetDevice(entity, &device);
+  if (device == NULL_REF)
+    return result;
+  
+  str = NULL;
+  MIDIObjectGetStringProperty(device, kMIDIPropertyName, &str);
+  if (CFStringGetLength(result) == 0) {
+      CFRelease(result);
+      return str;
+  }
+  if (str != NULL) {
+    // if an external device has only one entity, throw away
+    // the endpoint name and just use the device name
+    if (isExternal && MIDIDeviceGetNumberOfEntities(device) < 2) {
+      CFRelease(result);
+      return str;
+    } else {
+      if (CFStringGetLength(str) == 0) {
+        CFRelease(str);
+        return result;
+      }
+      // does the entity name already start with the device name?
+      // (some drivers do this though they shouldn't)
+      // if so, do not prepend
+        if (CFStringCompareWithOptions( result, /* endpoint name */
+             str /* device name */,
+             CFRangeMake(0, CFStringGetLength(str)), 0) != kCFCompareEqualTo) {
+        // prepend the device name to the entity name
+        if (CFStringGetLength(result) > 0)
+          CFStringInsert(result, 0, CFSTR(" "));
+        CFStringInsert(result, 0, str);
+      }
+      CFRelease(str);
+    }
+  }
+  return result;
+}
+
+
+// Obtain the name of an endpoint, following connections.
+// The result should be released by the caller.
+static CFStringRef ConnectedEndpointName(MIDIEndpointRef endpoint)
+{
+  CFMutableStringRef result = CFStringCreateMutable(NULL, 0);
+  CFStringRef str;
+  OSStatus err;
+  long i;
+  
+  // Does the endpoint have connections?
+  CFDataRef connections = NULL;
+  long nConnected = 0;
+  bool anyStrings = false;
+  err = MIDIObjectGetDataProperty(endpoint, kMIDIPropertyConnectionUniqueID, &connections);
+  if (connections != NULL) {
+    // It has connections, follow them
+    // Concatenate the names of all connected devices
+    nConnected = CFDataGetLength(connections) / (int32_t) sizeof(MIDIUniqueID);
+    if (nConnected) {
+      const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections));
+      for (i = 0; i < nConnected; ++i, ++pid) {
+        MIDIUniqueID id = EndianS32_BtoN(*pid);
+        MIDIObjectRef connObject;
+        MIDIObjectType connObjectType;
+        err = MIDIObjectFindByUniqueID(id, &connObject, &connObjectType);
+        if (err == noErr) {
+          if (connObjectType == kMIDIObjectType_ExternalSource  ||
+              connObjectType == kMIDIObjectType_ExternalDestination) {
+            // Connected to an external device's endpoint (10.3 and later).
+            str = EndpointName((MIDIEndpointRef)(connObject), true);
+          } else {
+            // Connected to an external device (10.2) (or something else, catch-all)
+            str = NULL;
+            MIDIObjectGetStringProperty(connObject, kMIDIPropertyName, &str);
+          }
+          if (str != NULL) {
+            if (anyStrings)
+              CFStringAppend(result, CFSTR(", "));
+            else anyStrings = true;
+            CFStringAppend(result, str);
+            CFRelease(str);
+          }
+        }
+      }
+    }
+    CFRelease(connections);
+  }
+  if (anyStrings)
+    return result;
+  
+  // Here, either the endpoint had no connections, or we failed to obtain names for any of them.
+  return EndpointName(endpoint, false);
+}
+
+
+char* cm_get_full_endpoint_name(MIDIEndpointRef endpoint)
+{
+#ifdef OLDCODE
+    MIDIEntityRef entity;
+    MIDIDeviceRef device;
+
+    CFStringRef endpointName = NULL;
+    CFStringRef deviceName = NULL;
+#endif
+    CFStringRef fullName = NULL;
+    CFStringEncoding defaultEncoding;
+    char* newName;
+
+    /* get the default string encoding */
+    defaultEncoding = CFStringGetSystemEncoding();
+
+    fullName = ConnectedEndpointName(endpoint);
+    
+#ifdef OLDCODE
+    /* get the entity and device info */
+    MIDIEndpointGetEntity(endpoint, &entity);
+    MIDIEntityGetDevice(entity, &device);
+
+    /* create the nicely formated name */
+    MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &endpointName);
+    MIDIObjectGetStringProperty(device, kMIDIPropertyName, &deviceName);
+    if (deviceName != NULL) {
+        fullName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@: %@"),
+                                            deviceName, endpointName);
+    } else {
+        fullName = endpointName;
+    }
+#endif    
+    /* copy the string into our buffer */
+    newName = (char *) malloc(CFStringGetLength(fullName) + 1);
+    CFStringGetCString(fullName, newName, CFStringGetLength(fullName) + 1,
+                       defaultEncoding);
+
+    /* clean up */
+#ifdef OLDCODE
+    if (endpointName) CFRelease(endpointName);
+    if (deviceName) CFRelease(deviceName);
+#endif
+    if (fullName) CFRelease(fullName);
+
+    return newName;
+}
+
+
+pm_fns_node pm_macosx_in_dictionary = {
+    none_write_short,
+    none_sysex,
+    none_sysex,
+    none_write_byte,
+    none_write_short,
+    none_write_flush,
+    none_synchronize,
+    midi_in_open,
+    midi_abort,
+    midi_in_close,
+    success_poll,
+    midi_has_host_error,
+    midi_get_host_error,
+};
+
+pm_fns_node pm_macosx_out_dictionary = {
+    midi_write_short,
+    midi_begin_sysex,
+    midi_end_sysex,
+    midi_write_byte,
+    midi_write_realtime,
+    midi_write_flush,
+    midi_synchronize,
+    midi_out_open,
+    midi_abort,
+    midi_out_close,
+    success_poll,
+    midi_has_host_error,
+    midi_get_host_error,
+};
+
+
+PmError pm_macosxcm_init(void)
+{
+    ItemCount numInputs, numOutputs, numDevices;
+    MIDIEndpointRef endpoint;
+    int i;
+    OSStatus macHostError;
+    char *error_text;
+
+    /* Determine the number of MIDI devices on the system */
+    numDevices = MIDIGetNumberOfDevices();
+    numInputs = MIDIGetNumberOfSources();
+    numOutputs = MIDIGetNumberOfDestinations();
+
+    /* Return prematurely if no devices exist on the system
+       Note that this is not an error. There may be no devices.
+       Pm_CountDevices() will return zero, which is correct and
+       useful information
+     */
+    if (numDevices <= 0) {
+        return pmNoError;
+    }
+
+
+    /* Initialize the client handle */
+    macHostError = MIDIClientCreate(CFSTR("PortMidi"), NULL, NULL, &client);
+    if (macHostError != noErr) {
+        error_text = "MIDIClientCreate() in pm_macosxcm_init()";
+        goto error_return;
+    }
+
+    /* Create the input port */
+    macHostError = MIDIInputPortCreate(client, CFSTR("Input port"), readProc,
+                                          NULL, &portIn);
+    if (macHostError != noErr) {
+        error_text = "MIDIInputPortCreate() in pm_macosxcm_init()";
+        goto error_return;
+    }
+        
+    /* Create the output port */
+    macHostError = MIDIOutputPortCreate(client, CFSTR("Output port"), &portOut);
+    if (macHostError != noErr) {
+        error_text = "MIDIOutputPortCreate() in pm_macosxcm_init()";
+        goto error_return;
+    }
+
+    /* Iterate over the MIDI input devices */
+    for (i = 0; i < numInputs; i++) {
+        endpoint = MIDIGetSource(i);
+        if (endpoint == NULL_REF) {
+            continue;
+        }
+
+        /* set the first input we see to the default */
+        if (pm_default_input_device_id == -1)
+            pm_default_input_device_id = pm_descriptor_index;
+        
+        /* Register this device with PortMidi */
+        pm_add_device("CoreMIDI", cm_get_full_endpoint_name(endpoint),
+                      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_REF) {
+            continue;
+        }
+
+        /* set the first output we see to the default */
+        if (pm_default_output_device_id == -1)
+            pm_default_output_device_id = pm_descriptor_index;
+
+        /* Register this device with PortMidi */
+        pm_add_device("CoreMIDI", cm_get_full_endpoint_name(endpoint),
+                      FALSE, (void *) (long) endpoint,
+                      &pm_macosx_out_dictionary);
+    }
+    return pmNoError;
+    
+error_return:
+    pm_hosterror = macHostError;
+    sprintf(pm_hosterror_text, "Host error %ld: %s\n", (long) macHostError, 
+            error_text);
+    pm_macosxcm_term(); /* clear out any opened ports */
+    return pmHostError;
+}
+
+void pm_macosxcm_term(void)
+{
+    if (client != NULL_REF) MIDIClientDispose(client);
+    if (portIn != NULL_REF) MIDIPortDispose(portIn);
+    if (portOut != NULL_REF) MIDIPortDispose(portOut);
+}
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmacosxcm.h b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmacosxcm.h
new file mode 100644 (file)
index 0000000..97235b5
--- /dev/null
@@ -0,0 +1,6 @@
+/* system-specific definitions */\r
+\r
+PmError pm_macosxcm_init(void);\r
+void pm_macosxcm_term(void);\r
+\r
+PmDeviceID find_default_device(char *path, int input, PmDeviceID id);\r
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/readbinaryplist.c b/libs/backends/wavesaudio/portmidi/src/pm_mac/readbinaryplist.c
new file mode 100644 (file)
index 0000000..bccd095
--- /dev/null
@@ -0,0 +1,1115 @@
+/*\r
+\r
+readbinaryplist.c -- Roger B. Dannenberg, Jun 2008\r
+Based on ReadBinaryPList.m by Jens Ayton, 2007\r
+\r
+Note that this code is intended to read preference files and has an upper\r
+bound on file size (currently 100MB) and assumes in some places that 32 bit\r
+offsets are sufficient.\r
+\r
+Here are his comments:\r
+\r
+Reader for binary property list files (version 00).\r
+\r
+This has been found to work on all 566 binary plists in my ~/Library/Preferences/\r
+and /Library/Preferences/ directories. This probably does not provide full\r
+test coverage. It has also been found to provide different data to Apple's\r
+implementation when presented with a key-value archive. This is because Apple's\r
+implementation produces undocumented CFKeyArchiverUID objects. My implementation\r
+produces dictionaries instead, matching the in-file representation used in XML\r
+and OpenStep plists. See extract_uid().\r
+\r
+Full disclosure: in implementing this software, I read one comment and one\r
+struct defintion in CFLite, Apple's implementation, which is under the APSL\r
+license. I also deduced the information about CFKeyArchiverUID from that code.\r
+However, none of the implementation was copied.\r
+\r
+Copyright (C) 2007 Jens Ayton\r
+\r
+Permission is hereby granted, free of charge, to any person obtaining a copy\r
+of this software and associated documentation files (the "Software"), to deal\r
+in the Software without restriction, including without limitation the rights\r
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
+copies of the Software, and to permit persons to whom the Software is\r
+furnished to do so, subject to the following conditions:\r
+\r
+The above copyright notice and this permission notice shall be included in all\r
+copies or substantial portions of the Software.\r
+\r
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+SOFTWARE.\r
+\r
+*/\r
+\r
+/* A note about memory management:\r
+Strings and possibly other values are unique and because the values\r
+associated with IDs are cached, you end up with a directed graph rather\r
+than a tree. It is tricky to free the data because if you do a simple\r
+depth-first search to free nodes, you will free nodes twice. I decided\r
+to allocate memory from blocks of 1024 bytes and keep the blocks in a\r
+list associated with but private to this module. So the user should\r
+access this module by calling:\r
+    bplist_read_file() or bplist_read_user_pref() or \r
+    bplist_read_system_pref()\r
+which returns a value. When you are done with the value, call\r
+    bplist_free_data()\r
+This will of course free the value_ptr returned by bplist_read_*()\r
+\r
+To deal with memory exhaustion (what happens when malloc returns\r
+NULL?), use setjmp/longjmp -- a single setjmp protects the whole\r
+parser, and allocate uses longjmp to abort. After abort, memory\r
+is freed and NULL is returned to caller. There is not much here\r
+in the way of error reporting.\r
+\r
+Memory is obtained by calling allocate which either returns the\r
+memory requested or calls longjmp, so callers don't have to check.\r
+\r
+*/\r
+\r
+#include <sys/types.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <assert.h>\r
+#include <stdio.h>\r
+#include <sys/stat.h>\r
+#include "readbinaryplist.h"\r
+#include <Carbon/Carbon.h>\r
+\r
+#define NO 0\r
+#define YES 1\r
+#define BOOL int\r
+\r
+#define MAXPATHLEN 256\r
+\r
+/* there are 2 levels of error logging/printing:\r
+ *   BPLIST_LOG and BPLIST_LOG_VERBOSE\r
+ * either or both can be set to non-zero to turn on\r
+ * If BPLIST_LOG_VERBOSE is true, then BPLIST_LOG \r
+ * is also true.\r
+ * \r
+ * In the code, logging is done by calling either\r
+ * bplist_log() or bplist_log_verbose(), which take\r
+ * parameters like printf but might be a no-op.\r
+ */\r
\r
+/* #define BPLIST_LOG_VERBOSE 1 */\r
+\r
+#if BPLIST_LOG_VERBOSE\r
+    #ifndef BPLIST_LOG\r
+        #define BPLIST_LOG 1\r
+    #endif\r
+#endif\r
+\r
+#if BPLIST_LOG\r
+    #define bplist_log printf\r
+#else\r
+    #define bplist_log(...)\r
+#endif\r
+\r
+#if BPLIST_LOG_VERBOSE\r
+    #define bplist_log_verbose bplist_log\r
+#else\r
+    #define bplist_log_verbose(...)\r
+#endif\r
+\r
+\r
+/********* MEMORY MANAGEMENT ********/\r
+#define BLOCK_SIZE 1024\r
+// memory is aligned to multiples of this; assume malloc automatically\r
+// aligns to this number and assume this number is > sizeof(void *)\r
+#define ALIGNMENT 8\r
+static void *block_list = NULL;\r
+static char *free_ptr = NULL;\r
+static char *end_ptr = NULL;\r
+static jmp_buf abort_parsing;\r
+\r
+static void *allocate(size_t size)\r
+{\r
+    void *result;\r
+    if (free_ptr + size > end_ptr) {\r
+        size_t how_much = BLOCK_SIZE;\r
+        // align everything to 8 bytes\r
+        if (size > BLOCK_SIZE - ALIGNMENT) {\r
+            how_much = size + ALIGNMENT;\r
+        }\r
+        result = malloc(how_much);\r
+        if (result == NULL) {\r
+            /* serious problem */\r
+            longjmp(abort_parsing, 1);\r
+        }\r
+        *((void **)result) = block_list;\r
+        block_list = result;\r
+        free_ptr = ((char *) result) + ALIGNMENT;\r
+        end_ptr = ((char *) result) + how_much;\r
+    }\r
+    // now, there is enough rooom at free_ptr\r
+    result = free_ptr;\r
+    free_ptr += size;\r
+    return result;\r
+}\r
+\r
+void bplist_free_data()\r
+{\r
+    while (block_list) {\r
+        void *next = *(void **)block_list;\r
+        free(block_list);\r
+        block_list = next;\r
+    }\r
+    free_ptr = NULL;\r
+    end_ptr = NULL;\r
+}\r
+\r
+// layout of trailer -- last 32 bytes in plist data\r
+    uint8_t unused[6];\r
+    uint8_t offset_int_size;\r
+    uint8_t object_ref_size;\r
+    uint64_t object_count;\r
+    uint64_t top_level_object;\r
+    uint64_t offset_table_offset;\r
+\r
+\r
+enum\r
+{\r
+    kHEADER_SIZE = 8,\r
+    kTRAILER_SIZE = 32, //sizeof(bplist_trailer_node),\r
+    kMINIMUM_SANE_SIZE = kHEADER_SIZE + kTRAILER_SIZE\r
+};\r
+\r
+\r
+static const char kHEADER_BYTES[kHEADER_SIZE] = "bplist00";\r
+\r
+// map from UID key to previously parsed value\r
+typedef struct cache_struct {\r
+    uint64_t key;\r
+    value_ptr value;\r
+    struct cache_struct *next;\r
+} cache_node, *cache_ptr;\r
+\r
+\r
+typedef struct bplist_info\r
+{\r
+    uint64_t object_count;\r
+    const uint8_t *data_bytes;\r
+    uint64_t length;\r
+    uint64_t offset_table_offset;\r
+    uint8_t offset_int_size;\r
+    uint8_t object_ref_size;\r
+    cache_ptr cache;\r
+} bplist_info_node, *bplist_info_ptr;\r
+\r
+\r
+static value_ptr bplist_read_pldata(pldata_ptr data);\r
+static value_ptr bplist_read_pref(char *filename, OSType folder_type);\r
+static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset, uint8_t size);\r
+static uint64_t read_offset(bplist_info_ptr bplist, uint64_t index);\r
+static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset, uint64_t *outValue, size_t *outSize);\r
+\r
+static value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef);\r
+static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset);\r
+static value_ptr extract_int(bplist_info_ptr bplist, uint64_t offset);\r
+static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset);\r
+static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset);\r
+static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset);\r
+static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset);\r
+static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset);\r
+static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset);\r
+static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset);\r
+static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset);\r
+\r
+\r
+value_ptr value_create()\r
+{\r
+    value_ptr value = (value_ptr) allocate(sizeof(value_node));\r
+    return value;\r
+}\r
+\r
+\r
+void value_set_integer(value_ptr v, int64_t i) {\r
+    v->tag = kTAG_INT; v->integer = i;\r
+}\r
+\r
+void value_set_real(value_ptr v, double d) {\r
+    v->tag = kTAG_REAL; v->real = d;\r
+}\r
+\r
+// d is seconds since 1 January 2001\r
+void value_set_date(value_ptr v, double d) {\r
+    v->tag = kTAG_DATE; v->real = d;\r
+}\r
+\r
+void value_set_ascii_string(value_ptr v, const uint8_t *s, size_t len) {\r
+    v->tag = kTAG_ASCIISTRING;\r
+    v->string = (char *) allocate(len + 1);\r
+    memcpy(v->string, s, len);\r
+    v->string[len] = 0;\r
+}\r
+\r
+void value_set_unicode_string(value_ptr v, const uint8_t *s, size_t len) {\r
+    v->tag = kTAG_UNICODESTRING;\r
+    v->string = (char *) allocate(len + 1);\r
+    memcpy(v->string, s, len);\r
+    v->string[len] = 0;\r
+}\r
+\r
+void value_set_uid(value_ptr v, uint64_t uid)\r
+{\r
+    v->tag = kTAG_UID; v->uinteger = uid;\r
+}\r
+\r
+// v->data points to a pldata that points to the actual bytes\r
+// the bytes are copied, so caller must free byte source (*data)\r
+void value_set_data(value_ptr v, const uint8_t *data, size_t len) {\r
+    v->tag = kTAG_DATA;\r
+    pldata_ptr pldata = (pldata_ptr) allocate(sizeof(pldata_node));\r
+    pldata->data = (uint8_t *) allocate(len);\r
+    memcpy(pldata->data, data, len);\r
+    pldata->len = len;\r
+    v->data = pldata;\r
+    printf("value at %p gets data at %p\n", v, pldata);\r
+}\r
+\r
+// caller releases ownership of array to value_ptr v\r
+void value_set_array(value_ptr v, value_ptr *array, size_t length) {\r
+    array_ptr a = (array_ptr) allocate(sizeof(array_node));\r
+    a->array = array;\r
+    a->length = length;\r
+    v->tag = kTAG_ARRAY;\r
+    v->array = a;\r
+}\r
+\r
+// caller releases ownership of dict to value_ptr v\r
+void value_set_dict(value_ptr v, dict_ptr dict) {\r
+    v->tag = kTAG_DICTIONARY;\r
+    v->dict = dict;\r
+}\r
+\r
+\r
+// look up an objectref in the cache, a ref->value_ptr mapping\r
+value_ptr cache_lookup(cache_ptr cache, uint64_t ref)\r
+{\r
+    while (cache) {\r
+        if (cache->key == ref) {\r
+            return cache->value;\r
+        }\r
+        cache = cache->next;\r
+    }\r
+    return NULL;\r
+}\r
+\r
+\r
+// insert an objectref and value in the cache\r
+void cache_insert(cache_ptr *cache, uint64_t ref, value_ptr value)\r
+{\r
+    cache_ptr c = (cache_ptr) allocate(sizeof(cache_node));\r
+    c->key = ref;\r
+    c->value = value;\r
+    c->next = *cache;\r
+    *cache = c;\r
+}\r
+\r
+\r
+// insert an objectref and value in a dictionary\r
+void dict_insert(dict_ptr *dict, value_ptr key, value_ptr value)\r
+{\r
+    dict_ptr d = (dict_ptr) allocate(sizeof(dict_node));\r
+    d->key = key;\r
+    d->value = value;\r
+    d->next = *dict;\r
+    *dict = d;\r
+}\r
+\r
+\r
+BOOL is_binary_plist(pldata_ptr data)\r
+{\r
+    if (data->len < kMINIMUM_SANE_SIZE)  return NO;\r
+    return memcmp(data->data, kHEADER_BYTES, kHEADER_SIZE) == 0;\r
+}\r
+\r
+\r
+value_ptr bplist_read_file(char *filename)\r
+{\r
+    struct stat stbuf;\r
+    pldata_node pldata;\r
+    FILE *file;\r
+    size_t n;\r
+    value_ptr value;\r
+    int rslt = stat(filename, &stbuf);\r
+    if (rslt) {\r
+        #if BPLIST_LOG\r
+            perror("in stat");\r
+        #endif\r
+        bplist_log("Could not stat %s, error %d\n", filename, rslt);\r
+        return NULL;\r
+    }\r
+    // if file is >100MB, assume it is not a preferences file and give up\r
+    if (stbuf.st_size > 100000000) {\r
+        bplist_log("Large file %s encountered (%llu bytes) -- not read\n",\r
+                   filename, stbuf.st_size);\r
+        return NULL;\r
+    }\r
+    pldata.len = (size_t) stbuf.st_size;\r
+    // note: this is supposed to be malloc, not allocate. It is separate\r
+    // from the graph structure, large, and easy to free right after\r
+    // parsing.\r
+    pldata.data = (uint8_t *) malloc(pldata.len);\r
+    if (!pldata.data) {\r
+        bplist_log("Could not allocate %lu bytes for %s\n",\r
+                   (unsigned long) pldata.len, filename);\r
+        return NULL;\r
+    }\r
+    file = fopen(filename, "rb");\r
+    if (!file) {\r
+        bplist_log("Could not open %s\n", filename);\r
+        return NULL;\r
+    }\r
+    n = fread(pldata.data, 1, pldata.len, file);\r
+    if (n != pldata.len) {\r
+        bplist_log("Error reading from %s\n", filename);\r
+        return NULL;\r
+    }\r
+    value = bplist_read_pldata(&pldata);\r
+    free(pldata.data);\r
+    return value;\r
+}\r
+\r
+\r
+value_ptr bplist_read_pref(char *filename, OSType folder_type)\r
+{\r
+    FSRef prefdir;\r
+    char cstr[MAXPATHLEN];\r
+\r
+    OSErr err = FSFindFolder(kOnAppropriateDisk, folder_type,\r
+                             FALSE, &prefdir);\r
+    if (err) {\r
+        bplist_log("Error finding preferences folder: %d\n", err);\r
+        return NULL;\r
+    }\r
+    err = FSRefMakePath(&prefdir, (UInt8 *) cstr, (UInt32) (MAXPATHLEN - 1));\r
+    if (err) {\r
+        bplist_log("Error making path name for preferences folder: %d\n", err);\r
+        return NULL;\r
+    }\r
+    strlcat(cstr, "/", MAXPATHLEN);\r
+    strlcat(cstr, filename, MAXPATHLEN);\r
+    return bplist_read_file(cstr);\r
+}\r
+\r
+\r
+value_ptr bplist_read_system_pref(char *filename) {\r
+    return bplist_read_pref(filename, kSystemPreferencesFolderType);\r
+}\r
+\r
+\r
+value_ptr bplist_read_user_pref(char *filename) {\r
+    return bplist_read_pref(filename, kPreferencesFolderType);\r
+}\r
+\r
+\r
+// data is stored with high-order bytes first.\r
+// read from plist data in a machine-independent fashion\r
+//\r
+uint64_t convert_uint64(uint8_t *ptr)\r
+{\r
+    uint64_t rslt = 0;\r
+    int i;\r
+    // shift in bytes, high-order first\r
+    for (i = 0; i < sizeof(uint64_t); i++) {\r
+        rslt <<= 8;\r
+        rslt += ptr[i];\r
+    }\r
+    return rslt;\r
+}\r
+\r
+\r
+value_ptr bplist_read_pldata(pldata_ptr data)\r
+{\r
+    value_ptr result = NULL;\r
+    bplist_info_node bplist;\r
+    uint8_t *ptr;\r
+    uint64_t top_level_object;\r
+    int i;\r
+\r
+    if (data == NULL)  return NULL;\r
+    if (!is_binary_plist(data)) {\r
+        bplist_log("Bad binary plist: too short or invalid header.\n");\r
+        return NULL;\r
+    }\r
+        \r
+    // read trailer\r
+    ptr = (uint8_t *) (data->data + data->len - kTRAILER_SIZE);\r
+    bplist.offset_int_size = ptr[6];\r
+    bplist.object_ref_size = ptr[7];\r
+    bplist.object_count = convert_uint64(ptr + 8);\r
+    top_level_object = convert_uint64(ptr + 16);\r
+    bplist.offset_table_offset = convert_uint64(ptr + 24);\r
+        \r
+    // Basic sanity checks\r
+    if (bplist.offset_int_size < 1 || bplist.offset_int_size > 8 ||\r
+        bplist.object_ref_size < 1 || bplist.object_ref_size > 8 ||\r
+        bplist.offset_table_offset < kHEADER_SIZE) {\r
+        bplist_log("Bad binary plist: trailer declared insane.\n");\r
+        return NULL;                \r
+    }\r
+        \r
+    // Ensure offset table is inside file\r
+    uint64_t offsetTableSize = bplist.offset_int_size * bplist.object_count;\r
+    if (offsetTableSize + bplist.offset_table_offset + kTRAILER_SIZE > \r
+        data->len) {\r
+        bplist_log("Bad binary plist: offset table overlaps end of container.\n");\r
+        return NULL;\r
+    }\r
+        \r
+    bplist.data_bytes = data->data;\r
+    bplist.length = data->len;\r
+    bplist.cache = NULL; /* dictionary is empty */\r
+\r
+    bplist_log_verbose("Got a sane bplist with %llu items, offset_int_size: %u, object_ref_size: %u\n", \r
+                      bplist.object_count, bplist.offset_int_size, \r
+                      bplist.object_ref_size);\r
+    /* at this point, we are ready to do some parsing which allocates\r
+        memory for the result data structure. If memory allocation (using\r
+        allocate fails, a longjmp will return to here and we simply give up\r
+     */\r
+    i = setjmp(abort_parsing);\r
+    if (i == 0) {\r
+        result = extract_object(&bplist, top_level_object);\r
+    } else {\r
+        bplist_log("allocate() failed to allocate memory. Giving up.\n");\r
+        result = NULL;\r
+    }\r
+    if (!result) {\r
+        bplist_free_data();\r
+    }\r
+    return result;\r
+}\r
+\r
+\r
+static value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef)\r
+{\r
+    uint64_t offset;\r
+    value_ptr result = NULL;\r
+    uint8_t objectTag;\r
+    \r
+    if (objectRef >= bplist->object_count) {\r
+        // Out-of-range object reference.\r
+        bplist_log("Bad binary plist: object index is out of range.\n");\r
+        return NULL;\r
+    }\r
+        \r
+    // Use cached object if it exists\r
+    result = cache_lookup(bplist->cache, objectRef);\r
+    if (result != NULL)  return result;\r
+        \r
+    // Otherwise, find object in file.\r
+    offset = read_offset(bplist, objectRef);\r
+    if (offset > bplist->length) {\r
+        // Out-of-range offset.\r
+        bplist_log("Bad binary plist: object outside container.\n");\r
+        return NULL;\r
+    }\r
+    objectTag = *(bplist->data_bytes + offset);\r
+    switch (objectTag & 0xF0) {\r
+    case kTAG_SIMPLE:\r
+        result = extract_simple(bplist, offset);\r
+        break;\r
+                \r
+    case kTAG_INT:\r
+        result = extract_int(bplist, offset);\r
+        break;\r
+                        \r
+    case kTAG_REAL:\r
+        result = extract_real(bplist, offset);\r
+        break;\r
+                        \r
+    case kTAG_DATE:\r
+        result = extract_date(bplist, offset);\r
+        break;\r
+                        \r
+    case kTAG_DATA:\r
+        result = extract_data(bplist, offset);\r
+        break;\r
+                        \r
+    case kTAG_ASCIISTRING:\r
+        result = extract_ascii_string(bplist, offset);\r
+        break;\r
+                        \r
+    case kTAG_UNICODESTRING:\r
+        result = extract_unicode_string(bplist, offset);\r
+        break;\r
+        \r
+    case kTAG_UID:\r
+        result = extract_uid(bplist, offset);\r
+        break;\r
+        \r
+    case kTAG_ARRAY:\r
+        result = extract_array(bplist, offset);\r
+        break;\r
+        \r
+    case kTAG_DICTIONARY:\r
+        result = extract_dictionary(bplist, offset);\r
+        break;\r
+        \r
+    default:\r
+        // Unknown tag.\r
+        bplist_log("Bad binary plist: unknown tag 0x%X.\n", \r
+                   (objectTag & 0x0F) >> 4);\r
+        result = NULL;\r
+    }\r
+    \r
+    // Cache and return result.\r
+    if (result != NULL)  \r
+        cache_insert(&bplist->cache, objectRef, result);\r
+    return result;\r
+}\r
+\r
+\r
+static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset, \r
+                               uint8_t size)\r
+{\r
+    assert(bplist->data_bytes != NULL && size >= 1 && size <= 8 && \r
+           offset + size <= bplist->length);\r
+        \r
+    uint64_t result = 0;\r
+    const uint8_t *byte = bplist->data_bytes + offset;\r
+        \r
+    do {\r
+        // note that ints seem to be high-order first\r
+        result = (result << 8) | *byte++;\r
+    } while (--size);\r
+        \r
+    return result;\r
+}\r
+\r
+\r
+static uint64_t read_offset(bplist_info_ptr bplist, uint64_t index)\r
+{\r
+    assert(index < bplist->object_count);\r
+        \r
+    return read_sized_int(bplist, \r
+            bplist->offset_table_offset + bplist->offset_int_size * index, \r
+            bplist->offset_int_size);\r
+}\r
+\r
+\r
+static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset, \r
+                             uint64_t *outValue, size_t *outSize)\r
+{\r
+    uint32_t size;\r
+    int64_t value;\r
+        \r
+    assert(bplist->data_bytes != NULL && offset < bplist->length);\r
+        \r
+    size = 1 << (bplist->data_bytes[offset] & 0x0F);\r
+    if (size > 8) {\r
+        // Maximum allowable size in this implementation is 1<<3 = 8 bytes.\r
+        // This also happens to be the biggest we can handle.\r
+        return NO;\r
+    }\r
+        \r
+    if (offset + 1 + size > bplist->length) {\r
+        // Out of range.\r
+        return NO;\r
+    }\r
+        \r
+    value = read_sized_int(bplist, offset + 1, size);\r
+    \r
+    if (outValue != NULL) *outValue = value;\r
+    if (outSize != NULL) *outSize = size + 1; // +1 for tag byte.\r
+    return YES;\r
+}\r
+\r
+\r
+static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset)\r
+{\r
+    assert(bplist->data_bytes != NULL && offset < bplist->length);\r
+    value_ptr value = value_create();\r
+        \r
+    switch (bplist->data_bytes[offset]) {\r
+    case kVALUE_NULL:\r
+        value->tag = kVALUE_NULL;\r
+        return value;\r
+        \r
+    case kVALUE_TRUE:\r
+        value->tag = kVALUE_TRUE;\r
+        return value;\r
+                        \r
+    case kVALUE_FALSE:\r
+        value->tag = kVALUE_FALSE;\r
+        return value;\r
+    }\r
+        \r
+    // Note: kVALUE_FILLER is treated as invalid, because it, er, is.\r
+    bplist_log("Bad binary plist: invalid atom.\n");\r
+    free(value);\r
+    return NULL;\r
+}\r
+\r
+\r
+static value_ptr extract_int(bplist_info_ptr bplist, uint64_t offset)\r
+{\r
+    value_ptr value = value_create();\r
+    value->tag = kTAG_INT;\r
+\r
+    if (!read_self_sized_int(bplist, offset, &value->uinteger, NULL)) {\r
+        bplist_log("Bad binary plist: invalid integer object.\n");\r
+    }\r
+        \r
+    /* NOTE: originally, I sign-extended here. This was the wrong thing; it\r
+       turns out that negative ints are always stored as 64-bit, and smaller\r
+       ints are unsigned.\r
+    */\r
+    return value;\r
+}\r
+\r
+\r
+static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset)\r
+{\r
+    value_ptr value = value_create();\r
+    uint32_t size;\r
+        \r
+    assert(bplist->data_bytes != NULL && offset < bplist->length);\r
+    \r
+    size = 1 << (bplist->data_bytes[offset] & 0x0F);\r
+        \r
+    // FIXME: what to do if faced with other sizes for float/double?\r
+    assert (sizeof (float) == sizeof (uint32_t) && \r
+            sizeof (double) == sizeof (uint64_t));\r
+        \r
+    if (offset + 1 + size > bplist->length) {\r
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", \r
+                  "floating-point number");\r
+        free(value);\r
+        return NULL;\r
+    }\r
+        \r
+    if (size == sizeof (float)) {\r
+        // cast is ok because we know size is 4 bytes\r
+        uint32_t i = (uint32_t) read_sized_int(bplist, offset + 1, size); \r
+        // Note that this handles byte swapping.\r
+        value_set_real(value, *(float *)&i);\r
+        return value;\r
+    } else if (size == sizeof (double)) {\r
+        uint64_t i = read_sized_int(bplist, offset + 1, size);\r
+        // Note that this handles byte swapping.\r
+        value_set_real(value, *(double *)&i);\r
+        return value;\r
+    } else {\r
+        // Can't handle floats of other sizes.\r
+        bplist_log("Bad binary plist: can't handle %u-byte float.\n", size);\r
+        free(value);\r
+        return NULL;\r
+    }\r
+}\r
+\r
+\r
+static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset)\r
+{\r
+    value_ptr value;\r
+    assert(bplist->data_bytes != NULL && offset < bplist->length);\r
+        \r
+    // Data has size code like int and real, but only 3 (meaning 8 bytes) is valid.\r
+    if (bplist->data_bytes[offset] != kVALUE_FULLDATETAG) {\r
+        bplist_log("Bad binary plist: invalid size for date object.\n");\r
+        return NULL;\r
+    }\r
+        \r
+    if (offset + 1 + sizeof (double) > bplist->length) {\r
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", \r
+                  "date");\r
+        return NULL;\r
+    }\r
+        \r
+    // FIXME: what to do if faced with other sizes for double?\r
+    assert (sizeof (double) == sizeof (uint64_t));\r
+        \r
+    uint64_t date = read_sized_int(bplist, offset + 1, sizeof(double));\r
+    // Note that this handles byte swapping.\r
+    value = value_create();\r
+    value_set_date(value, *(double *)&date);\r
+    return value;\r
+}\r
+\r
+\r
+uint64_t bplist_get_a_size(bplist_info_ptr bplist, \r
+                           uint64_t *offset_ptr, char *msg)\r
+{\r
+    uint64_t size = bplist->data_bytes[*offset_ptr] & 0x0F;\r
+    (*offset_ptr)++;\r
+    if (size == 0x0F) {\r
+        // 0x0F means separate int size follows. \r
+        // Smaller values are used for short data.\r
+        size_t extra; // the length of the data size we are about to read\r
+        if ((bplist->data_bytes[*offset_ptr] & 0xF0) != kTAG_INT) {\r
+            // Bad data, mistagged size int\r
+            bplist_log("Bad binary plist: %s object size is not tagged as int.\n",\r
+                       msg);\r
+            return UINT64_MAX; // error\r
+        }\r
+                \r
+        // read integer data as size, extra tells how many bytes to skip\r
+        if (!read_self_sized_int(bplist, *offset_ptr, &size, &extra)) {\r
+            bplist_log("Bad binary plist: invalid %s object size tag.\n", \r
+                      "data");\r
+            return UINT64_MAX; // error\r
+        }\r
+        (*offset_ptr) += extra;\r
+    }\r
+\r
+    if (*offset_ptr + size > bplist->length) {\r
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", \r
+                  "data");\r
+        return UINT64_MAX; // error\r
+    }\r
+    return size;\r
+}\r
+\r
+\r
+static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset)\r
+{\r
+    uint64_t size;\r
+    value_ptr value;\r
+        \r
+    assert(bplist->data_bytes != NULL && offset < bplist->length);\r
+        \r
+    if ((size = bplist_get_a_size(bplist, &offset, "data")) == UINT64_MAX) \r
+        return NULL;\r
+        \r
+    value = value_create();\r
+    // cast is ok because we only allow files up to 100MB:\r
+    value_set_data(value, bplist->data_bytes + (size_t) offset, (size_t) size);\r
+    return value;\r
+}\r
+\r
+\r
+static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset)\r
+{\r
+    uint64_t size;\r
+    value_ptr value; // return value\r
+        \r
+    assert(bplist->data_bytes != NULL && offset < bplist->length);\r
+        \r
+    if ((size = bplist_get_a_size(bplist, &offset, "ascii string")) ==\r
+        UINT64_MAX) \r
+        return NULL;\r
+\r
+    value = value_create();\r
+    // cast is ok because we only allow 100MB files\r
+    value_set_ascii_string(value, bplist->data_bytes + (size_t) offset, \r
+                           (size_t) size);\r
+    return value;\r
+}\r
+\r
+\r
+static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset)\r
+{\r
+    uint64_t size;\r
+    value_ptr value;\r
+        \r
+    assert(bplist->data_bytes != NULL && offset < bplist->length);\r
+        \r
+    if ((size = bplist_get_a_size(bplist, &offset, "unicode string")) == \r
+        UINT64_MAX)\r
+        return NULL;\r
+        \r
+    value = value_create();\r
+    // cast is ok because we only allow 100MB files\r
+    value_set_unicode_string(value, bplist->data_bytes + (size_t) offset, \r
+                             (size_t) size);\r
+    return value;\r
+}\r
+\r
+\r
+static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset)\r
+{\r
+    /* UIDs are used by Cocoa's key-value coder.\r
+       When writing other plist formats, they are expanded to dictionaries of\r
+       the form <dict><key>CF$UID</key><integer>value</integer></dict>, so we\r
+       do the same here on reading. This results in plists identical to what\r
+       running plutil -convert xml1 gives us. However, this is not the same\r
+       result as [Core]Foundation's plist parser, which extracts them as un-\r
+       introspectable CF objects. In fact, it even seems to convert the CF$UID\r
+       dictionaries from XML plists on the fly.\r
+    */\r
+        \r
+    value_ptr value;\r
+    uint64_t uid;\r
+        \r
+    if (!read_self_sized_int(bplist, offset, &uid, NULL)) {\r
+        bplist_log("Bad binary plist: invalid UID object.\n");\r
+        return NULL;\r
+    }\r
+        \r
+    // assert(NO); // original code suggests using a string for a key\r
+    // but our dictionaries all use big ints for keys, so I don't know\r
+    // what to do here\r
+    \r
+    // In practice, I believe this code is never executed by PortMidi.\r
+    // I changed it to do something and not raise compiler warnings, but\r
+    // not sure what the code should do.\r
+\r
+    value = value_create();\r
+    value_set_uid(value, uid);\r
+    // return [NSDictionary dictionaryWithObject:\r
+    //         [NSNumber numberWithUnsignedLongLong:value] \r
+    //         forKey:"CF$UID"];\r
+    return value;\r
+}\r
+\r
+\r
+static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset)\r
+{\r
+    uint64_t i, count;\r
+    uint64_t size;\r
+    uint64_t elementID;\r
+    value_ptr element = NULL;\r
+    value_ptr *array = NULL;\r
+    value_ptr value = NULL;\r
+    BOOL ok = YES;\r
+        \r
+    assert(bplist->data_bytes != NULL && offset < bplist->length);\r
+        \r
+    if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX)\r
+        return NULL;\r
+        \r
+    if (count > UINT64_MAX / bplist->object_ref_size - offset) {\r
+        // Offset overflow.\r
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", \r
+                   "array");\r
+        return NULL;\r
+    }\r
+        \r
+    size = bplist->object_ref_size * count;\r
+    if (size + offset > bplist->length) {\r
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", \r
+                   "array");\r
+        return NULL;\r
+    }\r
+        \r
+    // got count, the number of array elements\r
+\r
+    value = value_create();\r
+    assert(value);\r
+\r
+    if (count == 0) {\r
+        // count must be size_t or smaller because max file size is 100MB\r
+        value_set_array(value, array, (size_t) count);\r
+        return value;\r
+    }\r
+        \r
+    array = allocate(sizeof(value_ptr) * (size_t) count);\r
+        \r
+    for (i = 0; i != count; ++i) {\r
+        bplist_log_verbose("[%u]\n", i);\r
+        elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size, \r
+                                 bplist->object_ref_size);\r
+        element = extract_object(bplist, elementID);\r
+        if (element != NULL) {\r
+            array[i] = element;\r
+        } else {\r
+            ok = NO;\r
+            break;\r
+        }\r
+    }\r
+    if (ok) { // count is smaller than size_t max because of 100MB file limit\r
+        value_set_array(value, array, (size_t) count);\r
+    }\r
+\r
+    return value;\r
+}\r
+\r
+\r
+static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset)\r
+{\r
+    uint64_t i, count;\r
+    uint64_t size;\r
+    uint64_t elementID;\r
+    value_ptr value = NULL;\r
+    dict_ptr dict = NULL;\r
+    BOOL ok = YES;\r
+        \r
+    assert(bplist->data_bytes != NULL && offset < bplist->length);\r
+        \r
+        \r
+    if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX)\r
+        return NULL;\r
+\r
+    if (count > UINT64_MAX / (bplist->object_ref_size * 2) - offset) {\r
+        // Offset overflow.\r
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", \r
+                   "dictionary");\r
+        return NULL;\r
+    }\r
+    \r
+    size = bplist->object_ref_size * count * 2;\r
+    if (size + offset > bplist->length) {\r
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", \r
+                   "dictionary");\r
+        return NULL;\r
+    }\r
+    \r
+    value = value_create();\r
+    if (count == 0) {\r
+        value_set_dict(value, NULL);\r
+        return value;\r
+    }\r
+\r
+    for (i = 0; i != count; ++i) {\r
+        value_ptr key;\r
+        value_ptr val;\r
+        elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size, \r
+                                 bplist->object_ref_size);\r
+        key = extract_object(bplist, elementID);\r
+        if (key != NULL) {\r
+            bplist_log_verbose("key: %p\n", key);\r
+        } else {\r
+            ok = NO;\r
+            break;\r
+        }\r
+                    \r
+        elementID = read_sized_int(bplist, \r
+                            offset + (i + count) * bplist->object_ref_size, \r
+                            bplist->object_ref_size);\r
+        val = extract_object(bplist, elementID);\r
+        if (val != NULL) {\r
+            dict_insert(&dict, key, val);\r
+        } else {\r
+            ok = NO;\r
+            break;\r
+        }\r
+    }\r
+    if (ok) {\r
+        value_set_dict(value, dict);\r
+    }\r
+    \r
+    return value;\r
+}\r
+\r
+/*************** functions for accessing values ****************/\r
+\r
+\r
+char *value_get_asciistring(value_ptr v)\r
+{\r
+    if (v->tag != kTAG_ASCIISTRING) return NULL;\r
+    return v->string;\r
+}\r
+\r
+\r
+value_ptr value_dict_lookup_using_string(value_ptr v, char *key)\r
+{\r
+    dict_ptr dict;\r
+    if (v->tag != kTAG_DICTIONARY) return NULL; // not a dictionary\r
+    dict = v->dict;\r
+    /* search for key */\r
+    while (dict) {\r
+        if (dict->key && dict->key->tag == kTAG_ASCIISTRING &&\r
+            strcmp(key, dict->key->string) == 0) { // found it\r
+            return dict->value;\r
+        }\r
+        dict = dict->next;\r
+    }\r
+    return NULL; /* not found */\r
+}\r
+\r
+value_ptr value_dict_lookup_using_path(value_ptr v, char *path)\r
+{\r
+    char key[MAX_KEY_SIZE];\r
+    while (*path) { /* more to the path */\r
+        int i = 0;\r
+        while (i < MAX_KEY_SIZE - 1) {\r
+            key[i] = *path++;\r
+            if (key[i] == '/') { /* end of entry in path */\r
+                key[i + 1] = 0;\r
+                break;\r
+            }\r
+            if (!key[i]) {\r
+                path--; /* back up to end of string char */\r
+                break;  /* this will cause outer loop to exit */\r
+            }\r
+            i++;\r
+        }\r
+        if (!v || v->tag != kTAG_DICTIONARY) return NULL;\r
+        /* now, look up the key to get next value */\r
+        v = value_dict_lookup_using_string(v, key);\r
+        if (v == NULL) return NULL;\r
+    }\r
+    return v;\r
+}\r
+                \r
+\r
+/*************** functions for debugging ***************/\r
+\r
+void plist_print(value_ptr v)\r
+{\r
+    size_t i;\r
+    int comma_needed;\r
+    dict_ptr dict;\r
+    if (!v) {\r
+        printf("NULL");\r
+        return;\r
+    }\r
+    switch (v->tag & 0xF0) {\r
+    case kTAG_SIMPLE:\r
+        switch (v->tag) {\r
+        case kVALUE_NULL: \r
+            printf("NULL@%p", v); break;\r
+        case kVALUE_FALSE: \r
+            printf("FALSE@%p", v); break;\r
+        case kVALUE_TRUE:\r
+            printf("TRUE@%p", v); break;\r
+        default:\r
+            printf("UNKNOWN tag=%x@%p", v->tag, v); break;\r
+        }\r
+        break;\r
+    case kTAG_INT:\r
+        printf("%lld@%p", v->integer, v); break;\r
+    case kTAG_REAL:\r
+        printf("%g@%p", v->real, v); break;\r
+    case kTAG_DATE:\r
+        printf("date:%g@%p", v->real, v); break;\r
+    case kTAG_DATA:\r
+        printf("data@%p->%p:[%p:", v, v->data, v->data->data);\r
+        for (i = 0; i < v->data->len; i++) {\r
+            printf(" %2x", v->data->data[i]);\r
+        }\r
+        printf("]"); break;\r
+    case kTAG_ASCIISTRING:\r
+        printf("%p:\"%s\"@%p", v->string, v->string, v); break;\r
+    case kTAG_UNICODESTRING:\r
+        printf("unicode:%p:\"%s\"@%p", v->string, v->string, v); break;\r
+    case kTAG_UID:\r
+        printf("UID:%llu@%p", v->uinteger, v); break;\r
+    case kTAG_ARRAY:\r
+        comma_needed = FALSE;\r
+        printf("%p->%p:[%p:", v, v->array, v->array->array);\r
+        for (i = 0; i < v->array->length; i++) {\r
+            if (comma_needed) printf(", ");\r
+            plist_print(v->array->array[i]);\r
+            comma_needed = TRUE;\r
+        }\r
+        printf("]"); break;\r
+    case kTAG_DICTIONARY:\r
+        comma_needed = FALSE;\r
+        printf("%p:[", v);\r
+        dict = v->dict;\r
+        while (dict) {\r
+            if (comma_needed) printf(", ");\r
+            printf("%p:", dict);\r
+            plist_print(dict->key);\r
+            printf("->");\r
+            plist_print(dict->value);\r
+            comma_needed = TRUE;\r
+            dict = dict->next;\r
+        }\r
+        printf("]"); break;\r
+    default:\r
+        printf("UNKNOWN tag=%x", v->tag);\r
+        break;\r
+    }\r
+}\r
+\r
+            \r
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/readbinaryplist.h b/libs/backends/wavesaudio/portmidi/src/pm_mac/readbinaryplist.h
new file mode 100644 (file)
index 0000000..5778659
--- /dev/null
@@ -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/libs/backends/wavesaudio/portmidi/src/pm_win/pmwin.c b/libs/backends/wavesaudio/portmidi/src/pm_win/pmwin.c
new file mode 100644 (file)
index 0000000..5b4dec6
--- /dev/null
@@ -0,0 +1,143 @@
+/* pmwin.c -- PortMidi os-dependent code */\r
+\r
+/* This file only needs to implement:\r
+       pm_init(), which calls various routines to register the \r
+           available midi devices,\r
+       Pm_GetDefaultInputDeviceID(), and\r
+       Pm_GetDefaultOutputDeviceID().\r
+   This file must\r
+   be separate from the main portmidi.c file because it is system\r
+   dependent, and it is separate from, say, pmwinmm.c, because it\r
+   might need to register devices for winmm, directx, and others.\r
+\r
+ */\r
+\r
+#include "stdlib.h"\r
+#include "portmidi.h"\r
+#include "pmutil.h"\r
+#include "pminternal.h"\r
+#include "pmwinmm.h"\r
+#ifdef DEBUG\r
+#include "stdio.h"\r
+#endif\r
+#include <windows.h>\r
+\r
+/* pm_exit is called when the program exits.\r
+   It calls pm_term to make sure PortMidi is properly closed.\r
+   If DEBUG is on, we prompt for input to avoid losing error messages.\r
+ */\r
+static void pm_exit(void) {\r
+    pm_term();\r
+#ifdef DEBUG\r
+#define STRING_MAX 80\r
+    {\r
+        char line[STRING_MAX];\r
+        printf("Type ENTER...\n");\r
+        /* note, w/o this prompting, client console application can not see one\r
+           of its errors before closing. */\r
+        fgets(line, STRING_MAX, stdin);\r
+    }\r
+#endif\r
+}\r
+\r
+\r
+/* pm_init is the windows-dependent initialization.*/\r
+void pm_init(void)\r
+{\r
+    atexit(pm_exit);\r
+#ifdef DEBUG\r
+    printf("registered pm_exit with atexit()\n");\r
+#endif\r
+    pm_winmm_init();\r
+    /* initialize other APIs (DirectX?) here */\r
+}\r
+\r
+\r
+void pm_term(void) {\r
+    pm_winmm_term();\r
+}\r
+\r
+\r
+static PmDeviceID pm_get_default_device_id(int is_input, char *key) {\r
+    HKEY hkey;\r
+#define PATTERN_MAX 256\r
+    char pattern[PATTERN_MAX];\r
+    long pattern_max = PATTERN_MAX;\r
+    DWORD dwType;\r
+    /* Find first input or device -- this is the default. */\r
+    PmDeviceID id = pmNoDevice;\r
+    int i, j;\r
+    Pm_Initialize(); /* make sure descriptors exist! */\r
+    for (i = 0; i < pm_descriptor_index; i++) {\r
+        if (descriptors[i].pub.input == is_input) {\r
+            id = i;\r
+            break;\r
+        }\r
+    }\r
+    /* Look in registry for a default device name pattern. */\r
+    if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &hkey) != \r
+        ERROR_SUCCESS) {\r
+        return id;\r
+    }\r
+    if (RegOpenKeyEx(hkey, "JavaSoft", 0, KEY_READ, &hkey) !=\r
+        ERROR_SUCCESS) {\r
+        return id;\r
+    }\r
+    if (RegOpenKeyEx(hkey, "Prefs", 0, KEY_READ, &hkey) !=\r
+        ERROR_SUCCESS) {\r
+        return id;\r
+    }\r
+    if (RegOpenKeyEx(hkey, "/Port/Midi", 0, KEY_READ, &hkey) !=\r
+        ERROR_SUCCESS) {\r
+        return id;\r
+    }\r
+    if (RegQueryValueEx(hkey, key, NULL, &dwType, pattern, &pattern_max) != \r
+       ERROR_SUCCESS) {\r
+        return id;\r
+    }\r
+\r
+    /* decode pattern: upper case encoded with "/" prefix */\r
+    i = j = 0;\r
+    while (pattern[i]) {\r
+        if (pattern[i] == '/' && pattern[i + 1]) {\r
+            pattern[j++] = toupper(pattern[++i]);\r
+       } else {\r
+            pattern[j++] = tolower(pattern[i]);\r
+       }\r
+        i++;\r
+    }\r
+    pattern[j] = 0; /* end of string */\r
+\r
+    /* now pattern is the string from the registry; search for match */\r
+    i = pm_find_default_device(pattern, is_input);\r
+    if (i != pmNoDevice) {\r
+        id = i;\r
+    }\r
+    return id;\r
+}\r
+\r
+\r
+PmDeviceID Pm_GetDefaultInputDeviceID() {\r
+    return pm_get_default_device_id(TRUE, \r
+           "/P/M_/R/E/C/O/M/M/E/N/D/E/D_/I/N/P/U/T_/D/E/V/I/C/E");\r
+}\r
+\r
+\r
+PmDeviceID Pm_GetDefaultOutputDeviceID() {\r
+  return pm_get_default_device_id(FALSE,\r
+          "/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");\r
+}\r
+\r
+\r
+#include "stdio.h" \r
+\r
+void *pm_alloc(size_t s) {\r
+    return malloc(s); \r
+}\r
+\r
+\r
+void pm_free(void *ptr) { \r
+    free(ptr); \r
+}\r
+\r
+\r
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.c b/libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.c
new file mode 100644 (file)
index 0000000..ab66f80
--- /dev/null
@@ -0,0 +1,1464 @@
+/* pmwinmm.c -- system specific definitions */\r
+\r
+#ifdef _MSC_VER\r
+ #pragma warning(disable: 4133) // stop warnings about implicit typecasts\r
+#endif\r
+\r
+#ifndef _WIN32_WINNT\r
+    /* without this define, InitializeCriticalSectionAndSpinCount is \r
+     * undefined. This version level means "Windows 2000 and higher" \r
+     */\r
+    #define _WIN32_WINNT 0x0500\r
+#endif\r
+\r
+#include "windows.h"\r
+#include "mmsystem.h"\r
+#include "portmidi.h"\r
+#include "pmutil.h"\r
+#include "pminternal.h"\r
+#include "pmwinmm.h"\r
+#include <string.h>\r
+#include "porttime.h"\r
+\r
+/* asserts used to verify portMidi code logic is sound; later may want\r
+    something more graceful */\r
+#include <assert.h>\r
+#ifdef DEBUG\r
+/* this printf stuff really important for debugging client app w/host errors.\r
+    probably want to do something else besides read/write from/to console\r
+    for portability, however */\r
+#define STRING_MAX 80\r
+#include "stdio.h"\r
+#endif\r
+\r
+#define streql(x, y) (strcmp(x, y) == 0)\r
+\r
+#define MIDI_SYSEX      0xf0\r
+#define MIDI_EOX        0xf7\r
+\r
+/* callback routines */\r
+static void CALLBACK winmm_in_callback(HMIDIIN hMidiIn,\r
+                                       WORD wMsg, DWORD dwInstance, \r
+                                       DWORD dwParam1, DWORD dwParam2);\r
+static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg,\r
+                                              DWORD dwInstance, DWORD dwParam1, \r
+                                              DWORD dwParam2);\r
+#ifdef USE_SYSEX_BUFFERS\r
+static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg,\r
+                                        DWORD dwInstance, DWORD dwParam1, \r
+                                        DWORD dwParam2);\r
+#endif\r
+\r
+extern pm_fns_node pm_winmm_in_dictionary;\r
+extern pm_fns_node pm_winmm_out_dictionary;\r
+\r
+static void winmm_out_delete(PmInternal *midi); /* forward reference */\r
+\r
+/*\r
+A note about buffers: WinMM seems to hold onto buffers longer than\r
+one would expect, e.g. when I tried using 2 small buffers to send\r
+long sysex messages, at some point WinMM held both buffers. This problem\r
+was fixed by making buffers bigger. Therefore, it seems that there should \r
+be enough buffer space to hold a whole sysex message. \r
+\r
+The bufferSize passed into Pm_OpenInput (passed into here as buffer_len)\r
+will be used to estimate the largest sysex message (= buffer_len * 4 bytes).\r
+Call that the max_sysex_len = buffer_len * 4.\r
+\r
+For simple midi output (latency == 0), allocate 3 buffers, each with half\r
+the size of max_sysex_len, but each at least 256 bytes.\r
+\r
+For stream output, there will already be enough space in very short\r
+buffers, so use them, but make sure there are at least 16.\r
+\r
+For input, use many small buffers rather than 2 large ones so that when \r
+there are short sysex messages arriving frequently (as in control surfaces)\r
+there will be more free buffers to fill. Use max_sysex_len / 64 buffers,\r
+but at least 16, of size 64 bytes each.\r
+\r
+The following constants help to represent these design parameters:\r
+*/\r
+#define NUM_SIMPLE_SYSEX_BUFFERS 3\r
+#define MIN_SIMPLE_SYSEX_LEN 256\r
+\r
+#define MIN_STREAM_BUFFERS 16\r
+#define STREAM_BUFFER_LEN 24\r
+\r
+#define INPUT_SYSEX_LEN 64\r
+#define MIN_INPUT_BUFFERS 16\r
+\r
+/* if we run out of space for output (assume this is due to a sysex msg,\r
+   expand by up to NUM_EXPANSION_BUFFERS in increments of EXPANSION_BUFFER_LEN\r
+ */\r
+#define NUM_EXPANSION_BUFFERS 128\r
+#define EXPANSION_BUFFER_LEN 1024\r
+\r
+/* A sysex buffer has 3 DWORDS as a header plus the actual message size */\r
+#define MIDIHDR_SYSEX_BUFFER_LENGTH(x) ((x) + sizeof(long)*3)\r
+/* A MIDIHDR with a sysex message is the buffer length plus the header size */\r
+#define MIDIHDR_SYSEX_SIZE(x) (MIDIHDR_SYSEX_BUFFER_LENGTH(x) + sizeof(MIDIHDR))\r
+#ifdef USE_SYSEX_BUFFERS\r
+/* Size of a MIDIHDR with a buffer contaning multiple MIDIEVENT structures */\r
+#define MIDIHDR_SIZE(x) ((x) + sizeof(MIDIHDR))\r
+#endif\r
+\r
+/*\r
+==============================================================================\r
+win32 mmedia system specific structure passed to midi callbacks\r
+==============================================================================\r
+*/\r
+\r
+/* global winmm device info */\r
+MIDIINCAPS *midi_in_caps = NULL;\r
+MIDIINCAPS midi_in_mapper_caps;\r
+UINT midi_num_inputs = 0;\r
+MIDIOUTCAPS *midi_out_caps = NULL;\r
+MIDIOUTCAPS midi_out_mapper_caps;\r
+UINT midi_num_outputs = 0;\r
+\r
+/* per device info */\r
+typedef struct midiwinmm_struct {\r
+    union {\r
+        HMIDISTRM stream;   /* windows handle for stream */\r
+        HMIDIOUT out;       /* windows handle for out calls */\r
+        HMIDIIN in;         /* windows handle for in calls */\r
+    } handle;\r
+\r
+    /* midi output messages are sent in these buffers, which are allocated\r
+     * in a round-robin fashion, using next_buffer as an index\r
+     */\r
+    LPMIDIHDR *buffers;     /* pool of buffers for midi in or out data */\r
+    int max_buffers;        /* length of buffers array */\r
+    int buffers_expanded;   /* buffers array expanded for extra msgs? */\r
+    int num_buffers;        /* how many buffers allocated in buffers array */\r
+    int next_buffer;        /* index of next buffer to send */\r
+    HANDLE buffer_signal;   /* used to wait for buffer to become free */\r
+#ifdef USE_SYSEX_BUFFERS\r
+    /* sysex buffers will be allocated only when\r
+     * a sysex message is sent. The size of the buffer is fixed.\r
+     */\r
+    LPMIDIHDR sysex_buffers[NUM_SYSEX_BUFFERS]; /* pool of buffers for sysex data */\r
+    int next_sysex_buffer;      /* index of next sysexbuffer to send */\r
+#endif\r
+    unsigned long last_time;    /* last output time */\r
+    int first_message;          /* flag: treat first message differently */\r
+    int sysex_mode;             /* middle of sending sysex */\r
+    unsigned long sysex_word;   /* accumulate data when receiving sysex */\r
+    unsigned int sysex_byte_count; /* count how many received */\r
+    LPMIDIHDR hdr;              /* the message accumulating sysex to send */\r
+    unsigned long sync_time;    /* when did we last determine delta? */\r
+    long delta;                 /* difference between stream time and\r
+                                       real time */\r
+    int error;                  /* host error from doing port midi call */\r
+    CRITICAL_SECTION lock;      /* prevents reentrant callbacks (input only) */\r
+} midiwinmm_node, *midiwinmm_type;\r
+\r
+\r
+/*\r
+=============================================================================\r
+general MIDI device queries\r
+=============================================================================\r
+*/\r
+static void pm_winmm_general_inputs()\r
+{\r
+    UINT i;\r
+    WORD wRtn;\r
+    midi_num_inputs = midiInGetNumDevs();\r
+    midi_in_caps = (MIDIINCAPS *) pm_alloc(sizeof(MIDIINCAPS) * \r
+                                           midi_num_inputs);\r
+    if (midi_in_caps == NULL) {\r
+        /* if you can't open a particular system-level midi interface\r
+         * (such as winmm), we just consider that system or API to be\r
+         * unavailable and move on without reporting an error.\r
+         */\r
+        return;\r
+    }\r
+\r
+    for (i = 0; i < midi_num_inputs; i++) {\r
+        wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) & midi_in_caps[i],\r
+                                sizeof(MIDIINCAPS));\r
+        if (wRtn == MMSYSERR_NOERROR) {\r
+            /* ignore errors here -- if pm_descriptor_max is exceeded, some\r
+               devices will not be accessible. */\r
+            pm_add_device("MMSystem", midi_in_caps[i].szPname, TRUE,\r
+                          (void *) i, &pm_winmm_in_dictionary);\r
+        }\r
+    }\r
+}\r
+\r
+\r
+static void pm_winmm_mapper_input()\r
+{\r
+    WORD wRtn;\r
+    /* Note: if MIDIMAPPER opened as input (documentation implies you\r
+        can, but current system fails to retrieve input mapper\r
+        capabilities) then you still should retrieve some formof\r
+        setup info. */\r
+    wRtn = midiInGetDevCaps((UINT) MIDIMAPPER,\r
+                            (LPMIDIINCAPS) & midi_in_mapper_caps, \r
+                            sizeof(MIDIINCAPS));\r
+    if (wRtn == MMSYSERR_NOERROR) {\r
+        pm_add_device("MMSystem", midi_in_mapper_caps.szPname, TRUE,\r
+                      (void *) MIDIMAPPER, &pm_winmm_in_dictionary);\r
+    }\r
+}\r
+\r
+\r
+static void pm_winmm_general_outputs()\r
+{\r
+    UINT i;\r
+    DWORD wRtn;\r
+    midi_num_outputs = midiOutGetNumDevs();\r
+    midi_out_caps = pm_alloc( sizeof(MIDIOUTCAPS) * midi_num_outputs );\r
+\r
+    if (midi_out_caps == NULL) {\r
+        /* no error is reported -- see pm_winmm_general_inputs */\r
+        return ;\r
+    }\r
+\r
+    for (i = 0; i < midi_num_outputs; i++) {\r
+        wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) & midi_out_caps[i],\r
+                                 sizeof(MIDIOUTCAPS));\r
+        if (wRtn == MMSYSERR_NOERROR) {\r
+            pm_add_device("MMSystem", midi_out_caps[i].szPname, FALSE,\r
+                          (void *) i, &pm_winmm_out_dictionary);\r
+        }\r
+    }\r
+}\r
+\r
+\r
+static void pm_winmm_mapper_output()\r
+{\r
+    WORD wRtn;\r
+    /* Note: if MIDIMAPPER opened as output (pseudo MIDI device\r
+        maps device independent messages into device dependant ones,\r
+        via NT midimapper program) you still should get some setup info */\r
+    wRtn = midiOutGetDevCaps((UINT) MIDIMAPPER, (LPMIDIOUTCAPS)\r
+                             & midi_out_mapper_caps, sizeof(MIDIOUTCAPS));\r
+    if (wRtn == MMSYSERR_NOERROR) {\r
+        pm_add_device("MMSystem", midi_out_mapper_caps.szPname, FALSE,\r
+                      (void *) MIDIMAPPER, &pm_winmm_out_dictionary);\r
+    }\r
+}\r
+\r
+\r
+/*\r
+=========================================================================================\r
+host error handling\r
+=========================================================================================\r
+*/\r
+static unsigned int winmm_has_host_error(PmInternal * midi)\r
+{\r
+    midiwinmm_type m = (midiwinmm_type)midi->descriptor;\r
+    return m->error;\r
+}\r
+\r
+\r
+/* str_copy_len -- like strcat, but won't overrun the destination string */\r
+/*\r
+ * returns length of resulting string\r
+ */\r
+static int str_copy_len(char *dst, char *src, int len)\r
+{\r
+    strncpy(dst, src, len);\r
+    /* just in case suffex is greater then len, terminate with zero */\r
+    dst[len - 1] = 0;\r
+    return strlen(dst);\r
+}\r
+\r
+\r
+static void winmm_get_host_error(PmInternal * midi, char * msg, UINT len)\r
+{\r
+    /* precondition: midi != NULL */\r
+    midiwinmm_node * m = (midiwinmm_node *) midi->descriptor;\r
+    char *hdr1 = "Host error: ";\r
+    char *hdr2 = "Host callback error: ";\r
+\r
+    msg[0] = 0; /* initialize result string to empty */\r
+\r
+    if (descriptors[midi->device_id].pub.input) {\r
+        /* input and output use different winmm API calls */\r
+        if (m) { /* make sure there is an open device to examine */\r
+            if (m->error != MMSYSERR_NOERROR) {\r
+                int n = str_copy_len(msg, hdr1, len);\r
+                /* read and record host error */\r
+                int err = midiInGetErrorText(m->error, msg + n, len - n);\r
+                assert(err == MMSYSERR_NOERROR);\r
+                m->error = MMSYSERR_NOERROR;\r
+            }\r
+        }\r
+    } else { /* output port */\r
+        if (m) {\r
+            if (m->error != MMSYSERR_NOERROR) {\r
+                int n = str_copy_len(msg, hdr1, len);\r
+                int err = midiOutGetErrorText(m->error, msg + n, len - n);\r
+                assert(err == MMSYSERR_NOERROR);\r
+                m->error = MMSYSERR_NOERROR;\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+buffer handling\r
+=============================================================================\r
+*/\r
+static MIDIHDR *allocate_buffer(long data_size)\r
+{\r
+    LPMIDIHDR hdr = (LPMIDIHDR) pm_alloc(MIDIHDR_SYSEX_SIZE(data_size));\r
+    MIDIEVENT *evt;\r
+    if (!hdr) return NULL;\r
+    evt = (MIDIEVENT *) (hdr + 1); /* place MIDIEVENT after header */\r
+    hdr->lpData = (LPSTR) evt;\r
+    hdr->dwBufferLength = MIDIHDR_SYSEX_BUFFER_LENGTH(data_size);\r
+    hdr->dwBytesRecorded = 0;\r
+    hdr->dwFlags = 0;\r
+    hdr->dwUser = hdr->dwBufferLength;\r
+    return hdr;\r
+}\r
+\r
+#ifdef USE_SYSEX_BUFFERS\r
+static MIDIHDR *allocate_sysex_buffer(long data_size)\r
+{\r
+    /* we're actually allocating more than data_size because the buffer \r
+     * will include the MIDIEVENT header in addition to the data \r
+     */\r
+    LPMIDIHDR hdr = (LPMIDIHDR) pm_alloc(MIDIHDR_SYSEX_SIZE(data_size));\r
+    MIDIEVENT *evt;\r
+    if (!hdr) return NULL;\r
+    evt = (MIDIEVENT *) (hdr + 1); /* place MIDIEVENT after header */\r
+    hdr->lpData = (LPSTR) evt;\r
+    hdr->dwFlags = 0;\r
+    hdr->dwUser = 0;\r
+    return hdr;\r
+}\r
+#endif\r
+\r
+static PmError allocate_buffers(midiwinmm_type m, long data_size, long count)\r
+{\r
+    int i;\r
+    /* buffers is an array of count pointers to MIDIHDR/MIDIEVENT struct */\r
+    m->num_buffers = 0; /* in case no memory can be allocated */\r
+    m->buffers = (LPMIDIHDR *) pm_alloc(sizeof(LPMIDIHDR) * count);\r
+    if (!m->buffers) return pmInsufficientMemory;\r
+    m->max_buffers = count;\r
+    for (i = 0; i < count; i++) {\r
+        LPMIDIHDR hdr = allocate_buffer(data_size);\r
+        if (!hdr) { /* free everything allocated so far and return */\r
+            for (i = i - 1; i >= 0; i--) pm_free(m->buffers[i]);\r
+            pm_free(m->buffers);\r
+            m->max_buffers = 0;\r
+            return pmInsufficientMemory;\r
+        }\r
+        m->buffers[i] = hdr; /* this may be NULL if allocation fails */\r
+    }\r
+    m->num_buffers = count;\r
+    return pmNoError;\r
+}\r
+\r
+#ifdef USE_SYSEX_BUFFERS\r
+static PmError allocate_sysex_buffers(midiwinmm_type m, long data_size)\r
+{\r
+    PmError rslt = pmNoError;\r
+    /* sysex_buffers is an array of count pointers to MIDIHDR/MIDIEVENT struct */\r
+    int i;\r
+    for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {\r
+        LPMIDIHDR hdr = allocate_sysex_buffer(data_size);\r
+\r
+        if (!hdr) rslt = pmInsufficientMemory;\r
+        m->sysex_buffers[i] = hdr; /* this may be NULL if allocation fails */\r
+        hdr->dwFlags = 0; /* mark as free */\r
+    }\r
+    return rslt;\r
+}\r
+#endif\r
+\r
+#ifdef USE_SYSEX_BUFFERS\r
+static LPMIDIHDR get_free_sysex_buffer(PmInternal *midi)\r
+{\r
+    LPMIDIHDR r = NULL;\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    if (!m->sysex_buffers[0]) {\r
+        if (allocate_sysex_buffers(m, SYSEX_BYTES_PER_BUFFER)) {\r
+            return NULL;\r
+        }\r
+    }\r
+    /* busy wait until we find a free buffer */\r
+    while (TRUE) {\r
+        int i;\r
+        for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {\r
+            /* cycle through buffers, modulo NUM_SYSEX_BUFFERS */\r
+            m->next_sysex_buffer++;\r
+            if (m->next_sysex_buffer >= NUM_SYSEX_BUFFERS) m->next_sysex_buffer = 0;\r
+            r = m->sysex_buffers[m->next_sysex_buffer];\r
+            if ((r->dwFlags & MHDR_PREPARED) == 0) goto found_sysex_buffer;\r
+        }\r
+        /* after scanning every buffer and not finding anything, block */\r
+        if (WaitForSingleObject(m->buffer_signal, 1000) == WAIT_TIMEOUT) {\r
+#ifdef DEBUG\r
+            printf("PortMidi warning: get_free_sysex_buffer() wait timed out after 1000ms\n");\r
+#endif\r
+        }\r
+    }\r
+found_sysex_buffer:\r
+    r->dwBytesRecorded = 0;\r
+    r->dwBufferLength = 0; /* changed to correct value later */\r
+    return r;\r
+}\r
+#endif\r
+\r
+static LPMIDIHDR get_free_output_buffer(PmInternal *midi)\r
+{\r
+    LPMIDIHDR r = NULL;\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    while (TRUE) {\r
+        int i;\r
+        for (i = 0; i < m->num_buffers; i++) {\r
+            /* cycle through buffers, modulo m->num_buffers */\r
+            m->next_buffer++;\r
+            if (m->next_buffer >= m->num_buffers) m->next_buffer = 0;\r
+            r = m->buffers[m->next_buffer];\r
+            if ((r->dwFlags & MHDR_PREPARED) == 0) goto found_buffer;\r
+        }\r
+        /* after scanning every buffer and not finding anything, block */\r
+        if (WaitForSingleObject(m->buffer_signal, 1000) == WAIT_TIMEOUT) {\r
+#ifdef DEBUG\r
+            printf("PortMidi warning: get_free_output_buffer() wait timed out after 1000ms\n");\r
+#endif\r
+            /* if we're trying to send a sysex message, maybe the \r
+             * message is too big and we need more message buffers.\r
+             * Expand the buffer pool by 128KB using 1024-byte buffers.\r
+             */\r
+            /* first, expand the buffers array if necessary */\r
+            if (!m->buffers_expanded) {\r
+                LPMIDIHDR *new_buffers = (LPMIDIHDR *) pm_alloc(\r
+                        (m->num_buffers + NUM_EXPANSION_BUFFERS) * \r
+                        sizeof(LPMIDIHDR));\r
+                /* if no memory, we could return a no-memory error, but user\r
+                 * probably will be unprepared to deal with it. Maybe the\r
+                 * MIDI driver is temporarily hung so we should just wait.\r
+                 * I don't know the right answer, but waiting is easier.\r
+                 */\r
+                if (!new_buffers) continue;\r
+                /* copy buffers to new_buffers and replace buffers */\r
+                memcpy(new_buffers, m->buffers, \r
+                       m->num_buffers * sizeof(LPMIDIHDR));\r
+                pm_free(m->buffers);\r
+                m->buffers = new_buffers;\r
+                m->max_buffers = m->num_buffers + NUM_EXPANSION_BUFFERS;\r
+                m->buffers_expanded = TRUE;\r
+            }\r
+            /* next, add one buffer and return it */\r
+            if (m->num_buffers < m->max_buffers) {\r
+                r = allocate_buffer(EXPANSION_BUFFER_LEN);\r
+                /* again, if there's no memory, we may not really be \r
+                 * dead -- maybe the system is temporarily hung and\r
+                 * we can just wait longer for a message buffer */\r
+                if (!r) continue;\r
+                m->buffers[m->num_buffers++] = r;\r
+                goto found_buffer; /* break out of 2 loops */\r
+            }\r
+            /* else, we've allocated all NUM_EXPANSION_BUFFERS buffers,\r
+             * and we have no free buffers to send. We'll just keep\r
+             * polling to see if any buffers show up.\r
+             */\r
+        }\r
+    }\r
+found_buffer:\r
+    r->dwBytesRecorded = 0;\r
+    /* actual buffer length is saved in dwUser field */\r
+    r->dwBufferLength = (DWORD) r->dwUser;\r
+    return r;\r
+}\r
+\r
+#ifdef EXPANDING_SYSEX_BUFFERS\r
+note: this is not working code, but might be useful if you want\r
+      to grow sysex buffers.\r
+static PmError resize_sysex_buffer(PmInternal *midi, long old_size, long new_size)\r
+{\r
+    LPMIDIHDR big;\r
+    int i;\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    /* buffer must be smaller than 64k, but be also a multiple of 4 */\r
+    if (new_size > 65520) {\r
+        if (old_size >= 65520)\r
+            return pmBufferMaxSize;\r
+        else\r
+            new_size = 65520;\r
+    }\r
+    /* allocate a bigger message  */\r
+    big = allocate_sysex_buffer(new_size);\r
+    /* printf("expand to %d bytes\n", new_size);*/\r
+    if (!big) return pmInsufficientMemory;\r
+    m->error = midiOutPrepareHeader(m->handle.out, big, sizeof(MIDIHDR));\r
+    if (m->error) {\r
+        pm_free(big);\r
+        return pmHostError;\r
+    }\r
+    /* make sure we're not going to overwrite any memory */\r
+    assert(old_size <= new_size);\r
+    memcpy(big->lpData, m->hdr->lpData, old_size);\r
+    /* keep track of how many sysex bytes are in message so far */\r
+    big->dwBytesRecorded = m->hdr->dwBytesRecorded;\r
+    big->dwBufferLength = new_size;\r
+    /* find which buffer this was, and replace it */\r
+    for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {\r
+        if (m->sysex_buffers[i] == m->hdr) {\r
+            m->sysex_buffers[i] = big;\r
+            m->sysex_buffer_size[i] = new_size;\r
+            pm_free(m->hdr);\r
+            m->hdr = big;\r
+            break;\r
+        }\r
+    }\r
+    assert(i != NUM_SYSEX_BUFFERS);\r
+\r
+    return pmNoError;\r
+}\r
+#endif\r
+\r
+/*\r
+=========================================================================================\r
+begin midi input implementation\r
+=========================================================================================\r
+*/\r
+\r
+\r
+static PmError allocate_input_buffer(HMIDIIN h, long buffer_len)\r
+{\r
+    LPMIDIHDR hdr = allocate_buffer(buffer_len);\r
+    if (!hdr) return pmInsufficientMemory;\r
+    pm_hosterror = midiInPrepareHeader(h, hdr, sizeof(MIDIHDR));\r
+    if (pm_hosterror) {\r
+        pm_free(hdr);\r
+        return pm_hosterror;\r
+    }\r
+    pm_hosterror = midiInAddBuffer(h, hdr, sizeof(MIDIHDR));\r
+    return pm_hosterror;\r
+}\r
+\r
+\r
+static PmError winmm_in_open(PmInternal *midi, void *driverInfo)\r
+{\r
+    DWORD dwDevice;\r
+    int i = midi->device_id;\r
+    int max_sysex_len = midi->buffer_len * 4;\r
+    int num_input_buffers = max_sysex_len / INPUT_SYSEX_LEN;\r
+    midiwinmm_type m;\r
+\r
+    dwDevice = (DWORD) descriptors[i].descriptor;\r
+\r
+    /* create system dependent device data */\r
+    m = (midiwinmm_type) pm_alloc(sizeof(midiwinmm_node)); /* create */\r
+    midi->descriptor = m;\r
+    if (!m) goto no_memory;\r
+    m->handle.in = NULL;\r
+    m->buffers = NULL; /* not used for input */\r
+    m->num_buffers = 0; /* not used for input */\r
+    m->max_buffers = FALSE; /* not used for input */\r
+    m->buffers_expanded = 0; /* not used for input */\r
+    m->next_buffer = 0; /* not used for input */\r
+    m->buffer_signal = 0; /* not used for input */\r
+#ifdef USE_SYSEX_BUFFERS\r
+    for (i = 0; i < NUM_SYSEX_BUFFERS; i++) \r
+        m->sysex_buffers[i] = NULL; /* not used for input */\r
+    m->next_sysex_buffer = 0; /* not used for input */\r
+#endif\r
+    m->last_time = 0;\r
+    m->first_message = TRUE; /* not used for input */\r
+    m->sysex_mode = FALSE;\r
+    m->sysex_word = 0;\r
+    m->sysex_byte_count = 0;\r
+    m->hdr = NULL; /* not used for input */\r
+    m->sync_time = 0;\r
+    m->delta = 0;\r
+    m->error = MMSYSERR_NOERROR;\r
+    /* 4000 is based on Windows documentation -- that's the value used in the\r
+       memory manager. It's small enough that it should not hurt performance even\r
+       if it's not optimal.\r
+     */\r
+    InitializeCriticalSectionAndSpinCount(&m->lock, 4000);\r
+    /* open device */\r
+    pm_hosterror = midiInOpen(\r
+           &(m->handle.in),  /* input device handle */\r
+           dwDevice,  /* device ID */\r
+           (DWORD_PTR) winmm_in_callback,  /* callback address */\r
+           (DWORD_PTR) midi,  /* callback instance data */\r
+           CALLBACK_FUNCTION); /* callback is a procedure */\r
+    if (pm_hosterror) goto free_descriptor;\r
+\r
+    if (num_input_buffers < MIN_INPUT_BUFFERS)\r
+        num_input_buffers = MIN_INPUT_BUFFERS;\r
+    for (i = 0; i < num_input_buffers; i++) {\r
+        if (allocate_input_buffer(m->handle.in, INPUT_SYSEX_LEN)) {\r
+            /* either pm_hosterror was set, or the proper return code\r
+               is pmInsufficientMemory */\r
+            goto close_device;\r
+        }\r
+    }\r
+    /* start device */\r
+    pm_hosterror = midiInStart(m->handle.in);\r
+    if (pm_hosterror) goto reset_device;\r
+    return pmNoError;\r
+\r
+    /* undo steps leading up to the detected error */\r
+reset_device:\r
+    /* ignore return code (we already have an error to report) */\r
+    midiInReset(m->handle.in);\r
+close_device:\r
+    midiInClose(m->handle.in); /* ignore return code */\r
+free_descriptor:\r
+    midi->descriptor = NULL;\r
+    pm_free(m);\r
+no_memory:\r
+    if (pm_hosterror) {\r
+        int err = midiInGetErrorText(pm_hosterror, (char *) pm_hosterror_text,\r
+                                     PM_HOST_ERROR_MSG_LEN);\r
+        assert(err == MMSYSERR_NOERROR);\r
+        return pmHostError;\r
+    }\r
+    /* if !pm_hosterror, then the error must be pmInsufficientMemory */\r
+    return pmInsufficientMemory;\r
+    /* note: if we return an error code, the device will be\r
+       closed and memory will be freed. It's up to the caller\r
+       to free the parameter midi */\r
+}\r
+\r
+static PmError winmm_in_poll(PmInternal *midi) {\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    return m->error;\r
+}\r
+\r
+\r
+\r
+/* winmm_in_close -- close an open midi input device */\r
+/*\r
+ * assume midi is non-null (checked by caller)\r
+ */\r
+static PmError winmm_in_close(PmInternal *midi)\r
+{\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    if (!m) return pmBadPtr;\r
+    /* device to close */\r
+    if (pm_hosterror = midiInStop(m->handle.in)) {\r
+        midiInReset(m->handle.in); /* try to reset and close port */\r
+        midiInClose(m->handle.in);\r
+    } else if (pm_hosterror = midiInReset(m->handle.in)) {\r
+        midiInClose(m->handle.in); /* best effort to close midi port */\r
+    } else {\r
+        pm_hosterror = midiInClose(m->handle.in);\r
+    }\r
+    midi->descriptor = NULL;\r
+    DeleteCriticalSection(&m->lock);\r
+    pm_free(m); /* delete */\r
+    if (pm_hosterror) {\r
+        int err = midiInGetErrorText(pm_hosterror, (char *) pm_hosterror_text,\r
+                                     PM_HOST_ERROR_MSG_LEN);\r
+        assert(err == MMSYSERR_NOERROR);\r
+        return pmHostError;\r
+    }\r
+    return pmNoError;\r
+}\r
+\r
+\r
+/* Callback function executed via midiInput SW interrupt (via midiInOpen). */\r
+static void FAR PASCAL winmm_in_callback(\r
+    HMIDIIN hMidiIn,    /* midiInput device Handle */\r
+    WORD wMsg,          /* midi msg */\r
+    DWORD dwInstance,   /* application data */\r
+    DWORD dwParam1,     /* MIDI data */\r
+    DWORD dwParam2)    /* device timestamp (wrt most recent midiInStart) */\r
+{\r
+    static int entry = 0;\r
+    PmInternal *midi = (PmInternal *) dwInstance;\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+\r
+    /* NOTE: we do not just EnterCriticalSection() here because an\r
+     * MIM_CLOSE message arrives when the port is closed, but then\r
+     * the m->lock has been destroyed.\r
+     */\r
+\r
+    switch (wMsg) {\r
+    case MIM_DATA: {\r
+        /* if this callback is reentered with data, we're in trouble. \r
+         * It's hard to imagine that Microsoft would allow callbacks \r
+         * to be reentrant -- isn't the model that this is like a \r
+         * hardware interrupt? -- but I've seen reentrant behavior \r
+         * using a debugger, so it happens.\r
+         */\r
+        long new_driver_time;\r
+        EnterCriticalSection(&m->lock);\r
+\r
+        /* dwParam1 is MIDI data received, packed into DWORD w/ 1st byte of\r
+                message LOB;\r
+           dwParam2 is time message received by input device driver, specified\r
+            in [ms] from when midiInStart called.\r
+           each message is expanded to include the status byte */\r
+\r
+        new_driver_time = dwParam2;\r
+\r
+        if ((dwParam1 & 0x80) == 0) {\r
+            /* not a status byte -- ignore it. This happened running the\r
+               sysex.c test under Win2K with MidiMan USB 1x1 interface,\r
+               but I can't reproduce it. -RBD\r
+             */\r
+            /* printf("non-status byte found\n"); */\r
+        } else { /* data to process */\r
+            PmEvent event;\r
+            if (midi->time_proc)\r
+                dwParam2 = (*midi->time_proc)(midi->time_info);\r
+            event.timestamp = dwParam2;\r
+            event.message = dwParam1;\r
+            pm_read_short(midi, &event);\r
+        }\r
+        LeaveCriticalSection(&m->lock);\r
+        break;\r
+    }\r
+    case MIM_LONGDATA: {\r
+        MIDIHDR *lpMidiHdr = (MIDIHDR *) dwParam1;\r
+        unsigned char *data = (unsigned char *) lpMidiHdr->lpData;\r
+        unsigned int processed = 0;\r
+        int remaining = lpMidiHdr->dwBytesRecorded;\r
+\r
+        EnterCriticalSection(&m->lock);\r
+        /* printf("midi_in_callback -- lpMidiHdr %x, %d bytes, %2x...\n", \r
+                lpMidiHdr, lpMidiHdr->dwBytesRecorded, *data); */\r
+        if (midi->time_proc)\r
+            dwParam2 = (*midi->time_proc)(midi->time_info);\r
+        /* can there be more than one message in one buffer? */\r
+        /* assume yes and iterate through them */\r
+        while (remaining > 0) {\r
+            unsigned int amt = pm_read_bytes(midi, data + processed, \r
+                                             remaining, dwParam2);\r
+            remaining -= amt;\r
+            processed += amt;\r
+        }\r
+\r
+        /* when a device is closed, the pending MIM_LONGDATA buffers are\r
+           returned to this callback with dwBytesRecorded == 0. In this\r
+           case, we do not want to send them back to the interface (if\r
+           we do, the interface will not close, and Windows OS may hang). */\r
+        if (lpMidiHdr->dwBytesRecorded > 0) {\r
+            MMRESULT rslt;\r
+            lpMidiHdr->dwBytesRecorded = 0;\r
+            lpMidiHdr->dwFlags = 0;\r
+                       \r
+            /* note: no error checking -- can this actually fail? */\r
+            rslt = midiInPrepareHeader(hMidiIn, lpMidiHdr, sizeof(MIDIHDR));\r
+            assert(rslt == MMSYSERR_NOERROR);\r
+            /* note: I don't think this can fail except possibly for\r
+             * MMSYSERR_NOMEM, but the pain of reporting this\r
+             * unlikely but probably catastrophic error does not seem\r
+             * worth it.\r
+             */\r
+            rslt = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR));\r
+            assert(rslt == MMSYSERR_NOERROR);\r
+            LeaveCriticalSection(&m->lock);\r
+        } else {\r
+            midiInUnprepareHeader(hMidiIn,lpMidiHdr,sizeof(MIDIHDR));\r
+            LeaveCriticalSection(&m->lock);\r
+            pm_free(lpMidiHdr);\r
+        }\r
+        break;\r
+    }\r
+    case MIM_OPEN:\r
+        break;\r
+    case MIM_CLOSE:\r
+        break;\r
+    case MIM_ERROR:\r
+        /* printf("MIM_ERROR\n"); */\r
+        break;\r
+    case MIM_LONGERROR:\r
+        /* printf("MIM_LONGERROR\n"); */\r
+        break;\r
+    default:\r
+        break;\r
+    }\r
+}\r
+\r
+/*\r
+=========================================================================================\r
+begin midi output implementation\r
+=========================================================================================\r
+*/\r
+\r
+/* begin helper routines used by midiOutStream interface */\r
+\r
+/* add_to_buffer -- adds timestamped short msg to buffer, returns fullp */\r
+static int add_to_buffer(midiwinmm_type m, LPMIDIHDR hdr,\r
+                         unsigned long delta, unsigned long msg)\r
+{\r
+    unsigned long *ptr = (unsigned long *)\r
+                         (hdr->lpData + hdr->dwBytesRecorded);\r
+    *ptr++ = delta; /* dwDeltaTime */\r
+    *ptr++ = 0;     /* dwStream */\r
+    *ptr++ = msg;   /* dwEvent */\r
+    hdr->dwBytesRecorded += 3 * sizeof(long);\r
+    /* if the addition of three more words (a message) would extend beyond\r
+       the buffer length, then return TRUE (full)\r
+     */\r
+    return hdr->dwBytesRecorded + 3 * sizeof(long) > hdr->dwBufferLength;\r
+}\r
+\r
+\r
+static PmTimestamp pm_time_get(midiwinmm_type m)\r
+{\r
+    MMTIME mmtime;\r
+    MMRESULT wRtn;\r
+    mmtime.wType = TIME_TICKS;\r
+    mmtime.u.ticks = 0;\r
+    wRtn = midiStreamPosition(m->handle.stream, &mmtime, sizeof(mmtime));\r
+    assert(wRtn == MMSYSERR_NOERROR);\r
+    return mmtime.u.ticks;\r
+}\r
+\r
+\r
+/* end helper routines used by midiOutStream interface */\r
+\r
+\r
+static PmError winmm_out_open(PmInternal *midi, void *driverInfo)\r
+{\r
+    DWORD dwDevice;\r
+    int i = midi->device_id;\r
+    midiwinmm_type m;\r
+    MIDIPROPTEMPO propdata;\r
+    MIDIPROPTIMEDIV divdata;\r
+    int max_sysex_len = midi->buffer_len * 4;\r
+    int output_buffer_len;\r
+    int num_buffers;\r
+    dwDevice = (DWORD) descriptors[i].descriptor;\r
+\r
+    /* create system dependent device data */\r
+    m = (midiwinmm_type) pm_alloc(sizeof(midiwinmm_node)); /* create */\r
+    midi->descriptor = m;\r
+    if (!m) goto no_memory;\r
+    m->handle.out = NULL;\r
+    m->buffers = NULL;\r
+    m->num_buffers = 0;\r
+    m->max_buffers = 0;\r
+    m->buffers_expanded = FALSE;\r
+    m->next_buffer = 0;\r
+#ifdef USE_SYSEX_BUFFERS\r
+    m->sysex_buffers[0] = NULL;\r
+    m->sysex_buffers[1] = NULL;\r
+    m->next_sysex_buffer = 0;\r
+#endif\r
+    m->last_time = 0;\r
+    m->first_message = TRUE; /* we treat first message as special case */\r
+    m->sysex_mode = FALSE;\r
+    m->sysex_word = 0;\r
+    m->sysex_byte_count = 0;\r
+    m->hdr = NULL;\r
+    m->sync_time = 0;\r
+    m->delta = 0;\r
+    m->error = MMSYSERR_NOERROR;\r
+\r
+    /* create a signal */\r
+    m->buffer_signal = CreateEvent(NULL, FALSE, FALSE, NULL);\r
+\r
+    /* this should only fail when there are very serious problems */\r
+    assert(m->buffer_signal);\r
+\r
+    /* open device */\r
+    if (midi->latency == 0) {\r
+        /* use simple midi out calls */\r
+        pm_hosterror = midiOutOpen(\r
+                (LPHMIDIOUT) & m->handle.out,  /* device Handle */\r
+               dwDevice,  /* device ID  */\r
+               /* note: same callback fn as for StreamOpen: */\r
+               (DWORD_PTR) winmm_streamout_callback, /* callback fn */\r
+               (DWORD_PTR) midi,  /* callback instance data */\r
+               CALLBACK_FUNCTION); /* callback type */\r
+    } else {\r
+        /* use stream-based midi output (schedulable in future) */\r
+        pm_hosterror = midiStreamOpen(\r
+               &m->handle.stream,  /* device Handle */\r
+               (LPUINT) & dwDevice,  /* device ID pointer */\r
+               1,  /* reserved, must be 1 */\r
+               (DWORD_PTR) winmm_streamout_callback,\r
+               (DWORD_PTR) midi,  /* callback instance data */\r
+               CALLBACK_FUNCTION);\r
+    }\r
+    if (pm_hosterror != MMSYSERR_NOERROR) {\r
+        goto free_descriptor;\r
+    }\r
+\r
+    if (midi->latency == 0) {\r
+        num_buffers = NUM_SIMPLE_SYSEX_BUFFERS;\r
+        output_buffer_len = max_sysex_len / num_buffers;\r
+        if (output_buffer_len < MIN_SIMPLE_SYSEX_LEN)\r
+            output_buffer_len = MIN_SIMPLE_SYSEX_LEN;\r
+    } else {\r
+        long dur = 0;\r
+        num_buffers = max(midi->buffer_len, midi->latency / 2);\r
+        if (num_buffers < MIN_STREAM_BUFFERS)\r
+            num_buffers = MIN_STREAM_BUFFERS;\r
+        output_buffer_len = STREAM_BUFFER_LEN;\r
+\r
+        propdata.cbStruct = sizeof(MIDIPROPTEMPO);\r
+        propdata.dwTempo = 480000; /* microseconds per quarter */\r
+        pm_hosterror = midiStreamProperty(m->handle.stream,\r
+                                          (LPBYTE) & propdata,\r
+                                          MIDIPROP_SET | MIDIPROP_TEMPO);\r
+        if (pm_hosterror) goto close_device;\r
+\r
+        divdata.cbStruct = sizeof(MIDIPROPTEMPO);\r
+        divdata.dwTimeDiv = 480;   /* divisions per quarter */\r
+        pm_hosterror = midiStreamProperty(m->handle.stream,\r
+                                          (LPBYTE) & divdata,\r
+                                          MIDIPROP_SET | MIDIPROP_TIMEDIV);\r
+        if (pm_hosterror) goto close_device;\r
+    }\r
+    /* allocate buffers */\r
+    if (allocate_buffers(m, output_buffer_len, num_buffers)) \r
+        goto free_buffers;\r
+    /* start device */\r
+    if (midi->latency != 0) {\r
+        pm_hosterror = midiStreamRestart(m->handle.stream);\r
+        if (pm_hosterror != MMSYSERR_NOERROR) goto free_buffers;\r
+    }\r
+    return pmNoError;\r
+\r
+free_buffers:\r
+    /* buffers are freed below by winmm_out_delete */\r
+close_device:\r
+    midiOutClose(m->handle.out);\r
+free_descriptor:\r
+    midi->descriptor = NULL;\r
+    winmm_out_delete(midi); /* frees buffers and m */\r
+no_memory:\r
+    if (pm_hosterror) {\r
+        int err = midiOutGetErrorText(pm_hosterror, (char *) pm_hosterror_text,\r
+                                      PM_HOST_ERROR_MSG_LEN);\r
+        assert(err == MMSYSERR_NOERROR);\r
+        return pmHostError;\r
+    }\r
+    return pmInsufficientMemory;\r
+}\r
+\r
+\r
+/* winmm_out_delete -- carefully free data associated with midi */\r
+/**/\r
+static void winmm_out_delete(PmInternal *midi)\r
+{\r
+    int i;\r
+    /* delete system dependent device data */\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    if (m) {\r
+        if (m->buffer_signal) {\r
+            /* don't report errors -- better not to stop cleanup */\r
+            CloseHandle(m->buffer_signal);\r
+        }\r
+        /* if using stream output, free buffers */\r
+        for (i = 0; i < m->num_buffers; i++) {\r
+            if (m->buffers[i]) pm_free(m->buffers[i]);\r
+        }\r
+        m->num_buffers = 0;\r
+        pm_free(m->buffers);\r
+        m->max_buffers = 0;\r
+#ifdef USE_SYSEX_BUFFERS\r
+        /* free sysex buffers */\r
+        for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {\r
+            if (m->sysex_buffers[i]) pm_free(m->sysex_buffers[i]);\r
+        }\r
+#endif\r
+    }\r
+    midi->descriptor = NULL;\r
+    pm_free(m); /* delete */\r
+}\r
+\r
+\r
+/* see comments for winmm_in_close */\r
+static PmError winmm_out_close(PmInternal *midi)\r
+{\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    if (m->handle.out) {\r
+        /* device to close */\r
+        if (midi->latency == 0) {\r
+            pm_hosterror = midiOutClose(m->handle.out);\r
+        } else {\r
+            pm_hosterror = midiStreamClose(m->handle.stream);\r
+        }\r
+        /* regardless of outcome, free memory */\r
+        winmm_out_delete(midi);\r
+    }\r
+    if (pm_hosterror) {\r
+        int err = midiOutGetErrorText(pm_hosterror,\r
+                                      (char *) pm_hosterror_text,\r
+                                      PM_HOST_ERROR_MSG_LEN);\r
+        assert(err == MMSYSERR_NOERROR);\r
+        return pmHostError;\r
+    }\r
+    return pmNoError;\r
+}\r
+\r
+\r
+static PmError winmm_out_abort(PmInternal *midi)\r
+{\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    m->error = MMSYSERR_NOERROR;\r
+\r
+    /* only stop output streams */\r
+    if (midi->latency > 0) {\r
+        m->error = midiStreamStop(m->handle.stream);\r
+    }\r
+    return m->error ? pmHostError : pmNoError;\r
+}\r
+\r
+\r
+static PmError winmm_write_flush(PmInternal *midi, PmTimestamp timestamp)\r
+{\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    assert(m);\r
+    if (m->hdr) {\r
+        m->error = midiOutPrepareHeader(m->handle.out, m->hdr, \r
+                                        sizeof(MIDIHDR));\r
+        if (m->error) {\r
+            /* do not send message */\r
+        } else if (midi->latency == 0) {\r
+            /* As pointed out by Nigel Brown, 20Sep06, dwBytesRecorded\r
+             * should be zero. This is set in get_free_sysex_buffer(). \r
+             * The msg length goes in dwBufferLength in spite of what\r
+             * Microsoft documentation says (or doesn't say). */\r
+            m->hdr->dwBufferLength = m->hdr->dwBytesRecorded;\r
+            m->hdr->dwBytesRecorded = 0;\r
+            m->error = midiOutLongMsg(m->handle.out, m->hdr, sizeof(MIDIHDR));\r
+        } else {\r
+            m->error = midiStreamOut(m->handle.stream, m->hdr, \r
+                                     sizeof(MIDIHDR));\r
+        }\r
+        midi->fill_base = NULL;\r
+        m->hdr = NULL;\r
+        if (m->error) {\r
+            m->hdr->dwFlags = 0; /* release the buffer */\r
+            return pmHostError;\r
+        }\r
+    }\r
+    return pmNoError;\r
+}\r
+\r
+\r
+\r
+#ifdef GARBAGE\r
+static PmError winmm_write_sysex_byte(PmInternal *midi, unsigned char byte)\r
+{\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    unsigned char *msg_buffer;\r
+\r
+    /* at the beginning of sysex, m->hdr is NULL */\r
+    if (!m->hdr) { /* allocate a buffer if none allocated yet */\r
+        m->hdr = get_free_output_buffer(midi);\r
+        if (!m->hdr) return pmInsufficientMemory;\r
+        m->sysex_byte_count = 0;\r
+    }\r
+    /* figure out where to write byte */\r
+    msg_buffer = (unsigned char *) (m->hdr->lpData);\r
+    assert(m->hdr->lpData == (char *) (m->hdr + 1));\r
+\r
+    /* check for overflow */\r
+    if (m->sysex_byte_count >= m->hdr->dwBufferLength) {\r
+        /* allocate a bigger message -- double it every time */\r
+        LPMIDIHDR big = allocate_buffer(m->sysex_byte_count * 2);\r
+        /* printf("expand to %d bytes\n", m->sysex_byte_count * 2); */\r
+        if (!big) return pmInsufficientMemory;\r
+        m->error = midiOutPrepareHeader(m->handle.out, big,\r
+                                        sizeof(MIDIHDR));\r
+        if (m->error) {\r
+            m->hdr = NULL;\r
+            return pmHostError;\r
+        }\r
+        memcpy(big->lpData, msg_buffer, m->sysex_byte_count);\r
+        msg_buffer = (unsigned char *) (big->lpData);\r
+        if (m->buffers[0] == m->hdr) {\r
+            m->buffers[0] = big;\r
+            pm_free(m->hdr);\r
+            /* printf("freed m->hdr\n"); */\r
+        } else if (m->buffers[1] == m->hdr) {\r
+            m->buffers[1] = big;\r
+            pm_free(m->hdr);\r
+            /* printf("freed m->hdr\n"); */\r
+        }\r
+        m->hdr = big;\r
+    }\r
+\r
+    /* append byte to message */\r
+    msg_buffer[m->sysex_byte_count++] = byte;\r
+\r
+    /* see if we have a complete message */\r
+    if (byte == MIDI_EOX) {\r
+        m->hdr->dwBytesRecorded = m->sysex_byte_count;\r
+        /*\r
+        { int i; int len = m->hdr->dwBytesRecorded;\r
+          printf("OutLongMsg %d ", len);\r
+          for (i = 0; i < len; i++) {\r
+              printf("%2x ", msg_buffer[i]);\r
+          }\r
+        }\r
+        */\r
+        m->error = midiOutLongMsg(m->handle.out, m->hdr, sizeof(MIDIHDR));\r
+        m->hdr = NULL; /* stop using this message buffer */\r
+        if (m->error) return pmHostError;\r
+    }\r
+    return pmNoError;\r
+}\r
+#endif\r
+\r
+\r
+static PmError winmm_write_short(PmInternal *midi, PmEvent *event)\r
+{\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    PmError rslt = pmNoError;\r
+    assert(m);\r
+\r
+    if (midi->latency == 0) { /* use midiOut interface, ignore timestamps */\r
+        m->error = midiOutShortMsg(m->handle.out, event->message);\r
+        if (m->error) rslt = pmHostError;\r
+    } else {  /* use midiStream interface -- pass data through buffers */\r
+        unsigned long when = event->timestamp;\r
+        unsigned long delta;\r
+        int full;\r
+        if (when == 0) when = midi->now;\r
+        /* when is in real_time; translate to intended stream time */\r
+        when = when + m->delta + midi->latency;\r
+        /* make sure we don't go backward in time */\r
+        if (when < m->last_time) when = m->last_time;\r
+        delta = when - m->last_time;\r
+        m->last_time = when;\r
+        /* before we insert any data, we must have a buffer */\r
+        if (m->hdr == NULL) {\r
+            /* stream interface: buffers allocated when stream is opened */\r
+            m->hdr = get_free_output_buffer(midi);\r
+        }\r
+        full = add_to_buffer(m, m->hdr, delta, event->message);\r
+        if (full) rslt = winmm_write_flush(midi, when);\r
+    }\r
+    return rslt;\r
+}\r
+\r
+#define winmm_begin_sysex winmm_write_flush\r
+#ifndef winmm_begin_sysex\r
+static PmError winmm_begin_sysex(PmInternal *midi, PmTimestamp timestamp)\r
+{\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    PmError rslt = pmNoError;\r
+\r
+    if (midi->latency == 0) {\r
+        /* do nothing -- it's handled in winmm_write_byte */\r
+    } else {\r
+        /* sysex expects an empty sysex buffer, so send whatever is here */\r
+        rslt = winmm_write_flush(midi);\r
+    }\r
+    return rslt;\r
+}\r
+#endif\r
+\r
+static PmError winmm_end_sysex(PmInternal *midi, PmTimestamp timestamp)\r
+{\r
+    /* could check for callback_error here, but I haven't checked\r
+     * what happens if we exit early and don't finish the sysex msg\r
+     * and clean up\r
+     */\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    PmError rslt = pmNoError;\r
+    LPMIDIHDR hdr = m->hdr;\r
+    if (!hdr) return rslt; /* something bad happened earlier,\r
+            do not report an error because it would have been \r
+            reported (at least) once already */\r
+    /* a(n old) version of MIDI YOKE requires a zero byte after\r
+     * the sysex message, but do not increment dwBytesRecorded: */\r
+    hdr->lpData[hdr->dwBytesRecorded] = 0;\r
+    if (midi->latency == 0) {\r
+#ifdef DEBUG_PRINT_BEFORE_SENDING_SYSEX\r
+        /* DEBUG CODE: */\r
+        { int i; int len = m->hdr->dwBufferLength;\r
+          printf("OutLongMsg %d ", len);\r
+          for (i = 0; i < len; i++) {\r
+              printf("%2x ", (unsigned char) (m->hdr->lpData[i]));\r
+          }\r
+        }\r
+#endif\r
+    } else {\r
+        /* Using stream interface. There are accumulated bytes in m->hdr\r
+           to send using midiStreamOut\r
+         */\r
+        /* add bytes recorded to MIDIEVENT length, but don't\r
+           count the MIDIEVENT data (3 longs) */\r
+        MIDIEVENT *evt = (MIDIEVENT *) (hdr->lpData);\r
+        evt->dwEvent += hdr->dwBytesRecorded - 3 * sizeof(long);\r
+        /* round up BytesRecorded to multiple of 4 */\r
+        hdr->dwBytesRecorded = (hdr->dwBytesRecorded + 3) & ~3;\r
+    }\r
+    rslt = winmm_write_flush(midi, timestamp);\r
+    return rslt;\r
+}\r
+\r
+\r
+static PmError winmm_write_byte(PmInternal *midi, unsigned char byte,\r
+                                PmTimestamp timestamp)\r
+{\r
+    /* write a sysex byte */\r
+    PmError rslt = pmNoError;\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    LPMIDIHDR hdr = m->hdr;\r
+    unsigned char *msg_buffer;\r
+    assert(m);\r
+    if (!hdr) {\r
+        m->hdr = hdr = get_free_output_buffer(midi);\r
+        assert(hdr);\r
+        midi->fill_base = (unsigned char *) m->hdr->lpData;\r
+        midi->fill_offset_ptr = &(hdr->dwBytesRecorded);\r
+        /* when buffer fills, Pm_WriteSysEx will revert to calling\r
+         * pmwin_write_byte, which expect to have space, so leave\r
+         * one byte free for pmwin_write_byte. Leave another byte\r
+         * of space for zero after message to make early version of \r
+         * MIDI YOKE driver happy -- therefore dwBufferLength - 2 */\r
+        midi->fill_length = hdr->dwBufferLength - 2;\r
+        if (midi->latency != 0) {\r
+            unsigned long when = (unsigned long) timestamp;\r
+            unsigned long delta;\r
+            unsigned long *ptr;\r
+            if (when == 0) when = midi->now;\r
+            /* when is in real_time; translate to intended stream time */\r
+            when = when + m->delta + midi->latency;\r
+            /* make sure we don't go backward in time */\r
+            if (when < m->last_time) when = m->last_time;\r
+            delta = when - m->last_time;\r
+            m->last_time = when;\r
+\r
+            ptr = (unsigned long *) hdr->lpData;\r
+            *ptr++ = delta;\r
+            *ptr++ = 0;\r
+            *ptr = MEVT_F_LONG;\r
+            hdr->dwBytesRecorded = 3 * sizeof(long);\r
+            /* data will be added at an offset of dwBytesRecorded ... */\r
+        }\r
+    }\r
+    /* add the data byte */\r
+    msg_buffer = (unsigned char *) (hdr->lpData);\r
+    msg_buffer[hdr->dwBytesRecorded++] = byte;\r
+\r
+    /* see if buffer is full, leave one byte extra for pad */\r
+    if (hdr->dwBytesRecorded >= hdr->dwBufferLength - 1) {\r
+        /* write what we've got and continue */\r
+        rslt = winmm_end_sysex(midi, timestamp); \r
+    }\r
+    return rslt;\r
+}\r
+\r
+#ifdef EXPANDING_SYSEX_BUFFERS\r
+note: this code is here as an aid in case you want sysex buffers\r
+      to expand to hold large messages completely. If so, you\r
+      will want to change SYSEX_BYTES_PER_BUFFER above to some\r
+      variable that remembers the buffer size. A good place to \r
+      put this value would be in the hdr->dwUser field.\r
+\r
+            rslt = resize_sysex_buffer(midi, m->sysex_byte_count, \r
+                                       m->sysex_byte_count * 2);\r
+\r
+            if (rslt == pmBufferMaxSize) /* if the buffer can't be resized */\r
+#endif\r
+#ifdef EXPANDING_SYSEX_BUFFERS\r
+            int bytesRecorded = hdr->dwBytesRecorded; /* this field gets wiped out, so we'll save it */\r
+            rslt = resize_sysex_buffer(midi, bytesRecorded, 2 * bytesRecorded);\r
+            hdr->dwBytesRecorded = bytesRecorded;\r
+\r
+            if (rslt == pmBufferMaxSize) /* if buffer can't be resized */\r
+#endif\r
+\r
+\r
+\r
+static PmTimestamp winmm_synchronize(PmInternal *midi)\r
+{\r
+    midiwinmm_type m;\r
+    unsigned long pm_stream_time_2;\r
+    unsigned long real_time;\r
+    unsigned long pm_stream_time;\r
+\r
+    /* only synchronize if we are using stream interface */\r
+    if (midi->latency == 0) return 0;\r
+\r
+    /* figure out the time */\r
+    m = (midiwinmm_type) midi->descriptor;\r
+    pm_stream_time_2 = pm_time_get(m);\r
+\r
+    do {\r
+        /* read real_time between two reads of stream time */\r
+        pm_stream_time = pm_stream_time_2;\r
+        real_time = (*midi->time_proc)(midi->time_info);\r
+        pm_stream_time_2 = pm_time_get(m);\r
+        /* repeat if more than 1ms elapsed */\r
+    } while (pm_stream_time_2 > pm_stream_time + 1);\r
+    m->delta = pm_stream_time - real_time;\r
+    m->sync_time = real_time;\r
+    return real_time;\r
+}\r
+\r
+#ifdef USE_SYSEX_BUFFERS\r
+/* winmm_out_callback -- recycle sysex buffers */\r
+static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg,\r
+                                        DWORD dwInstance, DWORD dwParam1, \r
+                                        DWORD dwParam2)\r
+{\r
+    PmInternal *midi = (PmInternal *) dwInstance;\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    LPMIDIHDR hdr = (LPMIDIHDR) dwParam1;\r
+    int err = 0;  /* set to 0 so that no buffer match will also be an error */\r
+\r
+    /* Future optimization: eliminate UnprepareHeader calls -- they aren't\r
+       necessary; however, this code uses the prepared-flag to indicate which\r
+       buffers are free, so we need to do something to flag empty buffers if\r
+       we leave them prepared\r
+     */\r
+    /*\r
+    printf("out_callback: hdr %x, wMsg %x, MOM_DONE %x\n", \r
+           hdr, wMsg, MOM_DONE);\r
+    */\r
+    if (wMsg == MOM_DONE) {\r
+        MMRESULT ret = midiOutUnprepareHeader(m->handle.out, hdr, \r
+                                              sizeof(MIDIHDR));\r
+        assert(ret == MMSYSERR_NOERROR);\r
+    }\r
+    /* notify waiting sender that a buffer is available */\r
+    err = SetEvent(m->buffer_signal);\r
+    assert(err); /* false -> error */\r
+}\r
+#endif\r
+\r
+/* winmm_streamout_callback -- unprepare (free) buffer header */\r
+static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg,\r
+        DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)\r
+{\r
+    PmInternal *midi = (PmInternal *) dwInstance;\r
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+    LPMIDIHDR hdr = (LPMIDIHDR) dwParam1;\r
+    int err;\r
+\r
+    /* Even if an error is pending, I think we should unprepare msgs and\r
+       signal their arrival\r
+     */\r
+    /* printf("streamout_callback: hdr %x, wMsg %x, MOM_DONE %x\n", \r
+           hdr, wMsg, MOM_DONE); */\r
+    if (wMsg == MOM_DONE) {\r
+        MMRESULT ret = midiOutUnprepareHeader(m->handle.out, hdr, \r
+                                              sizeof(MIDIHDR));\r
+        assert(ret == MMSYSERR_NOERROR);\r
+    }\r
+    /* signal client in case it is blocked waiting for buffer */\r
+    err = SetEvent(m->buffer_signal);\r
+    assert(err); /* false -> error */\r
+}\r
+\r
+\r
+/*\r
+=========================================================================================\r
+begin exported functions\r
+=========================================================================================\r
+*/\r
+\r
+#define winmm_in_abort pm_fail_fn\r
+pm_fns_node pm_winmm_in_dictionary = {\r
+                                         none_write_short,\r
+                                         none_sysex,\r
+                                         none_sysex,\r
+                                         none_write_byte,\r
+                                         none_write_short,\r
+                                         none_write_flush,\r
+                                         winmm_synchronize,\r
+                                         winmm_in_open,\r
+                                         winmm_in_abort,\r
+                                         winmm_in_close,\r
+                                         winmm_in_poll,\r
+                                         winmm_has_host_error,\r
+                                         winmm_get_host_error\r
+                                     };\r
+\r
+pm_fns_node pm_winmm_out_dictionary = {\r
+                                          winmm_write_short,\r
+                                          winmm_begin_sysex,\r
+                                          winmm_end_sysex,\r
+                                          winmm_write_byte,\r
+                                          winmm_write_short,  /* short realtime message */\r
+                                          winmm_write_flush,\r
+                                          winmm_synchronize,\r
+                                          winmm_out_open,\r
+                                          winmm_out_abort,\r
+                                          winmm_out_close,\r
+                                          none_poll,\r
+                                          winmm_has_host_error,\r
+                                          winmm_get_host_error\r
+                                      };\r
+\r
+\r
+/* initialize winmm interface. Note that if there is something wrong\r
+   with winmm (e.g. it is not supported or installed), it is not an\r
+   error. We should simply return without having added any devices to\r
+   the table. Hence, no error code is returned. Furthermore, this init\r
+   code is called along with every other supported interface, so the\r
+   user would have a very hard time figuring out what hardware and API\r
+   generated the error. Finally, it would add complexity to pmwin.c to\r
+   remember where the error code came from in order to convert to text.\r
+ */\r
+void pm_winmm_init( void )\r
+{\r
+    pm_winmm_mapper_input();\r
+    pm_winmm_mapper_output();\r
+    pm_winmm_general_inputs();\r
+    pm_winmm_general_outputs();\r
+}\r
+\r
+\r
+/* no error codes are returned, even if errors are encountered, because\r
+   there is probably nothing the user could do (e.g. it would be an error\r
+   to retry.\r
+ */\r
+void pm_winmm_term( void )\r
+{\r
+    int i;\r
+#ifdef DEBUG\r
+    char msg[PM_HOST_ERROR_MSG_LEN];\r
+#endif\r
+    int doneAny = 0;\r
+#ifdef DEBUG\r
+    printf("pm_winmm_term called\n");\r
+#endif\r
+    for (i = 0; i < pm_descriptor_index; i++) {\r
+        PmInternal * midi = descriptors[i].internalDescriptor;\r
+        if (midi) {\r
+            midiwinmm_type m = (midiwinmm_type) midi->descriptor;\r
+            if (m->handle.out) {\r
+                /* close next open device*/\r
+#ifdef DEBUG\r
+                if (doneAny == 0) {\r
+                    printf("begin closing open devices...\n");\r
+                    doneAny = 1;\r
+                }\r
+                /* report any host errors; this EXTEREMELY useful when\r
+                   trying to debug client app */\r
+                if (winmm_has_host_error(midi)) {\r
+                    winmm_get_host_error(midi, msg, PM_HOST_ERROR_MSG_LEN);\r
+                    printf("%s\n", msg);\r
+                }\r
+#endif\r
+                /* close all open ports */\r
+                (*midi->dictionary->close)(midi);\r
+            }\r
+        }\r
+    }\r
+    if (midi_in_caps) {\r
+        pm_free(midi_in_caps);\r
+        midi_in_caps = NULL;\r
+    }\r
+    if (midi_out_caps) {\r
+        pm_free(midi_out_caps);\r
+        midi_out_caps = NULL;\r
+    }\r
+#ifdef DEBUG\r
+    if (doneAny) {\r
+        printf("warning: devices were left open. They have been closed.\n");\r
+    }\r
+    printf("pm_winmm_term exiting\n");\r
+#endif\r
+    pm_descriptor_index = 0;\r
+}\r
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.h b/libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.h
new file mode 100644 (file)
index 0000000..53c5fe2
--- /dev/null
@@ -0,0 +1,5 @@
+/* midiwin32.h -- system-specific definitions */\r
+\r
+void pm_winmm_init( void );\r
+void pm_winmm_term( void );\r
+\r
diff --git a/libs/backends/wavesaudio/portmidi/src/porttime/ptmacosx_mach.c b/libs/backends/wavesaudio/portmidi/src/porttime/ptmacosx_mach.c
new file mode 100644 (file)
index 0000000..753f583
--- /dev/null
@@ -0,0 +1,131 @@
+/* ptmacosx.c -- portable timer implementation for mac os x */\r
+\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <CoreAudio/HostTime.h>\r
+\r
+#import <mach/mach.h>\r
+#import <mach/mach_error.h>\r
+#import <mach/mach_time.h>\r
+#import <mach/clock.h>\r
+#include <unistd.h>\r
+\r
+#include "porttime.h"\r
+#include "sys/time.h"\r
+#include "pthread.h"\r
+\r
+#define NSEC_PER_MSEC 1000000\r
+#define THREAD_IMPORTANCE 30\r
+\r
+static int time_started_flag = FALSE;\r
+static UInt64 start_time;\r
+static pthread_t pt_thread_pid;\r
+\r
+/* note that this is static data -- we only need one copy */\r
+typedef struct {\r
+    int id;\r
+    int resolution;\r
+    PtCallback *callback;\r
+    void *userData;\r
+} pt_callback_parameters;\r
+\r
+static int pt_callback_proc_id = 0;\r
+\r
+static void *Pt_CallbackProc(void *p)\r
+{\r
+    pt_callback_parameters *parameters = (pt_callback_parameters *) p;\r
+    int mytime = 1;\r
+\r
+    kern_return_t error;\r
+    thread_extended_policy_data_t extendedPolicy;\r
+    thread_precedence_policy_data_t precedencePolicy;\r
+\r
+    extendedPolicy.timeshare = 0;\r
+    error = thread_policy_set(mach_thread_self(), THREAD_EXTENDED_POLICY,\r
+                              (thread_policy_t)&extendedPolicy,\r
+                              THREAD_EXTENDED_POLICY_COUNT);\r
+    if (error != KERN_SUCCESS) {\r
+        mach_error("Couldn't set thread timeshare policy", error);\r
+    }\r
+\r
+    precedencePolicy.importance = THREAD_IMPORTANCE;\r
+    error = thread_policy_set(mach_thread_self(), THREAD_PRECEDENCE_POLICY,\r
+                              (thread_policy_t)&precedencePolicy,\r
+                              THREAD_PRECEDENCE_POLICY_COUNT);\r
+    if (error != KERN_SUCCESS) {\r
+        mach_error("Couldn't set thread precedence policy", error);\r
+    }\r
+    \r
+    \r
+    /* to kill a process, just increment the pt_callback_proc_id */\r
+    /* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id, parameters->id); */\r
+    while (pt_callback_proc_id == parameters->id) {\r
+        /* wait for a multiple of resolution ms */\r
+        UInt64 wait_time;\r
+        int delay = mytime++ * parameters->resolution - Pt_Time();\r
+       PtTimestamp timestamp;\r
+        if (delay < 0) delay = 0;\r
+        wait_time = AudioConvertNanosToHostTime((UInt64)delay * NSEC_PER_MSEC);\r
+        wait_time += AudioGetCurrentHostTime();\r
+        error = mach_wait_until(wait_time);\r
+       timestamp = Pt_Time();\r
+        (*(parameters->callback))(timestamp, parameters->userData);\r
+    }\r
+    free(parameters);\r
+    return NULL;\r
+}\r
+\r
+\r
+PtError Pt_Start(int resolution, PtCallback *callback, void *userData)\r
+{\r
+    if (time_started_flag) return ptAlreadyStarted;\r
+    start_time = AudioGetCurrentHostTime();\r
+    \r
+    if (callback) {\r
+        int res;\r
+        pt_callback_parameters *parms;\r
+\r
+        parms = (pt_callback_parameters *) malloc(sizeof(pt_callback_parameters));\r
+        if (!parms) return ptInsufficientMemory;\r
+        parms->id = pt_callback_proc_id;\r
+        parms->resolution = resolution;\r
+        parms->callback = callback;\r
+        parms->userData = userData;\r
+        res = pthread_create(&pt_thread_pid, NULL, Pt_CallbackProc, parms);\r
+        if (res != 0) return ptHostError;\r
+    }\r
+    \r
+    time_started_flag = TRUE;\r
+    return ptNoError;\r
+}\r
+\r
+\r
+PtError Pt_Stop()\r
+{\r
+    /* printf("Pt_Stop called\n"); */\r
+    pt_callback_proc_id++;\r
+    pthread_join(pt_thread_pid, NULL);\r
+    time_started_flag = FALSE;\r
+    return ptNoError;\r
+}\r
+\r
+\r
+int Pt_Started()\r
+{\r
+    return time_started_flag;\r
+}\r
+\r
+\r
+PtTimestamp Pt_Time()\r
+{\r
+    UInt64 clock_time, nsec_time;\r
+    clock_time = AudioGetCurrentHostTime() - start_time;\r
+    nsec_time = AudioConvertHostTimeToNanos(clock_time);\r
+    return (PtTimestamp)(nsec_time / NSEC_PER_MSEC);\r
+}\r
+\r
+\r
+void Pt_Sleep(int32_t duration)\r
+{\r
+    usleep(duration * 1000);\r
+}\r
diff --git a/libs/backends/wavesaudio/waves_audiobackend.cc b/libs/backends/wavesaudio/waves_audiobackend.cc
new file mode 100644 (file)
index 0000000..fbadc4c
--- /dev/null
@@ -0,0 +1,1203 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+#include "waves_audiobackend.h"\r
+#include "waves_audioport.h"\r
+#include "waves_midiport.h"\r
+\r
+using namespace ARDOUR;\r
+\r
+void WavesAudioBackend::AudioDeviceManagerNotification (NotificationReason reason, void* parameter)\r
+{\r
+    switch (reason) {\r
+        case WCMRAudioDeviceManagerClient::DeviceDebugInfo:\r
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::DeviceDebugInfo -- " << (char*)parameter << std::endl;\r
+        break;\r
+        case WCMRAudioDeviceManagerClient::BufferSizeChanged:\r
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::BufferSizeChanged" << std::endl;\r
+        break;\r
+        case WCMRAudioDeviceManagerClient::RequestReset:\r
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::RequestReset" << std::endl;\r
+            break;\r
+        case WCMRAudioDeviceManagerClient::RequestResync:\r
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::RequestResync" << std::endl;\r
+            break;\r
+        case WCMRAudioDeviceManagerClient::SamplingRateChanged:\r
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::SamplingRateChanged: " << (int64_t)parameter << std::endl;\r
+            break;\r
+        case WCMRAudioDeviceManagerClient::DeviceDroppedSamples:\r
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::DeviceDroppedSamples" << std::endl;\r
+            break;\r
+        case WCMRAudioDeviceManagerClient::DeviceStoppedStreaming:\r
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::DeviceStoppedStreaming" << std::endl;\r
+            break;\r
+        case WCMRAudioDeviceManagerClient::DeviceConnectionLost:\r
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::DeviceConnectionLost" << std::endl;\r
+            break;\r
+        case WCMRAudioDeviceManagerClient::DeviceListChanged:\r
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::DeviceListChanged" << std::endl;\r
+            break;\r
+        case WCMRAudioDeviceManagerClient::AudioCallback:\r
+            if (parameter) {\r
+                AudioCallbackData* audio_callback_data = (AudioCallbackData*)parameter;\r
+                _audio_device_callback (\r
+                    audio_callback_data->acdInputBuffer,\r
+                    audio_callback_data->acdOutputBuffer,\r
+                    audio_callback_data->acdFrames,\r
+                    audio_callback_data->acdSampleTime,\r
+                    audio_callback_data->acdCycleStartTimeNanos\r
+                );\r
+            }\r
+        break;\r
+        \r
+        default:\r
+        break;\r
+    };\r
+}\r
+\r
+\r
+WavesAudioBackend::WavesAudioBackend (AudioEngine& e)\r
+    : AudioBackend (e)\r
+    , _audio_device_manager (this)\r
+    , _midi_device_manager (*this)\r
+    , _device (NULL)\r
+    , _sample_format (FormatFloat)\r
+    , _interleaved (true)\r
+    , _input_channels (0)\r
+    , _max_input_channels (0)\r
+    , _output_channels (0)\r
+    , _max_output_channels (0)\r
+    , _sample_rate (0)\r
+    , _buffer_size (0)\r
+    , _systemic_input_latency (0)\r
+    , _systemic_output_latency (0)\r
+    , _call_thread_init_callback (false)\r
+    , _use_midi (false)\r
+    , _sample_time_at_cycle_start (0)\r
+    , _freewheeling (false)\r
+    , _freewheel_thread_active (false)\r
+    , _audio_cycle_period_nanos (0)\r
+    , _dsp_load_accumulator (0)\r
+    , _dsp_load_history_length(0)\r
+{\r
+}\r
+\r
+\r
+WavesAudioBackend::~WavesAudioBackend ()\r
+{\r
+}\r
+\r
+std::string\r
+WavesAudioBackend::name () const\r
+{\r
+#ifdef __MACOS__\r
+    return std::string ("CoreAudio");\r
+#elif _WINDOWS\r
+    return std::string ("ASIO");\r
+#endif\r
+}\r
+\r
+\r
+bool\r
+WavesAudioBackend::is_realtime () const\r
+{\r
+    return true;\r
+}\r
+\r
+\r
+bool \r
+WavesAudioBackend::requires_driver_selection () const\r
+{ \r
+    return false; \r
+}\r
+\r
+\r
+std::vector<std::string> \r
+WavesAudioBackend::enumerate_drivers () const\r
+{ \r
+    // this backend does not suppose driver selection\r
+    assert (false);\r
+\r
+    return std::vector<std::string> (); \r
+}\r
+\r
+\r
+int \r
+WavesAudioBackend::set_driver (const std::string& /*drivername*/)\r
+{\r
+    //Waves audio backend does not suppose driver selection\r
+    assert (false);\r
+\r
+    return -1; \r
+}\r
+\r
+\r
+std::vector<AudioBackend::DeviceStatus> \r
+WavesAudioBackend::enumerate_devices () const\r
+{   \r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::enumerate_devices (): " << std::endl;\r
+\r
+    std::vector<DeviceStatus> devicesStatus;\r
+    const WCMRAudioDeviceList& devices = _audio_device_manager.Devices (); \r
+\r
+    for (WCMRAudioDeviceListConstIter deviceIter = devices.begin ();  deviceIter != devices.end (); ++deviceIter) {\r
+        /* COMMENTED DBG LOGS */ std::cout << "\t Device found: " << (*deviceIter)->DeviceName () << std::endl;\r
+        devicesStatus.push_back (DeviceStatus ((*deviceIter)->DeviceName (), true));\r
+    }\r
+    \r
+    return devicesStatus;\r
+} \r
+\r
+\r
+std::vector<float> \r
+WavesAudioBackend::available_sample_rates (const std::string& device_name) const\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::available_sample_rates (): [" << device_name << "]" << std::endl;\r
+\r
+    std::vector<int> sr;\r
+\r
+    WCMRAudioDevice * device = _audio_device_manager.GetDeviceByName (device_name);\r
+\r
+    if (!device) {\r
+        std::cerr << "WavesAudioBackend::available_sample_rates (): Failed to find device [" << device_name << "]" << std::endl;\r
+        return std::vector<float> ();\r
+    }\r
+\r
+    sr = device->SamplingRates ();\r
+    /* COMMENTED DBG LOGS */ std::cout << "\tFound " << sr.size () << " sample rates for " << device->DeviceName () << ":";\r
+\r
+    std::vector<float> sample_rates (sr.begin (), sr.end ());\r
+    \r
+    /* COMMENTED DBG LOGS */ for (std::vector<float>::iterator i = sample_rates.begin ();  i != sample_rates.end (); ++i) std::cout << " " << *i; std::cout << std::endl;\r
+\r
+    return sample_rates;\r
+}\r
+\r
+\r
+float WavesAudioBackend::default_sample_rate () const \r
+{ \r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::default_sample_rate ():" << std::endl;\r
+    return AudioBackend::default_sample_rate (); \r
+}\r
+\r
+\r
+std::vector<uint32_t> \r
+WavesAudioBackend::available_buffer_sizes (const std::string& device_name) const\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::available_buffer_sizes (): [" << device_name << "]" << std::endl;\r
+\r
+    WCMRAudioDevice * device = _audio_device_manager.GetDeviceByName (device_name);\r
+    if (!device) {\r
+        std::cerr << "WavesAudioBackend::available_buffer_sizes (): Failed to find device [" << device_name << "]" << std::endl;\r
+        return std::vector<uint32_t> ();\r
+    }\r
+\r
+    std::vector<uint32_t> buffer_sizes (device->BufferSizes ().begin (), device->BufferSizes ().end ());\r
+\r
+    /* COMMENTED DBG LOGS */ std::cout << "\tFound " << buffer_sizes.size () << " buffer sizes for " << device->DeviceName () << ":";\r
+    /* COMMENTED DBG LOGS */ for (std::vector<uint32_t>::const_iterator i = buffer_sizes.begin ();  i != buffer_sizes.end (); ++i) std::cout << " " << *i; std::cout << std::endl;\r
+\r
+    return buffer_sizes;\r
+}\r
+\r
+\r
+uint32_t \r
+WavesAudioBackend::available_input_channel_count (const std::string& device_name) const\r
+{\r
+    \r
+    WCMRAudioDevice * device = _audio_device_manager.GetDeviceByName (device_name);\r
+\r
+    if (!device) {\r
+        std::cerr << "WavesAudioBackend::available_input_channel_count (): Failed to find device [" << device_name << "]" << std::endl;\r
+        return 0;\r
+    }\r
+\r
+    uint32_t num_of_input_channels = device->InputChannels ().size ();\r
+\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::available_input_channel_count (): " << num_of_input_channels << std::endl;\r
+    return num_of_input_channels;\r
+}\r
+\r
+\r
+uint32_t \r
+WavesAudioBackend::available_output_channel_count (const std::string& device_name) const\r
+{\r
+    std::vector<std::string> output_channels;\r
\r
+    WCMRAudioDevice * device = _audio_device_manager.GetDeviceByName (device_name);\r
+    if (!device) {\r
+        std::cerr << "WavesAudioBackend::available_output_channel_count (): Failed to find device [" << device_name << "]" << std::endl;\r
+        return 0;\r
+    }\r
+\r
+    uint32_t num_of_output_channels = device->OutputChannels ().size ();\r
+\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::available_output_channel_count (): " << num_of_output_channels << std::endl;\r
+\r
+    return num_of_output_channels;\r
+}\r
+\r
+\r
+bool\r
+WavesAudioBackend::can_change_sample_rate_when_running () const\r
+{\r
+    // VERIFY IT CAREFULLY\r
+    return true;\r
+}\r
+\r
+\r
+bool\r
+WavesAudioBackend::can_change_buffer_size_when_running () const\r
+{\r
+    // VERIFY IT CAREFULLY\r
+    return true;\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::set_device_name (const std::string& device_name)\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_device_name (): " << device_name << std::endl;\r
+    \r
+    if (_ports.size ()) {\r
+        std::cerr << "WavesAudioBackend::set_device_name (): There are unregistered ports left after [" << (_device ? _device->DeviceName () : std::string ("<NULL>")) << "]!" << std::endl;\r
+        for (size_t i = 0; i < _ports.size (); ++i) {\r
+            std::cerr << "\t[" << _ports[i]->name () << "]!" << std::endl;\r
+        }\r
+        return -1;\r
+    }\r
+\r
+    WCMRAudioDevice * device = _audio_device_manager.GetDeviceByName (device_name);\r
+\r
+    if (!device) {\r
+        std::cerr << "WavesAudioBackend::set_device_name (): Failed to find device [" << device_name << "]!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    WTErr retVal;\r
+    if (_device) {\r
+        retVal = _device->SetActive (false);\r
+        if (retVal != eNoErr) {\r
+            std::cerr << "WavesAudioBackend::set_device_name (): [" << _device->DeviceName () << "]->SetActive (false) failed!" << std::endl;\r
+            return -1;\r
+        }\r
+    }\r
+\r
+    _device = NULL;\r
+\r
+    retVal = device->SetActive (true);\r
+    if (retVal != eNoErr) {\r
+        std::cerr << "WavesAudioBackend::set_device_name (): [" << device->DeviceName () << "]->SetActive () failed!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    _device = device;\r
+    return 0;\r
+}\r
+\r
+\r
+int \r
+WavesAudioBackend::set_sample_rate (float sample_rate)\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_sample_rate (): " << sample_rate << std::endl;\r
+    \r
+    WTErr retVal = eNoErr;\r
+\r
+    if (!_device) {\r
+        std::cerr << "WavesAudioBackend::set_sample_rate (): No device is set!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    \r
+    bool device_needs_restart = _device->Streaming ();\r
+    \r
+    if (device_needs_restart) {\r
+        retVal  = _device->SetStreaming (false);\r
+        /* COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->_device->SetStreaming (false);"<< std::endl;\r
+        if (retVal != eNoErr) {\r
+            std::cerr << "WavesAudioBackend::set_sample_rate (): [" << _device->DeviceName () << "]->SetStreaming (false) failed (" << retVal << ") !" << std::endl;\r
+            return -1;\r
+        }\r
+    }\r
+    \r
+    retVal = _device->SetCurrentSamplingRate ((int)sample_rate);\r
+    \r
+    if (retVal != eNoErr) {\r
+        std::cerr << "WavesAudioBackend::set_sample_rate (): [" << _device->DeviceName() << "]->SetCurrentSamplingRate ((int)" << sample_rate << ") failed (" << retVal << ") !" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    _sample_rate = sample_rate;\r
+    _init_dsp_load_history();\r
+    engine.sample_rate_change (sample_rate);\r
+    \r
+    if (device_needs_restart) {\r
+        /* COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetStreaming (true);"<< std::endl;\r
+        _call_thread_init_callback = true;\r
+        retVal  = _device->SetStreaming (true);\r
+        if (retVal != eNoErr) {\r
+            std::cerr << "WavesAudioBackend::set_sample_rate (): [" << _device->DeviceName () << "]->SetStreaming (true) failed (" << retVal << ") !" << std::endl;\r
+            return -1;\r
+        }\r
+    }\r
+    return 0;\r
+}\r
+\r
+\r
+int \r
+WavesAudioBackend::set_buffer_size (uint32_t buffer_size)\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_buffer_size (): " << buffer_size << std::endl;\r
+\r
+    WTErr retVal = eNoErr;\r
+\r
+    if (!_device) {\r
+        std::cerr << "WavesAudioBackend::set_buffer_size (): No device is set!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    bool device_needs_restart = _device->Streaming ();\r
+    \r
+    if (device_needs_restart) {\r
+        retVal  = _device->SetStreaming (false);\r
+        /* COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetStreaming (false);"<< std::endl;\r
+        if (retVal != eNoErr) {\r
+            std::cerr << "WavesAudioBackend::set_buffer_size (): [" << _device->DeviceName () << "]->SetStreaming (false) failed (" << retVal << ") !" << std::endl;\r
+            return -1;\r
+        }\r
+    }\r
+    \r
+    retVal = _device->SetCurrentBufferSize (buffer_size);\r
+    \r
+    if (retVal != eNoErr) {\r
+        std::cerr << "WavesAudioBackend::set_sample_rate (): [" << _device->DeviceName() << "]->SetCurrentBufferSize (" << buffer_size << ") failed (" << retVal << ") !" << std::endl;\r
+        return -1;\r
+    }\r
+    \r
+    _buffer_size = buffer_size;\r
+    _init_dsp_load_history();\r
+    engine.buffer_size_change (buffer_size);\r
+    \r
+    if (device_needs_restart) {\r
+        /* COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetStreaming (true);"<< std::endl;\r
+        _call_thread_init_callback = true;\r
+        retVal  = _device->SetStreaming (true);\r
+        if (retVal != eNoErr) {\r
+            std::cerr << "WavesAudioBackend::set_buffer_size (): [" << _device->DeviceName () << "]->SetStreaming (true) failed (" << retVal << ") !" << std::endl;\r
+            return -1;\r
+        }\r
+    }\r
+    \r
+    return 0;\r
+}\r
+\r
+\r
+int \r
+WavesAudioBackend::set_sample_format (SampleFormat sample_format)\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_sample_format (): " << sample_format << std::endl;\r
+\r
+    _sample_format = sample_format;\r
+    return 0;\r
+}\r
+\r
+\r
+int \r
+WavesAudioBackend::set_interleaved (bool yn)\r
+{\r
+    /*you can ignore them totally*/\r
+    _interleaved = yn;\r
+    return 0;\r
+}\r
+\r
+\r
+int \r
+WavesAudioBackend::set_input_channels (uint32_t input_channels)\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_input_channels (): " << input_channels << std::endl;\r
+\r
+    _input_channels = input_channels;\r
+    return 0;\r
+}\r
+\r
+\r
+int \r
+WavesAudioBackend::set_output_channels (uint32_t output_channels)\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_output_channels (): " << output_channels << std::endl;\r
+\r
+    _output_channels = output_channels;\r
+    return 0;\r
+}\r
+\r
+\r
+std::string  \r
+WavesAudioBackend::device_name () const\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::device_name (): " << _device->DeviceName () << std::endl;\r
+    if (!_device) {\r
+        return "";\r
+    }\r
+    return _device->DeviceName ();\r
+}\r
+\r
+\r
+float        \r
+WavesAudioBackend::sample_rate () const\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::sample_rate (): " << std::endl;\r
+\r
+    if (!_device) {\r
+        std::cerr << "WavesAudioBackend::sample_rate (): No device is set!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    int sample_rate = _device->CurrentSamplingRate ();\r
+\r
+    /* COMMENTED DBG LOGS */ std::cout << "\t[" << _device->DeviceName () << "]->CurrentSamplingRate () returned " << sample_rate << std::endl;\r
+\r
+    return (float)sample_rate;\r
+}\r
+\r
+\r
+uint32_t     \r
+WavesAudioBackend::buffer_size () const\r
+{\r
+\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::buffer_size (): " << std::endl;\r
+\r
+    if (!_device) {\r
+        std::cerr << "WavesAudioBackend::buffer_size (): No device is set!" << std::endl;\r
+        return 0;\r
+    }\r
+\r
+    int size = _device->CurrentBufferSize ();\r
+    \r
+    /* COMMENTED DBG LOGS */ std::cout << "\t[" << _device->DeviceName () << "]->CurrentBufferSize () returned " << size << std::endl;\r
+\r
+    return (uint32_t)size;\r
+}\r
+\r
+\r
+SampleFormat \r
+WavesAudioBackend::sample_format () const\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::sample_format ()" << std::endl;\r
+    return _sample_format;\r
+}\r
+\r
+\r
+bool         \r
+WavesAudioBackend::interleaved () const\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::interleaved ()" << std::endl;\r
+\r
+    return _interleaved;\r
+}\r
+\r
+\r
+uint32_t     \r
+WavesAudioBackend::input_channels () const\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::input_channels ()" << std::endl;\r
+\r
+    return _input_channels;\r
+}\r
+\r
+\r
+uint32_t     \r
+WavesAudioBackend::output_channels () const\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::output_channels ()" << std::endl;\r
+\r
+    return _output_channels;\r
+}\r
+\r
+\r
+std::string \r
+WavesAudioBackend::control_app_name () const\r
+{\r
+    std::string app_name = ""; \r
+\r
+    if (_device && !dynamic_cast<WCMRNativeAudioNoneDevice*> (_device))    {\r
+        app_name = "PortAudioMayKnowIt";\r
+    }\r
+\r
+    return app_name; \r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::launch_control_app ()\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::launch_control_app ()" << std::endl;\r
+    if (!_device) {\r
+        std::cerr << "WavesAudioBackend::launch_control_app (): No device is set!" << std::endl;\r
+        return;\r
+    }\r
+    \r
+    WTErr err = _device->ShowConfigPanel (NULL);\r
+    \r
+    if (eNoErr != err) {\r
+        std::cerr << "WavesAudioBackend::launch_control_app (): [" << _device->DeviceName () << "]->ShowConfigPanel () failed (" << err << ")!" << std::endl;\r
+    }\r
+\r
+    /* COMMENTED DBG LOGS */ else std::cout << "WavesAudioBackend::launch_control_app (): [" << _device->DeviceName () << "]->ShowConfigPanel ()  successfully launched!" << std::endl;\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::_start (bool for_latency_measurement)\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::_start ()" << std::endl;\r
+\r
+    if (!_device) {\r
+        std::cerr << "WavesAudioBackend::_start (): No device is set!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    if (_register_system_audio_ports () != 0) {\r
+        std::cerr << "WavesAudioBackend::_start (): _register_system_audio_ports () failed!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    if (_use_midi) {\r
+        if (_midi_device_manager.start () != 0) {\r
+            std::cerr << "WavesAudioBackend::_start (): _midi_device_manager.start () failed!" << std::endl;\r
+            return -1;\r
+        }\r
+        if (_register_system_midi_ports () != 0) {\r
+            std::cerr << "WavesAudioBackend::_start (): _register_system_midi_ports () failed!" << std::endl;\r
+            return -1;\r
+        }\r
+    }\r
+\r
+    if (engine.reestablish_ports () != 0) {\r
+        std::cerr << "WavesAudioBackend::_start (): engine.reestablish_ports () failed!" << std::endl;\r
+    }\r
+\r
+    manager.registration_callback ();\r
+\r
+    _call_thread_init_callback = true;\r
+    WTErr retVal  = _device->SetStreaming (true);\r
+    if (retVal != eNoErr) {\r
+        std::cerr << "WavesAudioBackend::_start (): [" << _device->DeviceName () << "]->SetStreaming () failed!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    if (_use_midi) {\r
+        if (_midi_device_manager.stream (true)) {\r
+            std::cerr << "WavesAudioBackend::_start (): _midi_device_manager.stream (true) failed!" << std::endl;\r
+            return -1;\r
+        }\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::_audio_device_callback (const float* input_buffer, \r
+                                           float* output_buffer, \r
+                                           unsigned long nframes,\r
+                                           pframes_t sample_time,\r
+                                           uint64_t cycle_start_time_nanos)\r
+{\r
+    uint64_t dsp_start_time_nanos = __get_time_nanos();\r
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::_audio_device_callback ():" << _device->DeviceName () << std::endl;\r
+    _sample_time_at_cycle_start = sample_time;\r
+    _cycle_start_time_nanos = cycle_start_time_nanos;\r
+\r
+    if (_buffer_size != nframes) {\r
+        std::cout << _buffer_size << "!=" << nframes << std::endl;\r
+        return;\r
+    }\r
+\r
+    _read_audio_data_from_device (input_buffer, nframes);\r
+    _read_midi_data_from_devices ();\r
+\r
+    if (_call_thread_init_callback) {\r
+        _call_thread_init_callback = false;\r
+        /* COMMENTED DBG LOGS */ std::cout << "\tAudioEngine::thread_init_callback() invoked for " << std::hex << pthread_self() << std::dec << " !" << std::endl;\r
+        AudioEngine::thread_init_callback (this);\r
+    }\r
+\r
+    engine.process_callback (nframes);\r
+    \r
+    _write_audio_data_to_device (output_buffer, nframes);\r
+    _write_midi_data_to_devices (nframes);\r
+    \r
+    uint64_t dsp_end_time_nanos = __get_time_nanos();\r
+    \r
+    _dsp_load_accumulator -= *_dsp_load_history.begin();\r
+    _dsp_load_history.pop_front();\r
+    uint64_t dsp_load_nanos = dsp_end_time_nanos - dsp_start_time_nanos;\r
+    _dsp_load_accumulator += dsp_load_nanos;\r
+    _dsp_load_history.push_back(dsp_load_nanos);\r
+\r
+    return;\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::stop ()\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::stop ()" << std::endl;\r
+\r
+    WTErr retVal = eNoErr;\r
+\r
+    if (!_device) {\r
+        std::cerr << "WavesAudioBackend::stop (): No device is set!" << std::endl;\r
+        return -1;\r
+    }\r
+    \r
+    /* COMMENTED DBG LOGS */ std::cout << "\t[" << _device->DeviceName () << "]" << std::endl;\r
+\r
+    retVal = _device->SetStreaming (false);\r
+    if (retVal != eNoErr) {\r
+        std::cerr << "WavesAudioBackend::stop (): [" << _device->DeviceName () << "]->SetStreaming () failed!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    _midi_device_manager.stop ();\r
+\r
+    _unregister_system_audio_ports ();\r
+    _unregister_system_midi_ports ();\r
+    return 0;\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::freewheel (bool start_stop)\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::freewheel (" << start_stop << "):" << std::endl;\r
+\r
+    if (start_stop != _freewheeling) {\r
+        if (start_stop == true) {\r
+            WTErr retval = _device->SetStreaming (false);\r
+            if (retval != eNoErr) {\r
+                std::cerr << "WavesAudioBackend::freewheel (): [" << _device->DeviceName () << "]->SetStreaming () failed!" << std::endl;\r
+                return -1;\r
+            }\r
+            _call_thread_init_callback = true;\r
+            _freewheel_thread ();\r
+            engine.freewheel_callback (start_stop);\r
+        }\r
+        else {\r
+            _freewheel_thread_active = false; // stop _freewheel_thread ()\r
+            engine.freewheel_callback (start_stop);\r
+            _call_thread_init_callback = true;\r
+            WTErr retval = _device->SetStreaming (true);\r
+            if (retval != eNoErr) {\r
+                std::cerr << "WavesAudioBackend::freewheel (): [" << _device->DeviceName () << "]->SetStreaming () failed!" << std::endl;\r
+                return -1;\r
+            }\r
+        }\r
+        _freewheeling = start_stop;\r
+    }\r
+    // already doing what has been asked for\r
+    return 0;\r
+}\r
+\r
+\r
+void \r
+WavesAudioBackend::_freewheel_thread ()\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::_freewheel_thread ():" << std::endl;\r
+    if (!_freewheel_thread_active) { // Lets create it\r
+        \r
+        /* COMMENTED DBG LOGS */ std::cout << "\tCreating the thread _freewheel_thread () . . ." << std::endl;\r
+        pthread_attr_t attributes;\r
+        pthread_t thread_id;\r
+\r
+        ThreadData* thread_data = new ThreadData (this, boost::bind (&WavesAudioBackend::_freewheel_thread, this), __thread_stack_size ());\r
+\r
+        if (pthread_attr_init (&attributes)) {\r
+            std::cerr << "WavesAudioBackend::freewheel_thread (): pthread_attr_init () failed!" << std::endl;\r
+            return;\r
+        }\r
+   \r
+        if (pthread_attr_setstacksize (&attributes, __thread_stack_size ())) {\r
+            std::cerr << "WavesAudioBackend::freewheel_thread (): pthread_attr_setstacksize () failed!" << std::endl;\r
+            return;\r
+        }\r
+\r
+        _freewheel_thread_active = false;\r
+        if ((pthread_create (&thread_id, &attributes, __start_process_thread, thread_data))) {\r
+            _freewheel_thread_active = true;\r
+            std::cerr << "WavesAudioBackend::freewheel_thread (): pthread_create () failed!" << std::endl;\r
+            return;\r
+        }\r
+\r
+        /* COMMENTED DBG LOGS */ std::cout << "\t. . . _freewheel_thread () complete." << std::endl;\r
+        return;\r
+    }\r
+    \r
+    if (_call_thread_init_callback) {\r
+        _call_thread_init_callback = false;\r
+        AudioEngine::thread_init_callback (this);\r
+    }\r
+\r
+    while (_freewheel_thread_active) {\r
+        engine.process_callback (_buffer_size);\r
+    }\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::_freewheel_thread (): FINISHED" << std::endl;\r
+    return;\r
+}\r
+\r
+\r
+float\r
+WavesAudioBackend::dsp_load () const\r
+{\r
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::dsp_load (): " << std::endl;\r
+\r
+    if (!_device) {\r
+        std::cerr << "WavesAudioBackend::cpu_load (): No device is set!" << std::endl;\r
+        return 0;\r
+    }\r
+\r
+    float average_dsp_load = (float)_dsp_load_accumulator/_dsp_load_history_length;\r
+    \r
+    return ( average_dsp_load  / _audio_cycle_period_nanos)*100.0;\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::_init_dsp_load_history()\r
+{\r
+    if((_sample_rate <= 0.0) || (_buffer_size <= 0.0)) {\r
+        return;\r
+    }\r
+    \r
+    _audio_cycle_period_nanos = ((uint64_t)1000000000L * _buffer_size) / _sample_rate;\r
+    \r
+    _dsp_load_accumulator = 0;\r
+    \r
+    _dsp_load_history_length = (_sample_rate + _buffer_size - 1) / _buffer_size;\r
+    /* COMMENTED DBG LOGS */ std::cout << "\t\t_dsp_load_history_length = " << _dsp_load_history_length << std::endl;\r
+    _dsp_load_history = std::list<uint64_t>(_dsp_load_history_length, 0);\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::transport_start ()\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::transport_start (): " << std::endl;\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::transport_stop () \r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::transport_stop (): " << std::endl;\r
+}\r
+\r
+\r
+TransportState\r
+WavesAudioBackend::transport_state () const\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::transport_state (): " << std::endl;\r
+    return TransportStopped; \r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::transport_locate (framepos_t pos)\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::transport_locate (" << pos << "): " << std::endl;\r
+}\r
+\r
+\r
+framepos_t\r
+WavesAudioBackend::transport_frame () const\r
+{ \r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::transport_frame (): " << std::endl;\r
+    return 0; \r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::set_time_master (bool yn)\r
+{ \r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_time_master (): " << yn << std::endl;\r
+    return 0; \r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::usecs_per_cycle () const\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::usecs_per_cycle (): " << std::endl;\r
+    return (1000000 * _sample_rate) / _buffer_size;\r
+}\r
+\r
+\r
+size_t\r
+WavesAudioBackend::raw_buffer_size (DataType data_type)\r
+{\r
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::raw_buffer_size (" << data_type.to_string () << "): " << std::endl;\r
+    switch (data_type) {\r
+    case DataType::AUDIO:\r
+            return WavesAudioPort::MAX_BUFFER_SIZE_BYTES;\r
+        break;\r
+\r
+    case DataType::MIDI:\r
+            return WavesMidiPort::MAX_BUFFER_SIZE_BYTES;\r
+        break;\r
+\r
+        default:\r
+            std::cerr << "WavesAudioBackend::raw_buffer_size (): unexpected data type (" << (uint32_t)data_type <<")!" << std::endl;\r
+        break;\r
+    }\r
+    return 0;\r
+}\r
+\r
+\r
+pframes_t\r
+WavesAudioBackend::sample_time ()\r
+{\r
+    // WARNING: This is approximate calculation. Implementation of accurate calculation is pending.\r
+    // http://kokkinizita.linuxaudio.org/papers/usingdll.pdf\r
+    \r
+    return _sample_time_at_cycle_start + ((__get_time_nanos () - _cycle_start_time_nanos)*_sample_rate)/1000000000L;\r
+}\r
+\r
+\r
+uint64_t\r
+WavesAudioBackend::__get_time_nanos ()\r
+{\r
+#ifdef __MACOS__\r
+    // here we exploit the time counting API which is used by the WCMRCoreAudioDeviceManager. However,\r
+    // the API should be a part of WCMRCoreAudioDeviceManager to give a chance of being tied to the\r
+    // audio device transport timeß.\r
+    return AudioConvertHostTimeToNanos (AudioGetCurrentHostTime ());\r
+    \r
+#elif _WINDOWS\r
+       LARGE_INTEGER Count;\r
+    QueryPerformanceCounter (&Count);\r
+    return uint64_t ((Count.QuadPart * 1000000000L / __performance_counter_frequency));\r
+#endif\r
+}\r
+\r
+\r
+pframes_t\r
+WavesAudioBackend::sample_time_at_cycle_start ()\r
+{\r
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::sample_time_at_cycle_start (): " << _sample_time_at_cycle_start << std::endl;\r
+    return _sample_time_at_cycle_start;\r
+}\r
+\r
+\r
+pframes_t\r
+WavesAudioBackend::samples_since_cycle_start ()\r
+{\r
+    pframes_t diff_sample_time; \r
+    diff_sample_time = sample_time () - _sample_time_at_cycle_start;\r
+    /* COMMENTED DBG LOGS */ std::cout << "samples_since_cycle_start: " << diff_sample_time << std::endl;\r
+\r
+    return diff_sample_time;\r
+}\r
+\r
+\r
+bool\r
+WavesAudioBackend::get_sync_offset (pframes_t& /*offset*/) const\r
+{ \r
+    /* COMMENTED DBG LOGS */ std::cout << "get_sync_offset: false" << std::endl;\r
+\r
+    return false; \r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::create_process_thread (boost::function<void ()> func)\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::create_process_thread ():" << std::endl;\r
+    int retVal;\r
+    pthread_attr_t attributes;\r
+    size_t stacksize_aligned;\r
+    pthread_t thread_id;\r
+\r
+    // Align stacksize to PTHREAD_STACK_MIN.\r
+    stacksize_aligned = __thread_stack_size ();\r
+\r
+    ThreadData* td = new ThreadData (this, func, stacksize_aligned);\r
+\r
+    if ((retVal = pthread_attr_init (&attributes))) {\r
+        std::cerr << "Cannot set thread attr init res = " << retVal << endmsg;\r
+        return -1;\r
+    }\r
+   \r
+    if ((retVal = pthread_attr_setstacksize (&attributes, stacksize_aligned))) {\r
+        std::cerr << "Cannot set thread stack size (" << stacksize_aligned << ") res = " << retVal << endmsg;\r
+        return -1;\r
+    }\r
+\r
+    if ((retVal = pthread_create (&thread_id, &attributes, __start_process_thread, td))) {\r
+        std::cerr << "Cannot create thread res = " << retVal << endmsg;\r
+        return -1;\r
+    }\r
+\r
+    _backend_threads.push_back (thread_id);\r
+    /* COMMENTED DBG LOGS */ std::cout << "\t\t\t. . . thread " << std::hex << thread_id << " has been created" << std::endl;\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+void*\r
+WavesAudioBackend::__start_process_thread (void* arg)\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::__start_process_thread ():" << std::endl;\r
+    ThreadData* td = reinterpret_cast<ThreadData*> (arg);\r
+    boost::function<void ()> f = td->f;\r
+    delete td;\r
+    f ();\r
+    return 0;\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::join_process_threads ()\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::join_process_thread ()" << std::endl;\r
+    int ret = 0;\r
+\r
+    for (std::vector<pthread_t>::const_iterator i = _backend_threads.begin ();\r
+         i != _backend_threads.end ();\r
+         ++i) {\r
+        /* COMMENTED DBG LOGS */ std::cout << "\t\t\tstopping thread " << std::hex << *i << std::dec << "...\n";\r
+\r
+        void* status;  \r
+        if (pthread_join (*i, &status) != 0) {\r
+            std::cerr << "AudioEngine: cannot stop process thread !" << std::endl;\r
+            ret += -1;\r
+        }\r
+        /* COMMENTED DBG LOGS */ std::cout << "\t\t\t\t...done" << std::endl;\r
+    }\r
+    /* COMMENTED DBG LOGS */ std::cout << "\t\t\tall threads finished..." << std::endl;\r
+    _backend_threads.clear ();\r
+    /* COMMENTED DBG LOGS */ std::cout << "\t\t\tthread list cleared..." << std::endl;\r
+\r
+    return ret;\r
+}\r
+\r
+\r
+bool \r
+WavesAudioBackend::in_process_thread ()\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::in_process_thread ()" << std::endl;\r
+    for (std::vector<pthread_t>::const_iterator i = _backend_threads.begin ();\r
+        i != _backend_threads.end (); i++) {\r
+        if (pthread_equal (*i, pthread_self ()) != 0) {\r
+            return true;\r
+        }\r
+    }\r
+    return false;\r
+}\r
+\r
+\r
+size_t\r
+WavesAudioBackend::__thread_stack_size ()\r
+{\r
+    // Align stacksize to PTHREAD_STACK_MIN.\r
+#if defined (__MACOS__)\r
+    return (((thread_stack_size () - 1) / PTHREAD_STACK_MIN) + 1) * PTHREAD_STACK_MIN;\r
+#elif defined (_WINDOWS)\r
+    return thread_stack_size ();\r
+#endif\r
+}\r
+\r
+\r
+uint32_t \r
+WavesAudioBackend::process_thread_count ()\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::process_thread_count (): returns " << _backend_threads.size () << std::endl;\r
+    return _backend_threads.size ();\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::_read_audio_data_from_device (const float* input_buffer, pframes_t nframes)\r
+{\r
+#if defined(_WINDOWS)\r
+    const float **buffer = (const float**)input_buffer;\r
+    size_t copied_bytes = nframes*sizeof(float*);\r
+\r
+    for(std::vector<WavesAudioPort*>::iterator it = _physical_audio_inputs.begin ();\r
+        it != _physical_audio_inputs.end();\r
+        ++it)\r
+    {\r
+        memcpy((*it)->buffer(), *buffer, copied_bytes);\r
+        ++buffer;\r
+    }\r
+#else\r
+    std::vector<WavesAudioPort*>::iterator it = _physical_audio_inputs.begin ();\r
+\r
+    // Well, let's de-interleave here:\r
+    const Sample* source = input_buffer;\r
+\r
+    for (uint32_t chann_cnt = 0; (chann_cnt < _max_input_channels) && (it != _physical_audio_inputs.end ()); ++chann_cnt, ++source, ++it) {\r
+        const Sample* src = source;\r
+        Sample* tgt = (*it)->buffer ();\r
+\r
+        for (uint32_t frame = 0; frame < nframes; ++frame, src += _max_input_channels, ++tgt) {\r
+            *tgt = *src;\r
+        }\r
+    }\r
+#endif\r
+}\r
+\r
+void\r
+WavesAudioBackend::_write_audio_data_to_device (float* output_buffer, pframes_t nframes)\r
+{\r
+#if defined(_WnonononoINDOWS)\r
+    float **buffer = (float**)output_buffer;\r
+    size_t copied_bytes = nframes*sizeof(float);\r
+    int i = 0;\r
+    for(std::vector<WavesAudioPort*>::iterator it = _physical_audio_outputs.begin ();\r
+        it != _physical_audio_outputs.end();\r
+        ++it)\r
+    {\r
+        memcpy(*buffer, (*it)->buffer(), copied_bytes);\r
+        //*buffer = (*it)->buffer();\r
+        buffer++;\r
+    }\r
+#else\r
+    // Well, let's interleave here:\r
+    std::vector<WavesAudioPort*>::iterator it = _physical_audio_outputs.begin ();\r
+    Sample* target = output_buffer;\r
+\r
+    for (uint32_t chann_cnt = 0;\r
+         (chann_cnt < _max_output_channels) && (it != _physical_audio_outputs.end ());\r
+         ++chann_cnt, ++target, ++it) {\r
+        const Sample* src = (Sample*) ((*it)->get_buffer (nframes));\r
+        Sample* tgt = target;\r
+        for (uint32_t frame = 0; frame < nframes; ++frame, tgt += _max_output_channels, ++src) {\r
+            *tgt = *src;\r
+        }\r
+    }\r
+#endif\r
+}\r
+\r
+\r
+static boost::shared_ptr<WavesAudioBackend> __instance;\r
+\r
+\r
+boost::shared_ptr<AudioBackend>\r
+WavesAudioBackend::__waves_backend_factory (AudioEngine& e)\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::__waves_backend_factory ():" << std::endl;\r
+    if (!__instance) {\r
+        __instance.reset (new WavesAudioBackend (e));\r
+    }\r
+    return __instance;\r
+}\r
+\r
+\r
+#if defined(_WINDOWS)\r
+\r
+uint64_t WavesAudioBackend::__performance_counter_frequency;\r
+\r
+#endif\r
+\r
+int \r
+WavesAudioBackend::__instantiate (const std::string& arg1, const std::string& arg2)\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::__instantiate ():" << "[" << arg1 << "], [" << arg2 << "]" << std::endl;\r
+    __instantiated_name = arg1;\r
+#if defined(_WINDOWS)\r
+\r
+       LARGE_INTEGER Frequency;\r
+       QueryPerformanceFrequency(&Frequency);\r
+       __performance_counter_frequency = Frequency.QuadPart;\r
+       std::cout << "__performance_counter_frequency:" << __performance_counter_frequency << std::endl;\r
+\r
+#endif\r
+    return 0;\r
+}\r
+\r
+\r
+int \r
+WavesAudioBackend::__deinstantiate ()\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::__deinstantiate ():" << std::endl;\r
+    __instance.reset ();\r
+    return 0;\r
+}\r
+\r
+\r
+bool\r
+WavesAudioBackend::__already_configured ()\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::__already_configured ():" << std::endl;\r
+    return false;\r
+}\r
+\r
+\r
+void*\r
+WavesAudioBackend::private_handle () const\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WHY DO CALL IT: WavesAudioBackend::private_handle: " << std::endl;\r
+    return NULL;\r
+}\r
+\r
+\r
+bool\r
+WavesAudioBackend::available () const\r
+{\r
+    // COMMENTED SECONDARY DBG LOGS */// std::cout << "WavesAudioBackend::available: " << std::endl;\r
+    return true;\r
+}\r
+\r
+\r
+const std::string&\r
+WavesAudioBackend::my_name () const\r
+{\r
+    // COMMENTED SECONDARY DBG LOGS */// std::cout << "WavesAudioBackend::my_name: " << _port_prefix_name << std::endl;\r
+    return __instantiated_name;\r
+}\r
+\r
+\r
+bool\r
+WavesAudioBackend::can_monitor_input () const\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::can_monitor_input: " << std::endl;\r
+    return false;\r
+}\r
+\r
+std::string WavesAudioBackend::__instantiated_name;\r
+\r
+AudioBackendInfo WavesAudioBackend::__backend_info = {\r
+#ifdef __MACOS__\r
+    "CoreAudio",\r
+#elif _WINDOWS\r
+    "ASIO",\r
+#endif\r
+    __instantiate,\r
+    WavesAudioBackend::__deinstantiate,\r
+    WavesAudioBackend::__waves_backend_factory,\r
+    WavesAudioBackend::__already_configured,\r
+};\r
+\r
+\r
+extern "C" ARDOURBACKEND_API ARDOUR::AudioBackendInfo* descriptor ()\r
+{\r
+    /* COMMENTED DBG LOGS */ std::cout  << "waves_backend.dll : ARDOUR::AudioBackendInfo* descriptor (): " << std::endl;\r
+    return &WavesAudioBackend::backend_info ();\r
+}\r
diff --git a/libs/backends/wavesaudio/waves_audiobackend.h b/libs/backends/wavesaudio/waves_audiobackend.h
new file mode 100644 (file)
index 0000000..7b56656
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+    Copyright (C) 2014 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_waves_audiobackend_h__
+#define __libardour_waves_audiobackend_h__
+
+#include <string>
+#include <vector>    
+#include <list>
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <boost/function.hpp>
+
+#include "ardour/types.h"
+#include "ardour/audio_backend.h"
+
+#include "waves_midi_device_manager.h"
+
+#ifdef __MACOS__
+
+#include <WCMRCoreAudioDeviceManager.h>
+
+class ArdourAudioDeviceManager : public WCMRCoreAudioDeviceManager
+{
+  public:
+    ArdourAudioDeviceManager (WCMRAudioDeviceManagerClient *client) : WCMRCoreAudioDeviceManager (client, eFullDuplexDevices, true, eCABS_Simple, false) {};
+};
+
+#elif defined (_WINDOWS)
+
+#include <WCMRPortAudioDeviceManager.h>
+
+class ArdourAudioDeviceManager : public WCMRPortAudioDeviceManager
+{
+  public:
+    ArdourAudioDeviceManager (WCMRAudioDeviceManagerClient *client) : WCMRPortAudioDeviceManager (client, eFullDuplexDevices, paASIO) {};
+};
+
+#endif
+
+namespace ARDOUR {
+
+class AudioEngine;
+class PortEngine;
+class PortManager;
+class WavesAudioBackend;
+class WavesDataPort;
+class WavesAudioPort;
+class WavesMidiPort;
+
+
+    class WavesAudioBackend : public AudioBackend, WCMRAudioDeviceManagerClient
+{
+  public:
+    WavesAudioBackend (AudioEngine& e);
+    virtual ~WavesAudioBackend ();
+
+    /* AUDIOBACKEND API */
+
+    virtual std::string name () const;
+    
+    virtual bool is_realtime () const;
+    
+    virtual bool requires_driver_selection () const;
+    
+    virtual std::vector<std::string> enumerate_drivers () const;
+    
+    virtual int set_driver (const std::string& /*drivername*/);
+    
+    virtual std::vector<DeviceStatus> enumerate_devices () const;
+    
+    virtual std::vector<float> available_sample_rates (const std::string& device) const;
+
+    virtual float default_sample_rate () const;
+
+    virtual std::vector<uint32_t> available_buffer_sizes (const std::string& device) const;
+
+    virtual uint32_t available_input_channel_count (const std::string& device) const;
+
+    virtual uint32_t available_output_channel_count (const std::string& device) const;
+
+    virtual bool can_change_sample_rate_when_running () const;
+
+    virtual bool can_change_buffer_size_when_running () const;
+
+    virtual int set_device_name (const std::string& name);
+
+    virtual int set_sample_rate (float);
+
+    virtual int set_buffer_size (uint32_t);
+
+    virtual int set_sample_format (SampleFormat);
+
+    virtual int set_interleaved (bool yn);
+    
+    virtual int set_input_channels (uint32_t);
+    
+    virtual int set_output_channels (uint32_t);
+
+    virtual int set_systemic_input_latency (uint32_t);
+
+    virtual int set_systemic_output_latency (uint32_t);
+
+    virtual std::string device_name () const;
+    
+    virtual float sample_rate () const;
+    
+    virtual uint32_t buffer_size () const;
+    
+    virtual SampleFormat sample_format () const;
+    
+    virtual bool interleaved () const;
+    
+    virtual uint32_t input_channels () const;
+    
+    virtual uint32_t output_channels () const;
+    
+    virtual uint32_t systemic_input_latency () const;
+    
+    virtual uint32_t systemic_output_latency () const;
+
+    virtual std::string control_app_name () const;
+
+    virtual void launch_control_app ();
+
+    virtual std::vector<std::string> enumerate_midi_options () const;
+
+    virtual int set_midi_option (const std::string& option);
+
+    virtual std::string midi_option () const;
+
+    virtual int _start (bool for_latency_measurement);
+
+    virtual int stop ();
+
+    virtual int freewheel (bool start_stop);
+
+    virtual float dsp_load () const ;
+
+    virtual void transport_start ();
+
+    virtual void transport_stop ();
+
+    virtual TransportState transport_state () const;
+
+    virtual void transport_locate (framepos_t pos);
+
+    virtual framepos_t transport_frame () const;
+
+    virtual int set_time_master (bool yn);
+
+    virtual int usecs_per_cycle () const;
+
+    virtual size_t raw_buffer_size (DataType data_type);
+    
+    virtual pframes_t sample_time ();
+
+    virtual pframes_t sample_time_at_cycle_start ();
+
+    virtual pframes_t samples_since_cycle_start ();
+
+    virtual bool get_sync_offset (pframes_t& offset) const;
+
+    virtual int create_process_thread (boost::function<void ()> func);
+
+    virtual int join_process_threads ();
+
+    virtual bool in_process_thread ();
+
+    virtual uint32_t process_thread_count ();
+
+    virtual void update_latencies ();
+
+    virtual bool speed_and_position (double& speed, framepos_t& position) {
+        speed = 0.0;
+        position = 0;
+        return false;
+    }
+
+    /* PORTENGINE API */
+
+    virtual void* private_handle () const;
+    virtual const std::string& my_name () const;
+    
+    virtual bool available () const;
+
+    virtual uint32_t port_name_size () const;
+
+    virtual int set_port_name (PortHandle port_handle, const std::string& port_name);
+
+    virtual std::string get_port_name (PortHandle port_handle ) const;
+
+    virtual PortHandle get_port_by_name (const std::string& port_name) const;
+
+    virtual int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>& port_handles) const;
+
+    virtual DataType port_data_type (PortHandle port_handle) const;
+
+    virtual PortHandle register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags);
+
+    virtual void unregister_port (PortHandle port_handle);
+
+    virtual int connect (const std::string& src, const std::string& dst);
+
+    virtual int disconnect (const std::string& src, const std::string& dst);
+    
+    virtual int connect (PortHandle port_handle, const std::string& port_name);
+
+    virtual int disconnect (PortHandle port_handle, const std::string& port_name);
+
+    virtual int disconnect_all (PortHandle port_handle);
+
+    virtual bool connected (PortHandle port_handle, bool process_callback_safe);
+
+    virtual bool connected_to (PortHandle port_handle, const std::string& port_name, bool process_callback_safe);
+
+    virtual bool physically_connected (PortHandle port_handle, bool process_callback_safe);
+
+    virtual int get_connections (PortHandle port_handle, std::vector<std::string>&, bool process_callback_safe);
+
+    virtual int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index);
+    
+    virtual int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size);
+    
+    virtual uint32_t get_midi_event_count (void* port_buffer);
+    
+    virtual void midi_clear (void* port_buffer);
+
+    virtual bool can_monitor_input () const;
+    
+    virtual int request_input_monitoring (PortHandle port_handle, bool);
+    
+    virtual int ensure_input_monitoring (PortHandle port_handle, bool);
+    
+    virtual bool monitoring_input (PortHandle port_handle);
+
+    virtual void set_latency_range (PortHandle port_handle, bool for_playback, LatencyRange);
+    
+    virtual LatencyRange get_latency_range (PortHandle port_handle, bool for_playback);
+
+    virtual bool port_is_physical (PortHandle port_handle) const;
+
+    virtual void get_physical_outputs (DataType type, std::vector<std::string>& port_names);
+
+    virtual void get_physical_inputs (DataType type, std::vector<std::string>& port_names);
+
+    virtual ChanCount n_physical_outputs () const;
+
+    virtual ChanCount n_physical_inputs () const;
+
+    virtual void* get_buffer (PortHandle port_handle, pframes_t frames);
+
+    static AudioBackendInfo& backend_info () { return __backend_info; }
+
+    virtual void AudioDeviceManagerNotification (NotificationReason reason, void* pParam);
+
+  private:
+    //ArdourAudioDeviceManagerClient _audio_device_manager_client;
+    ArdourAudioDeviceManager _audio_device_manager;
+    WavesMidiDeviceManager _midi_device_manager;
+
+    WCMRAudioDevice *_device;
+    SampleFormat _sample_format;
+    bool _interleaved;
+    static std::string __instantiated_name;
+    uint32_t _input_channels;
+    uint32_t _max_input_channels;
+    uint32_t _output_channels;
+    uint32_t _max_output_channels;
+    float _sample_rate;
+    uint32_t _buffer_size;
+    uint32_t _systemic_input_latency;
+    uint32_t _systemic_output_latency;
+    bool _call_thread_init_callback;
+    std::vector<pthread_t> _backend_threads;
+    static const size_t __max_raw_midi_buffer_size;
+
+    static const std::vector<std::string> __available_midi_options;
+    bool  _use_midi;
+
+    struct ThreadData {
+        WavesAudioBackend* engine;
+        boost::function<void ()> f;
+        size_t stacksize;
+    
+        ThreadData (WavesAudioBackend* e, boost::function<void ()> fp, size_t stacksz)
+            : engine (e) , f (fp) , stacksize (stacksz) {}
+    };
+
+    static boost::shared_ptr<AudioBackend>    __waves_backend_factory (AudioEngine& e);
+    static int __instantiate (const std::string& arg1, const std::string& arg2);
+    static int __deinstantiate ();
+    static bool __already_configured ();
+
+    static void* __start_process_thread (void*);
+    static uint64_t __get_time_nanos ();
+    
+    static size_t __thread_stack_size ();
+
+    void _audio_device_callback (const float* input_audio_buffer, 
+                                 float* output_buffer, 
+                                 unsigned long nframes,
+                                 pframes_t sample_time,
+                                 uint64_t cycle_start_time_nanos);
+
+    void _changed_midi_devices ();
+
+    int _register_system_audio_ports ();
+    int _register_system_midi_ports ();
+
+    int _read_midi_data_from_devices ();
+    int _write_midi_data_to_devices (pframes_t);
+
+    pframes_t _ms_to_sample_time (int32_t time_ms) const;
+    int32_t _sample_time_to_ms (pframes_t sample_time) const ;
+
+    void _read_audio_data_from_device (const float* input_buffer, pframes_t nframes);
+    void _write_audio_data_to_device (float* output_buffer, pframes_t nframes);
+
+    void _unregister_system_audio_ports ();
+    void _unregister_system_midi_ports ();
+
+    WavesDataPort* _register_port (const std::string& port_name, ARDOUR::DataType type, ARDOUR::PortFlags flags);
+    inline bool _registered (PortHandle  port_handle) const
+    {
+        return std::find (_ports.begin (), _ports.end (), (WavesDataPort*)port_handle) != _ports.end ();
+    }
+    
+    WavesDataPort* _find_port (const std::string& port_name) const;
+    void _freewheel_thread ();
+
+    std::vector<WavesAudioPort*> _physical_audio_inputs;
+    std::vector<WavesAudioPort*> _physical_audio_outputs;
+    std::vector<WavesMidiPort*> _physical_midi_inputs;
+    std::vector<WavesMidiPort*> _physical_midi_outputs;
+    std::vector<WavesDataPort*> _ports;
+    static AudioBackendInfo __backend_info;
+
+#if defined (_WINDOWS)
+       static uint64_t __performance_counter_frequency;
+#endif
+       uint64_t _cycle_start_time_nanos;
+    pframes_t _sample_time_at_cycle_start;
+
+    bool _freewheeling;
+    bool _freewheel_thread_active;
+
+    friend class WavesMidiDeviceManager;
+    
+    std::list<uint64_t> _dsp_load_history;
+    size_t _dsp_load_history_length;
+    uint64_t _dsp_load_accumulator;
+    float _audio_cycle_period_nanos;
+    void _init_dsp_load_history();
+};
+
+} // namespace
+
+#endif /* __libardour_waves_audiobackend_h__ */
+    
diff --git a/libs/backends/wavesaudio/waves_audiobackend.latency.cc b/libs/backends/wavesaudio/waves_audiobackend.latency.cc
new file mode 100644 (file)
index 0000000..c0d2fcd
--- /dev/null
@@ -0,0 +1,90 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+#include "waves_dataport.h"\r
+#include "waves_audiobackend.h"\r
+\r
+using namespace ARDOUR;\r
+\r
+\r
+int \r
+WavesAudioBackend::set_systemic_input_latency (uint32_t systemic_input_latency)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_systemic_input_latency (): " << systemic_input_latency << std::endl;\r
+\r
+    _systemic_input_latency = systemic_input_latency;\r
+    return 0;\r
+}\r
+\r
+\r
+int \r
+WavesAudioBackend::set_systemic_output_latency (uint32_t systemic_output_latency)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_systemic_output_latency (): " << systemic_output_latency << std::endl;\r
+\r
+    _systemic_output_latency = systemic_output_latency;\r
+    return 0;\r
+}\r
+\r
+uint32_t     \r
+WavesAudioBackend::systemic_input_latency () const\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::systemic_input_latency ()" << std::endl;\r
+\r
+    return _systemic_input_latency;\r
+}\r
+\r
+\r
+uint32_t     \r
+WavesAudioBackend::systemic_output_latency () const\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::systemic_output_latency ()" << std::endl;\r
+\r
+    return _systemic_output_latency;\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::update_latencies ()\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "update_latencies:" << std::endl;\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::set_latency_range (PortHandle port_handle, bool for_playback, LatencyRange latency_range)\r
+{\r
+    if (!_registered (port_handle)) {\r
+        std::cerr << "WavesAudioBackend::set_latency_range (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;\r
+        return;\r
+    }\r
+    ((WavesDataPort*)port_handle)->set_latency_range (latency_range, for_playback);\r
+}\r
+\r
+\r
+LatencyRange\r
+WavesAudioBackend::get_latency_range (PortHandle port_handle, bool for_playback)\r
+{\r
+    if (!_registered (port_handle)) {\r
+        std::cerr << "WavesAudioBackend::get_latency_range (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;\r
+        LatencyRange lr = {0,0};\r
+        return lr;\r
+    }   \r
+    return ((WavesDataPort*)port_handle)->latency_range (for_playback);\r
+}\r
diff --git a/libs/backends/wavesaudio/waves_audiobackend.midi.cc b/libs/backends/wavesaudio/waves_audiobackend.midi.cc
new file mode 100644 (file)
index 0000000..94c674d
--- /dev/null
@@ -0,0 +1,354 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+#include <boost/assign/list_of.hpp>\r
+\r
+#include "waves_audiobackend.h"\r
+#include "waves_midiport.h"\r
+#include "waves_midi_event.h"\r
+#include "waves_midi_buffer.h"\r
+\r
+using namespace ARDOUR;\r
+\r
+#ifdef __MACOS__\r
+\r
+const std::vector<std::string> WavesAudioBackend::__available_midi_options = boost::assign::list_of ("None") ("CoreMIDI");\r
+\r
+#elif _WINDOWS\r
+\r
+const std::vector<std::string> WavesAudioBackend::__available_midi_options = boost::assign::list_of ("None") ("Multimedia Extensions");\r
+\r
+#endif\r
+\r
+\r
+std::vector<std::string> \r
+WavesAudioBackend::enumerate_midi_options () const\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::enumerate_midi_options ()" << std::endl;\r
+    return __available_midi_options;\r
+}\r
+\r
+\r
+int \r
+WavesAudioBackend::set_midi_option (const std::string& option)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_midi_option ( " << option << " )" << std::endl;\r
+    if (option == __available_midi_options[0]) {\r
+        _use_midi = false;\r
+        // COMMENTED DBG LOGS */ std::cout << "\tNO MIDI system used)" << std::endl;\r
+    }\r
+    else if (option == __available_midi_options[1]) {\r
+        _use_midi = true;\r
+        // COMMENTED DBG LOGS */ std::cout << "\tNO MIDI system used)" << std::endl;\r
+    }\r
+    else {\r
+        std::cerr << "WavesAudioBackend::set_midi_option (): Invalid MIDI option!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+std::string\r
+WavesAudioBackend::midi_option () const\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::midi_option ():" << std::endl;\r
+    return * (__available_midi_options.begin () + (_use_midi?1:0));\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buffer, void* port_buffer, uint32_t event_index)\r
+{\r
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::midi_event_get ():" << std::endl;\r
+\r
+    if (buffer == NULL) {\r
+        std::cerr << "WavesAudioBackend::midi_event_get () : NULL in the 'buffer' argument!\n";\r
+        return -1;\r
+    }\r
+\r
+    if (port_buffer == NULL) {\r
+        std::cerr << "WavesAudioBackend::midi_event_get () : NULL in the 'port_buffer' argument!\n";\r
+        return -1;\r
+    }\r
+\r
+    WavesMidiBuffer& source = * (WavesMidiBuffer*)port_buffer;\r
+\r
+    if (event_index >= source.size ()) {\r
+        std::cerr << "WavesAudioBackend::midi_event_get () : 'event_index' is out of the number of events stored in 'port_buffer'!\n";\r
+        return -1;\r
+    }\r
+\r
+    WavesMidiEvent* waves_midi_event = source[event_index];\r
+\r
+    timestamp = waves_midi_event->timestamp ();\r
+    size = waves_midi_event->size ();\r
+    *buffer = waves_midi_event->data ();\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size)\r
+{\r
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::midi_event_put ():" << std::endl;\r
+    if (buffer == NULL) {\r
+        std::cerr << "WavesAudioBackend::midi_event_put () : NULL in the 'buffer' argument!\n";\r
+        return -1;\r
+    }\r
+\r
+    if (port_buffer == NULL) {\r
+        std::cerr << "WavesAudioBackend::midi_event_put () : NULL in the 'port_buffer' argument!\n";\r
+        return -1;\r
+    }\r
+\r
+    WavesMidiBuffer& target = * (WavesMidiBuffer*)port_buffer;\r
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "\t [" << target.name () << "]"<< std::endl;\r
+\r
+    if (target.size () && (pframes_t)target.back ()->timestamp () > timestamp) {\r
+        std::cerr << "WavesAudioBackend::midi_event_put (): The MIDI Event to put is a bit late!" << std::endl;\r
+        std::cerr << "\tprev timestamp is " << (pframes_t)target.back ()->timestamp () << " as the current one is " << timestamp << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    target.push_back (new WavesMidiEvent (timestamp, buffer, size));\r
+    return 0;\r
+}\r
+\r
+\r
+uint32_t\r
+WavesAudioBackend::get_midi_event_count (void* port_buffer)\r
+{\r
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::get_midi_event_count (): " << std::endl;\r
+    \r
+    if (port_buffer == NULL) {\r
+        std::cerr << "WavesAudioBackend::get_midi_event_count () : NULL in the 'port_buffer' argument!\n";\r
+        return -1;\r
+    }\r
+\r
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "\tcount = " << (* (WavesMidiBuffer*)port_buffer).size () << std::endl;\r
+\r
+    return (* (WavesMidiBuffer*)port_buffer).size ();\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::midi_clear (void* port_buffer)\r
+{\r
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::midi_clear (): " << std::endl;\r
+    if (port_buffer == NULL) {\r
+        std::cerr << "WavesAudioBackend::midi_clear () : NULL in the 'port_buffer' argument!\n";\r
+        return;\r
+    }\r
+\r
+    (* (WavesMidiBuffer*)port_buffer).clear ();\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::_changed_midi_devices ()\r
+{\r
+    if (_midi_device_manager.stream (false)) {\r
+        std::cerr << "WavesAudioBackend::_changed_midi_devices (): _midi_device_manager.stream (false) failed!" << std::endl;\r
+        return;\r
+    }\r
+\r
+    _midi_device_manager.stop ();\r
+\r
+    if (_midi_device_manager.start () != 0) {\r
+        std::cerr << "WavesAudioBackend::_changed_midi_devices (): _midi_device_manager.start () failed!" << std::endl;\r
+        return;\r
+    }\r
+\r
+    if (_register_system_midi_ports () != 0) {\r
+        std::cerr << "WavesAudioBackend::_changed_midi_devices (): _register_system_midi_ports () failed!" << std::endl;\r
+        return;\r
+    }\r
+    \r
+    manager.registration_callback ();\r
+\r
+    if (_midi_device_manager.stream (true)) {\r
+        std::cerr << "WavesAudioBackend::_changed_midi_devices (): _midi_device_manager.stream (true) failed!" << std::endl;\r
+        return;\r
+    }\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::_unregister_system_midi_ports ()\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::_unregister_system_midi_ports ()" << std::endl;\r
+    std::vector<WavesMidiPort*> physical_midi_ports = _physical_midi_inputs;\r
+    physical_midi_ports.insert (physical_midi_ports.begin (), _physical_midi_outputs.begin (), _physical_midi_outputs.end ());\r
+\r
+    for (std::vector<WavesMidiPort*>::const_iterator it = physical_midi_ports.begin (); it != physical_midi_ports.end (); ++it) {\r
+        std::vector<WavesDataPort*>::iterator port_iterator = std::find (_ports.begin (), _ports.end (), *it);\r
+        if (port_iterator == _ports.end ()) {\r
+            std::cerr << "WavesAudioBackend::_unregister_system_midi_ports (): Failed to find port [" << (*it)->name () << "]!"  << std::endl;\r
+        }\r
+        else\r
+            _ports.erase (port_iterator);\r
+        delete *it;\r
+    }\r
+    _physical_midi_inputs.clear ();\r
+    _physical_midi_outputs.clear ();\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::_register_system_midi_ports ()\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::_register_system_midi_ports ()" << std::endl;\r
+\r
+    LatencyRange lr = {0,0};\r
+    lr.min = lr.max = _buffer_size;\r
+\r
+    for (size_t i = 0; i<_ports.size ();)    {\r
+        WavesMidiPort* midi_port = dynamic_cast<WavesMidiPort*> (_ports[i]);\r
+        if (!midi_port || !midi_port->is_physical () || !midi_port->is_terminal ()) {\r
+            ++i;\r
+            continue;\r
+        }\r
+\r
+        if ((midi_port->is_input () && !midi_port->midi_device ()->is_output ()) ||\r
+            (midi_port->is_output () && !midi_port->midi_device ()->is_input ())) {\r
+            disconnect_all (midi_port);\r
+            unregister_port (midi_port);\r
+            continue; // to be here for further additions in the end of this loop\r
+        }\r
+\r
+        ++i;\r
+    }\r
+\r
+    const std::vector<WavesMidiDevice *>&  devices = _midi_device_manager.devices ();\r
+\r
+    for (std::vector<WavesMidiDevice*>::const_iterator it = devices.begin (); it != devices.end (); ++it) {\r
+        if ((*it)->is_input ()) {\r
+            std::string port_name = "system_midi:" + (*it)->name () + " capture";\r
+            WavesDataPort* port = _find_port (port_name);\r
+            WavesMidiPort* midi_port = dynamic_cast<WavesMidiPort*> (port);\r
+            if (midi_port && (midi_port->type () != DataType::MIDI || \r
+                midi_port->midi_device () != *it || \r
+                !midi_port->is_output () || \r
+                !midi_port->is_physical () ||\r
+                !midi_port->is_terminal ())) {\r
+                std::cerr << "WavesAudioBackend::_register_system_midi_ports (): the port [" << midi_port->name () << "] is inconsystently constructed!" << std::endl;\r
+                disconnect_all (midi_port);\r
+                unregister_port (midi_port);\r
+                port = NULL;\r
+            }\r
+\r
+            if (port == NULL) {\r
+                port = _register_port ( port_name, DataType::MIDI , static_cast<ARDOUR::PortFlags> (IsOutput | IsPhysical | IsTerminal));\r
+                if (port == NULL) {\r
+                    return -1;\r
+                }\r
+                ((WavesMidiPort*)port)->set_midi_device (*it);\r
+            }\r
+            port->set_latency_range (lr, false); \r
+        }\r
+\r
+        if ((*it)->is_output ()) {\r
+            std::string port_name = "system_midi:" + (*it)->name () + " playback";\r
+            WavesDataPort* port = _find_port (port_name);\r
+            WavesMidiPort* midi_port = dynamic_cast<WavesMidiPort*> (port);\r
+            if (midi_port && (midi_port->type () != DataType::MIDI || \r
+                midi_port->midi_device () != *it || \r
+                !midi_port->is_input () || \r
+                !midi_port->is_physical () ||\r
+                !midi_port->is_terminal ())) {\r
+                std::cerr << "WavesAudioBackend::_register_system_midi_ports (): the port [" << midi_port->name () << "] is inconsystently constructed!" << std::endl;\r
+                disconnect_all (midi_port);\r
+                unregister_port (midi_port);\r
+            }\r
+\r
+            if (port == NULL) {\r
+                port = _register_port (port_name,\r
+                                       DataType::MIDI,\r
+                                       static_cast<ARDOUR::PortFlags> (IsInput | IsPhysical | IsTerminal));\r
+                if (port == NULL) {\r
+                    return -1;\r
+                }\r
+            }\r
+\r
+            ((WavesMidiPort*)port)->set_midi_device ((*it));\r
+            port->set_latency_range (lr, true);\r
+        }\r
+    }\r
+    \r
+    return 0;\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::_read_midi_data_from_devices ()\r
+{\r
+    // COMMENTED FREQUENT DBG LOGS */ std::cout  << "WavesAudioBackend::_read_midi_data_from_devices ():" << std::endl;\r
+    if (!_midi_device_manager.is_streaming ())\r
+        return 0;\r
+    \r
+    _midi_device_manager.do_read ();\r
+\r
+    for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_inputs.begin (); it != _physical_midi_inputs.end (); ++it) {\r
+        WavesMidiDevice* midi_device = (*it)->midi_device ();\r
+        \r
+        WavesMidiBuffer& waves_midi_buffer = (*it)->buffer ();\r
+        waves_midi_buffer.clear ();\r
+        \r
+        while (WavesMidiEvent *waves_midi_event = midi_device->dequeue_input_waves_midi_event ()) {\r
+            int32_t timestamp_st = _buffer_size - (_sample_time_at_cycle_start - waves_midi_event->timestamp ());\r
+            \r
+            if (timestamp_st < 0) {\r
+                timestamp_st = 0;\r
+            }\r
+            else if (timestamp_st >= (int32_t)_buffer_size) {\r
+                timestamp_st = _buffer_size - 1;\r
+            }\r
+            waves_midi_event->set_timestamp (timestamp_st);\r
+            waves_midi_buffer.push_back (waves_midi_event);\r
+        }\r
+    }\r
+    return 0;\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::_write_midi_data_to_devices (pframes_t nframes)\r
+{\r
+    if (!_midi_device_manager.is_streaming ())\r
+        return 0;\r
+    \r
+    for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_outputs.begin (); it != _physical_midi_outputs.end (); ++it) {\r
+        WavesMidiDevice* midi_device = (*it)->midi_device (); \r
+        WavesMidiBuffer &waves_midi_buffer = * (WavesMidiBuffer*) (*it)->get_buffer (nframes);\r
+\r
+        for (WavesMidiBufferIterator it = waves_midi_buffer.begin (); it != waves_midi_buffer.end ();) {\r
+             WavesMidiEvent* waves_midi_event = *it;\r
+            \r
+            waves_midi_buffer.erase (it);\r
+            \r
+            waves_midi_event->set_timestamp (_sample_time_at_cycle_start + waves_midi_event->timestamp () + nframes);\r
+            midi_device->enqueue_output_waves_midi_event (waves_midi_event);\r
+       }\r
+    }\r
+    _midi_device_manager.do_write ();\r
+    return 0;\r
+}\r
diff --git a/libs/backends/wavesaudio/waves_audiobackend.port_engine.cc b/libs/backends/wavesaudio/waves_audiobackend.port_engine.cc
new file mode 100644 (file)
index 0000000..6225468
--- /dev/null
@@ -0,0 +1,654 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+#include "waves_audiobackend.h"\r
+#include "waves_audioport.h"\r
+#include "waves_midiport.h"\r
+#include "waves_midi_event.h"\r
+\r
+using namespace ARDOUR;\r
+\r
+uint32_t\r
+WavesAudioBackend::port_name_size () const\r
+{\r
+    return 256+64;\r
+}\r
+\r
+int\r
+WavesAudioBackend::set_port_name (PortHandle port_handle, const std::string& port_name)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::set_port_name (): [" << std::hex << port_handle << std::dec << "], [" << port_name << "]" << std::endl;\r
+    \r
+    if (!_registered (port_handle)) {\r
+        std::cerr << "WavesAudioBackend::set_port_name (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    return ((WavesAudioPort*)port_handle)->set_name (__instantiated_name + ":" + port_name);\r
+}\r
+\r
+\r
+std::string\r
+WavesAudioBackend::get_port_name (PortHandle port_handle) const\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::get_port_name (): [" << std::hex << port_handle << std::dec << "]" << std::endl;\r
+    if (!_registered (port_handle)) {\r
+        std::cerr << "WavesAudioBackend::get_port_name (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;\r
+        return std::string ();\r
+    }\r
+    // COMMENTED DBG LOGS */ else std::cout  << "\t[" << ((WavesAudioPort*)port_handle)->name () << "]" << std::endl;\r
+\r
+    return ((WavesAudioPort*)port_handle)->name ();\r
+}\r
+\r
+\r
+PortEngine::PortHandle\r
+WavesAudioBackend::get_port_by_name (const std::string& port_name) const\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::get_port_by_name (): [" << port_name << "]" << std::endl;\r
+\r
+    PortHandle port_handle = (PortHandle)_find_port (port_name);\r
+    if (!port_handle) {\r
+        std::cerr << "WavesAudioBackend::get_port_by_name (): Failed to find port [" << port_name << "]!" << std::endl;\r
+    }\r
+\r
+    return port_handle;\r
+}\r
+\r
+\r
+WavesDataPort* \r
+WavesAudioBackend::_find_port (const std::string& port_name) const\r
+{\r
+    for (std::vector<WavesDataPort*>::const_iterator it = _ports.begin (); it != _ports.end (); ++it) {\r
+        if ((*it)->name () == port_name) {\r
+            return *it;\r
+        }\r
+    }\r
+\r
+    return NULL;\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>& port_names) const\r
+{\r
+  \r
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::get_ports (): \n\tPattern: [" << port_name_pattern << "]\n\tType: " << type << "\n\tFlags: " << flags << endl;\r
+    \r
+    unsigned found_ports =0;\r
+    \r
+    for (size_t i = 0; i < _ports.size (); ++i) {\r
+        WavesDataPort* port = _ports[i];\r
+        \r
+        if ((port->type () == type) && (port->flags () & flags)) {\r
+            port_names.push_back (port->name ());\r
+            found_ports++;\r
+        }\r
+    }\r
+    return found_ports;\r
+}\r
+\r
+\r
+DataType\r
+WavesAudioBackend::port_data_type (PortHandle port_handle) const\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::port_data_type" << std::endl;\r
+\r
+    if (!_registered (port_handle)) {\r
+        std::cerr << "WavesAudioBackend::port_data_type (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;\r
+        return DataType::NIL;\r
+    }\r
+    \r
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::port_data_type: " << endl;\r
+    \r
+    return ((WavesAudioPort*)port_handle)->type ();\r
+}\r
+\r
+\r
+PortEngine::PortHandle\r
+WavesAudioBackend::register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::register_port (): " << type.to_string () << " [" << shortname << "]" << std::endl;\r
+\r
+    if (shortname.size () == 0) {\r
+        std::cerr << "WavesAudioBackend::register_port (): Invalid (empty) port name!" << std::endl;\r
+        return NULL;\r
+    }\r
+\r
+    if (flags & IsPhysical) {\r
+        std::cerr << "WavesAudioBackend::register_port (): Unexpected attribute for port [" << shortname << "]! The port must not be physical!";\r
+        return NULL;\r
+    }\r
+\r
+    return (PortEngine::PortHandle)_register_port (__instantiated_name + ":" + shortname, type, flags);\r
+}\r
+\r
+\r
+WavesDataPort*\r
+WavesAudioBackend::_register_port (const std::string& port_name, ARDOUR::DataType type, ARDOUR::PortFlags flags)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::_register_port (): [" << port_name << "]" << std::endl;\r
+\r
+    if (_find_port (port_name) != NULL) {\r
+        std::cerr << "WavesAudioBackend::register_port () : Port [" << port_name << "] is already registered!" << std::endl;\r
+        return NULL;\r
+    }\r
+\r
+    WavesDataPort* port = NULL;\r
+    switch (type) {\r
+        case ARDOUR::DataType::AUDIO: {\r
+            WavesAudioPort* audio_port = new WavesAudioPort (port_name, flags);\r
+            if (flags & IsPhysical)\r
+            {\r
+                if (flags & IsOutput)\r
+                {\r
+                    _physical_audio_inputs.push_back (audio_port);\r
+                    // COMMENTED DBG LOGS */ std::cout  << "\t\t" << port_name << " added to physical AUDIO Inputs !" << std::endl;\r
+                }\r
+                else if (flags & IsInput)\r
+                {\r
+                    _physical_audio_outputs.push_back (audio_port);\r
+                    // COMMENTED DBG LOGS */ std::cout  << "\t\t" << port_name << " added to physical AUDIO Outputs !" << std::endl;\r
+                }\r
+            }\r
+            port = audio_port;\r
+        } break;\r
+        case ARDOUR::DataType::MIDI: {\r
+            WavesMidiPort* midi_port = new WavesMidiPort (port_name, flags);\r
+            if (flags & IsPhysical)\r
+            {\r
+                if (flags & IsOutput)\r
+                {\r
+                    _physical_midi_inputs.push_back (midi_port);\r
+                    // COMMENTED DBG LOGS */ std::cout  << "\t\t" << port_name << " added to physical MIDI Inputs !" << std::endl;\r
+                }\r
+                else if (flags & IsInput)\r
+                {\r
+                    _physical_midi_outputs.push_back (midi_port);\r
+                    // COMMENTED DBG LOGS */ std::cout  << "\t\t" << port_name << " added to physical MIDI Outputs !" << std::endl;\r
+                }\r
+            }\r
+            port = midi_port;\r
+        } break;\r
+        default:\r
+            std::cerr << "WavesAudioBackend::register_port () : Invalid data type (" << (uint32_t)type << ") applied to port [" << port_name << "]!" << std::endl;\r
+        return NULL;\r
+    }\r
+    \r
+    _ports.push_back (port);\r
+\r
+    return port;\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::unregister_port (PortHandle port_handle)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::unregister_port ():" << std::hex << port_handle << std::dec << std::endl;\r
+\r
+    // so far we suppose all disconnections will be done prior to unregistering.\r
+    WavesDataPort* port = (WavesDataPort*)port_handle;\r
+    std::vector<WavesDataPort*>::iterator port_iterator = std::find (_ports.begin (), _ports.end (), (WavesDataPort*)port_handle);\r
+    if (port_iterator == _ports.end ()) {\r
+        std::cerr << "WavesAudioBackend::unregister_port (): Failed to find port [" << std::hex << port_handle << std::dec << "]!"  << std::endl;\r
+        return;\r
+    }\r
+    // COMMENTED DBG LOGS */ std::cout  << "\t[" << ((WavesDataPort*)port_handle)->name () << "]" << std::endl;\r
+\r
+    _ports.erase (port_iterator);\r
+\r
+    if (port->is_physical ()) {\r
+        if (port->is_output ()) {\r
+            switch (port->type ()) {\r
+                case ARDOUR::DataType::AUDIO: {\r
+                    std::vector<WavesAudioPort*>::iterator audio_port_iterator = std::find (_physical_audio_inputs.begin (), _physical_audio_inputs.end (), port);\r
+                    if (audio_port_iterator == _physical_audio_inputs.end ())    {\r
+                        std::cerr << "WavesAudioBackend::unregister_port (): Failed to find port [" << port->name () << "] in the list of registered physical audio inputs!" << std::endl;\r
+                        return;\r
+                    }\r
+                    _physical_audio_inputs.erase (audio_port_iterator);\r
+                }\r
+                break;\r
+                case ARDOUR::DataType::MIDI: {\r
+                    std::vector<WavesMidiPort*>::iterator midi_port_iterator = std::find (_physical_midi_inputs.begin (), _physical_midi_inputs.end (), port);\r
+                    if (midi_port_iterator == _physical_midi_inputs.end ()) {\r
+                        std::cerr << "WavesAudioBackend::unregister_port (): Failed to find port [" << port->name () << "] in the list of registered physical midi inputs!" << std::endl;\r
+                        return;\r
+                    }\r
+                    _physical_midi_inputs.erase (midi_port_iterator);\r
+                }\r
+                break;\r
+                default:\r
+                    std::cerr << "WavesAudioBackend::unregister_port (): Invalid type (" << port->type () << " applied to [" << port->name () << "]!" << std::endl;\r
+                break;\r
+            }\r
+        }\r
+        else if (port->flags () & IsInput) {\r
+            switch (port->type ()) {\r
+                case ARDOUR::DataType::AUDIO: {\r
+                    std::vector<WavesAudioPort*>::iterator audio_port_iterator = std::find (_physical_audio_outputs.begin (), _physical_audio_outputs.end (), port);\r
+                    if (audio_port_iterator == _physical_audio_outputs.end ())\r
+                    {\r
+                        std::cerr << "WavesAudioBackend::unregister_port: Failed to find port [" << port->name () << std::dec << "] in the list of registered physical audio outputs!\n";\r
+                        return;\r
+                    }\r
+                    _physical_audio_outputs.erase (audio_port_iterator);\r
+                }\r
+                break;\r
+                case ARDOUR::DataType::MIDI: {\r
+\r
+                    std::vector<WavesMidiPort*>::iterator midi_port_iterator = std::find (_physical_midi_outputs.begin (), _physical_midi_outputs.end (), port);\r
+                    if (midi_port_iterator == _physical_midi_outputs.end ())\r
+                    {\r
+                        std::cerr << "WavesAudioBackend::unregister_port: Failed to find port [" << port->name () << std::dec << "] in the list of registered physical midi outputs!\n";\r
+                        return;\r
+                    }\r
+                    _physical_midi_outputs.erase (midi_port_iterator);\r
+                }\r
+                break;\r
+                default:\r
+                    std::cerr << "WavesAudioBackend::unregister_port (): Invalid type (" << port->type () << " applied to [" << port->name () << "]!" << std::endl;\r
+                break;\r
+            }\r
+        }\r
+    }\r
+\r
+    delete port;\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::connect (const std::string& src_port_name, const std::string& dst_port_name)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::connect (" << src_port_name << ", " << dst_port_name << "):" << std::endl;\r
+\r
+    WavesDataPort* src_port = _find_port (src_port_name);\r
+    if (src_port == NULL) {\r
+        std::cerr << "WavesAudioBackend::connect: Failed to find source port " << src_port_name << " !" << std::endl;\r
+        return -1;\r
+    }\r
+    \r
+    WavesDataPort* dst_port = _find_port (dst_port_name);\r
+    if (dst_port == NULL) {\r
+        std::cerr << "WavesAudioBackend::connect: Failed to find destination port " << dst_port_name << " !" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    // COMMENTED DBG LOGS */ std::cout  << "\t\t (" << src_port << ", " << dst_port << "):" << std::endl;\r
+    return src_port->connect (dst_port);\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::connect (PortHandle src_port_handle, const std::string& dst_port_name)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::connect ():" << std::endl;\r
+    if (!_registered (src_port_handle)) {\r
+        std::cerr << "WavesAudioBackend::connect: Failed to find source port [" << std::hex << src_port_handle << std::dec << "]!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    // COMMENTED DBG LOGS */ std::cout  << "\t[" << std::hex << src_port_handle << std::dec << "]" << std::endl;\r
+    // COMMENTED DBG LOGS */ std::cout  << "\t[" << dst_port_name << "]" << std::endl;\r
+\r
+    WavesDataPort* dst_port = _find_port (dst_port_name);\r
+    if (dst_port == NULL) {\r
+        std::cerr << "WavesAudioBackend::connect (): Failed to find destination port [" << dst_port_name << "]!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    return ((WavesDataPort*)src_port_handle)->connect (dst_port);\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::disconnect (PortHandle src_port_handle, const std::string& dst_port_name)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::disconnect (" << src_port_handle << ", " << dst_port_name << "):" << std::endl;\r
+    if (!_registered (src_port_handle)) {\r
+        std::cerr << "WavesAudioBackend::disconnect (): Failed to find source port [" << std::hex << src_port_handle << std::dec << "]!" << std::endl;\r
+        return -1;\r
+    }\r
+    \r
+    // COMMENTED DBG LOGS */ std::cout  << "\t[" << std::hex << src_port_handle << std::dec << "]" << std::endl;\r
+    // COMMENTED DBG LOGS */ std::cout  << "\t[" << dst_port_name << "]" << std::endl;\r
+\r
+    WavesDataPort* dst_port = _find_port (dst_port_name);\r
+    if (dst_port == NULL) {\r
+        std::cerr << "WavesAudioBackend::disconnect (): Failed to find destination port [" << dst_port_name << "]!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    return ((WavesDataPort*)src_port_handle)->disconnect (dst_port);\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::disconnect_all (PortHandle port_handle)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::disconnect_all ():" << std::endl;\r
+    if (!_registered (port_handle)) {\r
+        std::cerr << "WavesAudioBackend::disconnect_all : Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+ ((WavesDataPort*)port_handle)->disconnect_all ();\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::disconnect (const std::string& src_port_name, const std::string& dst_port_name)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::disconnect (" << src_port_name << ", " << dst_port_name << "):" << std::endl;\r
+\r
+    WavesDataPort* src_port = _find_port (src_port_name);\r
+    if (src_port == NULL) {\r
+        std::cerr << "WavesAudioBackend::disconnect : Failed to find source port!\n";\r
+        return -1;\r
+    }\r
+    \r
+    WavesDataPort* dst_port = _find_port (dst_port_name);\r
+    if (dst_port == NULL) {\r
+        std::cerr << "WavesAudioBackend::disconnect : Failed to find destination port!\n";\r
+        return -1;\r
+    }\r
+\r
+    return dst_port->disconnect (src_port);\r
+}\r
+\r
+\r
+bool\r
+WavesAudioBackend::connected (PortHandle port_handle, bool process_callback_safe)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::connected ():" << std::endl;\r
+    if (!_registered (port_handle)) {\r
+        std::cerr << "WavesAudioBackend::connected (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;\r
+        return false;\r
+    }\r
+    \r
+    return ((WavesDataPort*)port_handle)->is_connected ();\r
+}\r
+\r
+\r
+bool\r
+WavesAudioBackend::connected_to (PortHandle src_port_handle, const std::string& dst_port_name, bool process_callback_safe)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::connected_to (" << src_port_handle << ", " << dst_port_name << ")" << std::endl;\r
+\r
+    if (!_registered (src_port_handle)) {\r
+        std::cerr << "WavesAudioBackend::connected_to : Failed to find source port!" << std::endl;\r
+        return false;\r
+    }\r
+\r
+    WavesDataPort* dst_port = _find_port (dst_port_name);\r
+    if (dst_port == NULL) {\r
+        std::cerr << "WavesAudioBackend::connected_to : Failed to find destination port!" << std::endl;\r
+        return -1;\r
+    }\r
+    // COMMENTED DBG LOGS */ std::cout  << "\t return " << ((((WavesDataPort*)src_port_handle)->is_connected (dst_port)) ? "YES":"NO") << ", " << dst_port_name << ")" << std::endl;\r
+    return ((WavesDataPort*)src_port_handle)->is_connected (dst_port);\r
+}\r
+\r
+\r
+bool\r
+WavesAudioBackend::physically_connected (PortHandle port_handle, bool process_callback_safe)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::physically_connected ():" << std::endl;\r
+\r
+    if (!_registered (port_handle)) {\r
+        std::cerr << "WavesAudioBackend::physically_connected (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;\r
+        return false;\r
+    }\r
+\r
+    return ((WavesDataPort*)port_handle)->is_physically_connected ();\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::get_connections (PortHandle port_handle, std::vector<std::string>& names, bool process_callback_safe)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::get_connections ()" << std::endl;\r
+    \r
+    if (!_registered (port_handle)) {\r
+        std::cerr << "WavesAudioBackend::get_connections (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    if (names.size ()) {\r
+        std::cerr << "WavesAudioBackend::get_connections () : Parameter 'names' is not empty!\n";\r
+        return -1;\r
+    }\r
\r
+    const std::vector<WavesDataPort*>& connected_ports = ((WavesDataPort*)port_handle)->get_connections ();\r
+\r
+    for (std::vector<WavesDataPort*>::const_iterator it = connected_ports.begin (); it != connected_ports.end (); ++it) {\r
+        names.push_back ((*it)->name ());\r
+    }\r
+\r
+    return (int)names.size ();\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::request_input_monitoring (PortHandle, bool)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::request_input_monitoring: " << std::endl;\r
+    return 0;\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::ensure_input_monitoring (PortHandle, bool)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::ensure_input_monitoring: " << std::endl;\r
+    return 0;\r
+}\r
+\r
+\r
+bool\r
+WavesAudioBackend::monitoring_input (PortHandle)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::monitoring_input: " << std::endl;\r
+    return false;\r
+}\r
+\r
+\r
+bool\r
+WavesAudioBackend::port_is_physical (PortHandle port_handle) const\r
+{\r
+    \r
+    if (!_registered (port_handle)) {\r
+        std::cerr << "WavesAudioBackend::port_is_physical (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;\r
+        return -1;\r
+    }\r
+    \r
+    return (((WavesAudioPort*)port_handle)->flags () & IsPhysical) != 0;\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>& names)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::get_physical_outputs ():" << std::endl << "\tdatatype = " << type << std::endl;\r
+\r
+    switch (type) {\r
+        case ARDOUR::DataType::AUDIO: {\r
+            for (std::vector<WavesAudioPort*>::iterator it = _physical_audio_outputs.begin (); it != _physical_audio_outputs.end (); ++it) {\r
+                // COMMENTED DBG LOGS */ std::cout  << "\t" << (*it)->name () << std::endl;\r
+                names.push_back ((*it)->name ());\r
+            }\r
+        } break;\r
+        case ARDOUR::DataType::MIDI: {\r
+            for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_outputs.begin (); it != _physical_midi_outputs.end (); ++it) {\r
+                // COMMENTED DBG LOGS */ std::cout  << "\t" << (*it)->name () << std::endl;\r
+                names.push_back ((*it)->name ());\r
+            }\r
+        } break;\r
+        default:\r
+            break;\r
+    }\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>& names)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::get_physical_inputs ():" << std::endl << "\tdatatype = " << type << std::endl;\r
+    switch (type) {\r
+        case ARDOUR::DataType::AUDIO: {\r
+            for (std::vector<WavesAudioPort*>::iterator it = _physical_audio_inputs.begin (); it != _physical_audio_inputs.end (); ++it) {\r
+                // COMMENTED DBG LOGS */ std::cout  << "\t" << (*it)->name () << std::endl;\r
+                names.push_back ((*it)->name ());\r
+            }\r
+        } break;\r
+        case ARDOUR::DataType::MIDI: {\r
+            for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_inputs.begin (); it != _physical_midi_inputs.end (); ++it) {\r
+                // COMMENTED DBG LOGS */ std::cout  << "\t" << (*it)->name () << std::endl;\r
+                names.push_back ((*it)->name ());\r
+            }\r
+        } break;\r
+        default:\r
+        break;\r
+    }\r
+}\r
+\r
+\r
+ChanCount\r
+WavesAudioBackend::n_physical_outputs () const\r
+{\r
+    ChanCount chan_count;\r
+    chan_count.set (DataType::AUDIO, _physical_audio_outputs.size ());\r
+    chan_count.set (DataType::MIDI, _physical_midi_outputs.size ());\r
+\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::n_physical_outputs ():" << std::endl << "\ttotal = " << chan_count.n_total () << std::endl;\r
+\r
+    return chan_count;\r
+}\r
+\r
+\r
+ChanCount\r
+WavesAudioBackend::n_physical_inputs () const\r
+{\r
+    ChanCount chan_count;\r
+    chan_count.set (DataType::AUDIO, _physical_audio_inputs.size ());\r
+    chan_count.set (DataType::MIDI, _physical_midi_inputs.size ());\r
+\r
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::n_physical_outputs ():" << std::endl << "\ttotal = " << chan_count.n_total () << std::endl;\r
+\r
+    return chan_count;\r
+}\r
+\r
+\r
+void*\r
+WavesAudioBackend::get_buffer (PortHandle port_handle, pframes_t nframes)\r
+{\r
+    // Here we would check if the port is registered. However, we will not do it as\r
+    // it's relatively VERY SLOW operation. So let's count on consistency\r
+    // of the caller as get_buffer normally is called hundreds of "kilotimes" per second.\r
+\r
+    if (port_handle == NULL) {\r
+        std::cerr << "WavesAudioBackend::get_buffer : Invalid port handler <NULL>!" << std::endl;\r
+        return NULL;\r
+    }  \r
+    \r
+    return ((WavesAudioPort*)port_handle)->get_buffer (nframes);\r
+}\r
+\r
+\r
+int\r
+WavesAudioBackend::_register_system_audio_ports ()\r
+{\r
+    if (!_device) {\r
+        std::cerr << "WavesAudioBackend::_register_system_audio_ports (): No device is set!" << std::endl;\r
+        return -1;\r
+    }\r
+    \r
+    std::vector<std::string> input_channels = _device->InputChannels ();\r
+    _max_input_channels = input_channels.size ();\r
+    \r
+    uint32_t channels = (_input_channels ? _input_channels : input_channels.size ());\r
+    uint32_t port_number = 0;\r
+\r
+    LatencyRange lr = {0,0};\r
+\r
+    // Get latency for capture\r
+    lr.min = lr.max = _device->GetLatency (false) + _device->CurrentBufferSize () + _systemic_input_latency;\r
+    for (std::vector<std::string>::iterator it = input_channels.begin (); \r
+         (port_number < channels) && (it != input_channels.end ());\r
+        ++it) {\r
+        std::ostringstream port_name;\r
+        port_name << "capture_" << ++port_number;\r
+\r
+        WavesDataPort* port = _register_port ("system:" + port_name.str (), DataType::AUDIO , static_cast<PortFlags> (IsOutput | IsPhysical | IsTerminal));\r
+        if (port == NULL) {\r
+            std::cerr << "WavesAudioBackend::_create_system_audio_ports (): Failed registering port [" << port_name << "] for [" << _device->DeviceName () << "]" << std::endl;\r
+            return-1;\r
+        }\r
+        set_latency_range (port, false, lr);\r
+    }\r
+    \r
+    std::vector<std::string> output_channels = _device->OutputChannels ();\r
+    _max_output_channels = output_channels.size ();\r
+    channels = (_output_channels ? _output_channels : _max_output_channels);\r
+    port_number = 0;\r
+    \r
+    // Get latency for playback\r
+    lr.min = lr.max = _device->GetLatency (true) + _device->CurrentBufferSize () + _systemic_output_latency;\r
+\r
+    for (std::vector<std::string>::iterator it = output_channels.begin ();\r
+         (port_number < channels) && (it != output_channels.end ());\r
+        ++it) {\r
+        std::ostringstream port_name;\r
+        port_name << "playback_" << ++port_number;\r
+        WavesDataPort* port = _register_port ("system:" + port_name.str (), DataType::AUDIO , static_cast<PortFlags> (IsInput| IsPhysical | IsTerminal));\r
+        if (port == NULL) {\r
+            std::cerr << "WavesAudioBackend::_create_system_audio_ports (): Failed registering port ]" << port_name << "] for [" << _device->DeviceName () << "]" << std::endl;\r
+            return-1;\r
+        }\r
+        set_latency_range (port, true, lr);\r
+    }\r
+    \r
+    return 0;\r
+}\r
+\r
+\r
+void\r
+WavesAudioBackend::_unregister_system_audio_ports ()\r
+{\r
+    std::vector<WavesAudioPort*> physical_audio_ports = _physical_audio_inputs;\r
+    physical_audio_ports.insert (physical_audio_ports.begin (), _physical_audio_outputs.begin (), _physical_audio_outputs.end ());\r
+        \r
+    for (std::vector<WavesAudioPort*>::const_iterator it = physical_audio_ports.begin (); it != physical_audio_ports.end (); ++it) {\r
+        std::vector<WavesDataPort*>::iterator port_iterator = std::find (_ports.begin (), _ports.end (), *it);\r
+        if (port_iterator == _ports.end ()) {\r
+            std::cerr << "WavesAudioBackend::_unregister_system_audio_ports (): Failed to find port [" << (*it)->name () << "]!"  << std::endl;\r
+        }\r
+        else {\r
+            _ports.erase (port_iterator);\r
+        }\r
+        delete *it;\r
+    }\r
+\r
+    _physical_audio_inputs.clear ();\r
+    _physical_audio_outputs.clear ();\r
+}\r
+\r
+\r
diff --git a/libs/backends/wavesaudio/waves_audioport.cc b/libs/backends/wavesaudio/waves_audioport.cc
new file mode 100644 (file)
index 0000000..62bacdb
--- /dev/null
@@ -0,0 +1,62 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+#include "waves_audioport.h"\r
+\r
+using namespace ARDOUR;\r
+\r
+WavesAudioPort::WavesAudioPort (const std::string& port_name, PortFlags flags)\r
+    : WavesDataPort (port_name, flags)    \r
+{\r
+    memset (_buffer, 0, sizeof (_buffer));\r
+}\r
+\r
+\r
+void* WavesAudioPort::get_buffer (pframes_t nframes)\r
+{\r
+    if (is_input ()) {\r
+        \r
+        std::vector<WavesDataPort*>::const_iterator it = get_connections ().begin ();\r
+        \r
+        if (it != get_connections ().end ()) {\r
+            /* In fact, the static casting to (const WavesAudioPort*) is not that safe.\r
+             * However, mixing the buffers is assumed in the time critical conditions.\r
+             * Base class WavesDataPort takes is supposed to provide enough consistentcy\r
+             * of the connections.\r
+             */\r
+            for (memcpy (_buffer, ((const WavesAudioPort*)*it)->const_buffer (), nframes * sizeof (Sample)), ++it;\r
+                                it != get_connections ().end ();\r
+                                ++it) {\r
+                Sample* tgt = buffer ();\r
+                const Sample* src = ((const WavesAudioPort*)*it)->const_buffer ();\r
+                for (uint32_t frame = 0; frame < nframes; ++frame, ++tgt, ++src)    {\r
+                    *tgt += *src;\r
+                }\r
+            }\r
+        }\r
+    }\r
+    return _buffer;\r
+}\r
+\r
+\r
+void\r
+WavesAudioPort::_wipe_buffer()\r
+{\r
+       memset (_buffer, 0, sizeof (_buffer));\r
+}\r
diff --git a/libs/backends/wavesaudio/waves_audioport.h b/libs/backends/wavesaudio/waves_audioport.h
new file mode 100644 (file)
index 0000000..a0f878b
--- /dev/null
@@ -0,0 +1,58 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+#ifndef __libardour_waves_audioport_h__\r
+#define __libardour_waves_audioport_h__\r
+\r
+#include "memory.h"\r
+#include "waves_dataport.h"\r
+        \r
+namespace ARDOUR {\r
+\r
+class WavesAudioPort : public WavesDataPort {\r
+\r
+public:\r
+    enum BufferSize {\r
+        MAX_BUFFER_SIZE_SAMPLES = 8192,\r
+        MAX_BUFFER_SIZE_BYTES = sizeof (Sample) * MAX_BUFFER_SIZE_SAMPLES\r
+    };\r
+\r
+    WavesAudioPort (const std::string& port_name, PortFlags flags);\r
+\r
+    virtual ~WavesAudioPort () { };\r
+\r
+    virtual DataType type () const {    return DataType::AUDIO; };\r
+\r
+    inline Sample* buffer () { return _buffer; }\r
+    inline const Sample* const_buffer () const { return _buffer; }\r
+\r
+    virtual void* get_buffer (pframes_t nframes);\r
+\r
+protected:\r
+       virtual void _wipe_buffer();\r
+\r
+private:\r
+\r
+    Sample _buffer[MAX_BUFFER_SIZE_SAMPLES];\r
+};\r
+\r
+} // namespace\r
+\r
+#endif /* __libardour_waves_audioport_h__ */\r
+    \r
diff --git a/libs/backends/wavesaudio/waves_dataport.cc b/libs/backends/wavesaudio/waves_dataport.cc
new file mode 100644 (file)
index 0000000..84f4efa
--- /dev/null
@@ -0,0 +1,142 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+#include "waves_dataport.h"\r
+\r
+using namespace ARDOUR;\r
+\r
+WavesDataPort::WavesDataPort (const std::string& inport_name, PortFlags inflags)\r
+    : _name (inport_name)\r
+    , _flags (inflags)\r
+{\r
+    _capture_latency_range.min = \r
+    _capture_latency_range.max = \r
+    _playback_latency_range.min = \r
+    _playback_latency_range.max = 0;\r
+}\r
+\r
+\r
+WavesDataPort::~WavesDataPort ()\r
+{\r
+    disconnect_all ();\r
+}\r
+\r
+\r
+int WavesDataPort::connect (WavesDataPort *port)\r
+{\r
+    if (!port) {\r
+        std::cerr << "WavesDataPort::connect (): invalid (null) port to connect to!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    if (type () != port->type ())    {\r
+        std::cerr << "WavesDataPort::connect (): wrong type of the port to connect to!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    if (is_output () && port->is_output ()) {\r
+        std::cerr << "WavesDataPort::connect (): attempt to connect output port to output port!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    if (is_input () && port->is_input ()) {\r
+        std::cerr << "WavesDataPort::connect (): attempt to connect input port to input port!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    if (this == port) {\r
+        std::cerr << "WavesDataPort::connect (): attempt to connect port to itself!" << std::endl;\r
+        return -1; \r
+    }\r
+\r
+    if (is_connected (port)) {\r
+        std::cerr << "WavesDataPort::connect (): the ports are already connected!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    _connect (port, true);\r
+    return 0;\r
+}\r
+\r
+\r
+void WavesDataPort::_connect (WavesDataPort *port, bool api_call)\r
+{\r
+    _connections.push_back (port);\r
+    if (api_call) {\r
+        port->_connect (this, false);\r
+    }\r
+}\r
+\r
+\r
+int WavesDataPort::disconnect (WavesDataPort *port)\r
+{\r
+    if (port == NULL) {\r
+        std::cerr << "WavesDataPort::disconnect (): invalid (null) port to disconnect from!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    if (!is_connected (port)) {\r
+        std::cerr << "WavesDataPort::disconnect (): the ports are not connected!" << std::endl;\r
+        return -1;\r
+    }\r
+       \r
+    _disconnect (port, true);\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+void WavesDataPort::_disconnect (WavesDataPort *port, bool api_call)\r
+{\r
+    std::vector<WavesDataPort*>::iterator it = std::find (_connections.begin (), _connections.end (), port);\r
+    \r
+    if (it != _connections.end ()) { // actually, it's supposed to be always true.\r
+        _connections.erase (it);\r
+    }\r
+\r
+    if (api_call) {\r
+        port->_disconnect (this, false);\r
+    }\r
+\r
+       if (is_input() && _connections.empty())\r
+       {\r
+               _wipe_buffer();\r
+       }\r
+}\r
+\r
+\r
+void WavesDataPort::disconnect_all ()\r
+{\r
+    while (!_connections.empty ()) {\r
+        _connections.back ()->_disconnect (this, false);\r
+        _connections.pop_back ();\r
+    }\r
+}\r
+\r
+\r
+bool WavesDataPort::is_physically_connected () const\r
+{\r
+    for (std::vector<WavesDataPort*>::const_iterator it = _connections.begin (); it != _connections.end (); ++it) {\r
+        if ((*it)->is_physical ()) {\r
+            return true;\r
+        }\r
+    }\r
+\r
+    return false;\r
+}\r
diff --git a/libs/backends/wavesaudio/waves_dataport.h b/libs/backends/wavesaudio/waves_dataport.h
new file mode 100644 (file)
index 0000000..fd8dd80
--- /dev/null
@@ -0,0 +1,115 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+#ifndef __libardour_waves_dataport_h__\r
+#define __libardour_waves_dataport_h__\r
+\r
+#include "ardour/types.h"\r
+#include "memory.h"\r
+        \r
+namespace ARDOUR {\r
+\r
+class WavesDataPort {\r
+public:\r
+\r
+    virtual ~WavesDataPort ();\r
+\r
+    inline const std::string& name () const\r
+    {\r
+        return _name;\r
+    }\r
+    \r
+    int set_name (const std::string &name)\r
+    {\r
+        _name = name;\r
+        return 0;\r
+    }\r
+\r
+    virtual DataType type () const = 0;\r
+\r
+    inline PortFlags flags () const\r
+    {\r
+        return _flags;\r
+    }\r
+\r
+    inline bool is_input () { return flags () & IsInput; }\r
+    inline bool is_output () { return flags () & IsOutput; }\r
+    inline bool is_physical () { return flags () & IsPhysical; }\r
+    inline bool is_terminal () { return flags () & IsTerminal; }\r
+    inline operator void* () { return (void*)this; }\r
+\r
+    inline const LatencyRange& latency_range (bool for_playback) const\r
+    {\r
+        return for_playback ? _playback_latency_range : _capture_latency_range;\r
+    }\r
+\r
+    inline void set_latency_range (const LatencyRange &latency_range, bool for_playback)\r
+    {\r
+        if (for_playback)\r
+        {\r
+            _playback_latency_range = latency_range;\r
+        }\r
+        else\r
+        {\r
+            _capture_latency_range = latency_range;\r
+        }\r
+    }\r
+\r
+    int connect (WavesDataPort *port);\r
+    \r
+    int disconnect (WavesDataPort *port);\r
+    \r
+    void disconnect_all ();\r
+\r
+    bool inline is_connected (const WavesDataPort *port) const\r
+    {\r
+        return std::find (_connections.begin (), _connections.end (), port) != _connections.end ();\r
+    }\r
+\r
+    bool inline is_connected () const\r
+    {\r
+        return _connections.size () != 0;\r
+    }\r
+\r
+    bool is_physically_connected () const;\r
+\r
+    inline const std::vector<WavesDataPort *>& get_connections () const { return _connections; }\r
+\r
+    virtual void* get_buffer (pframes_t nframes) = 0;\r
+\r
+protected:\r
+    WavesDataPort (const std::string& inport_name, PortFlags inflags);\r
+       virtual void _wipe_buffer() = 0;\r
+\r
+private:\r
+\r
+    std::string _name;\r
+    const PortFlags _flags;\r
+    LatencyRange _capture_latency_range;\r
+    LatencyRange  _playback_latency_range;\r
+    std::vector<WavesDataPort*> _connections;\r
+\r
+    void _connect (WavesDataPort* port, bool api_call);\r
+    void _disconnect (WavesDataPort* port, bool api_call);\r
+};\r
+\r
+} // namespace\r
+\r
+#endif /* __libardour_waves_dataport_h__ */\r
+    \r
diff --git a/libs/backends/wavesaudio/waves_midi_buffer.cc b/libs/backends/wavesaudio/waves_midi_buffer.cc
new file mode 100644 (file)
index 0000000..24527de
--- /dev/null
@@ -0,0 +1,50 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+#include "waves_midi_buffer.h"\r
+#include "waves_midi_event.h"\r
+\r
+using namespace ARDOUR;\r
+\r
+WavesMidiBuffer::WavesMidiBuffer (std::string name)\r
+    : std::vector<WavesMidiEvent*> ()\r
+    , _name (name)\r
+{\r
+}\r
+\r
+WavesMidiBuffer::~WavesMidiBuffer ()\r
+{\r
+    clear ();\r
+}\r
+\r
+void WavesMidiBuffer::clear ()\r
+{\r
+    for (WavesMidiBufferIterator it = begin (); it !=  end (); ++it)\r
+        delete *it;\r
+\r
+    std::vector<WavesMidiEvent*>::clear ();\r
+}\r
+\r
+WavesMidiBuffer& WavesMidiBuffer::operator += (const WavesMidiBuffer& source)\r
+{\r
+    for (WavesMidiBufferConstIterator it = source.begin (); it !=  source.end (); ++it) {\r
+        push_back (new WavesMidiEvent (**it));\r
+    }\r
+    return *this;\r
+}\r
diff --git a/libs/backends/wavesaudio/waves_midi_buffer.h b/libs/backends/wavesaudio/waves_midi_buffer.h
new file mode 100644 (file)
index 0000000..b1f6e90
--- /dev/null
@@ -0,0 +1,47 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+#ifndef __libardour_waves_midi_buffer_h__\r
+#define __libardour_waves_midi_buffer_h__\r
+\r
+#include "ardour/types.h"\r
+\r
+namespace ARDOUR {\r
+\r
+class WavesMidiEvent;\r
+\r
+class WavesMidiBuffer : public std::vector<WavesMidiEvent*>\r
+{\r
+public:\r
+    WavesMidiBuffer (std::string name);\r
+    ~WavesMidiBuffer ();\r
+    void clear ();\r
+    WavesMidiBuffer& operator += (const WavesMidiBuffer& source);\r
+\r
+    inline const std::string name () { return _name; } // for DBG purpouses;\r
+\r
+private:\r
+    const std::string _name;\r
+};\r
+\r
+typedef std::vector<WavesMidiEvent*>::iterator WavesMidiBufferIterator;\r
+typedef std::vector<WavesMidiEvent*>::const_iterator WavesMidiBufferConstIterator;\r
+\r
+} // namespace\r
+\r
+#endif /* __libardour_waves_midi_buffer_h__ */\r
diff --git a/libs/backends/wavesaudio/waves_midi_device.cc b/libs/backends/wavesaudio/waves_midi_device.cc
new file mode 100644 (file)
index 0000000..aa30595
--- /dev/null
@@ -0,0 +1,268 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+#include "waves_midi_device.h"\r
+#include "waves_midi_event.h"\r
+\r
+// use non-zero latency because we want output to be timestapmed\r
+#define LATENCY 0\r
+\r
+#define QUEUE_LENGTH 1024\r
+\r
+using namespace ARDOUR;\r
+\r
+WavesMidiDevice::WavesMidiDevice (const std::string& device_name)\r
+    : _pm_input_id (pmNoDevice)\r
+    , _pm_output_id (pmNoDevice)\r
+    , _name (device_name)\r
+    , _input_queue (NULL)\r
+    , _output_queue (NULL)\r
+    , _input_pm_stream (NULL)\r
+    , _output_pm_stream (NULL)\r
+    , _incomplete_waves_midi_event (NULL)\r
+{\r
+    validate ();\r
+}\r
+\r
+WavesMidiDevice::~WavesMidiDevice ()\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::~WavesMidiDevice ():" << name () << std::endl;\r
+    close ();\r
+}\r
+\r
+void\r
+WavesMidiDevice::validate ()\r
+{\r
+    _pm_input_id = \r
+    _pm_output_id = pmNoDevice;\r
+    int count = Pm_CountDevices ();\r
+\r
+    for (int i = 0; i < count; i++) {\r
+\r
+        const PmDeviceInfo* pm_device_info = Pm_GetDeviceInfo (i);\r
+\r
+        if (pm_device_info == NULL) {\r
+            continue;\r
+        }\r
+        if (name () == pm_device_info->name) {\r
+            if (pm_device_info->input){\r
+                _pm_input_id = i;\r
+            }\r
+            if (pm_device_info->output){\r
+                _pm_output_id = i;\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+int\r
+WavesMidiDevice::open (PmTimeProcPtr time_proc, void* time_info)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::open ():" << name () << std::endl;\r
+    \r
+    if (is_input () && !_input_pm_stream) {\r
+        if (pmNoError != Pm_OpenInput (&_input_pm_stream, \r
+                                      _pm_input_id,\r
+                                      NULL,\r
+                                      1024,\r
+                                      time_proc,\r
+                                      time_info)) {\r
+                std::cerr << "WavesMidiDevice::open (): Pm_OpenInput () failed for " << _pm_input_id << "-[" << name () <<  "]!" << std::endl;\r
+                _input_pm_stream = NULL;\r
+                _pm_input_id = pmNoDevice;\r
+                return -1;\r
+        }\r
+        _input_queue = Pm_QueueCreate (QUEUE_LENGTH, sizeof (const WavesMidiEvent*));\r
+        if (NULL == _input_queue) {\r
+            std::cerr << "WavesMidiDevice::open (): _input_queue = Pm_QueueCreate () failed for " << _pm_input_id << "-[" << name () <<  "]!" << std::endl;\r
+            close ();\r
+            return -1;\r
+        }\r
+    }\r
+\r
+    if (is_output () && !_output_pm_stream) {\r
+        if (pmNoError != Pm_OpenOutput (&_output_pm_stream, \r
+                                       _pm_output_id, \r
+                                       NULL,\r
+                                       1024,\r
+                                       time_proc,\r
+                                       time_info,\r
+                                       LATENCY)) {\r
+                std::cerr << "WavesMidiDevice::open (): Pm_OpenOutput () failed for " << _pm_output_id << "-[" << name () <<  "]!" << std::endl;\r
+                _output_pm_stream = NULL;\r
+                _pm_output_id = pmNoDevice;\r
+                return -1;\r
+        }\r
+        _output_queue = Pm_QueueCreate (QUEUE_LENGTH, sizeof (const WavesMidiEvent*));\r
+        if (NULL == _output_queue) {\r
+            std::cerr << "WavesMidiDevice::open (): _output_queue = Pm_QueueCreate () failed for " << _pm_output_id << "-[" << name () <<  "]!" << std::endl;\r
+            close ();\r
+            return -1;\r
+        }\r
+    }\r
+    return 0;\r
+}\r
+\r
+\r
+void\r
+WavesMidiDevice::close ()\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::close ():" << name () << std::endl;\r
+    WavesMidiEvent *waves_midi_event;\r
+\r
+    if (_input_pm_stream) {\r
+        Pm_Close (_input_pm_stream);\r
+        while (1 == Pm_Dequeue (_input_queue, &waves_midi_event)) {\r
+            delete waves_midi_event;\r
+        }\r
+\r
+        Pm_QueueDestroy (_input_queue);\r
+        _input_queue = NULL;\r
+        _input_pm_stream = NULL;\r
+        _pm_input_id = pmNoDevice;\r
+    }\r
+\r
+\r
+    if ( _output_pm_stream ) {\r
+        Pm_Close (_output_pm_stream);\r
+        while (1 == Pm_Dequeue (_output_queue, &waves_midi_event)) {\r
+            delete waves_midi_event;\r
+        }\r
+        Pm_QueueDestroy (_output_queue);\r
+        _output_queue = NULL;\r
+        _output_pm_stream = NULL;\r
+        _pm_output_id = pmNoDevice;\r
+    }\r
+}\r
+\r
+void\r
+WavesMidiDevice::do_io ()\r
+{\r
+    read_midi ();\r
+    write_midi ();\r
+}\r
+\r
+void\r
+WavesMidiDevice::read_midi ()\r
+{\r
+    if (NULL == _input_pm_stream) {\r
+        return;\r
+    }\r
+\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_read_midi (): " << _pm_device_id << "-[" << name () << "]" << std::endl;\r
+\r
+    while (Pm_Poll (_input_pm_stream) > 0) {\r
+        PmEvent pm_event; // just one message at a time\r
+        int result = Pm_Read (_input_pm_stream, &pm_event, 1);\r
+        if (result < 0) {\r
+            std::cerr << "WavesMidiDevice::_read_midi (): Pm_Read () failed (" << result << ") for [" << name () << "]!" << std::endl;\r
+            break;\r
+        }\r
+        // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_read_midi (): " << _pm_device_id << "-[" << name () << "] evt-tm:" << pm_event.timestamp << std::endl;\r
+        if (_incomplete_waves_midi_event == NULL ) {\r
+            // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_read_midi (): " << _pm_device_id << "-[" << name () << "] : new _incomplete_waves_midi_event" << std::endl;\r
+            _incomplete_waves_midi_event = new WavesMidiEvent (pm_event.timestamp);\r
+        }\r
+        \r
+        WavesMidiEvent *nested_pm_event = _incomplete_waves_midi_event->append_data (pm_event);\r
+        if (nested_pm_event) {\r
+            Pm_Enqueue (_input_queue, &nested_pm_event);\r
+            // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_read_midi (): " << _pm_device_id << "-[" << name () << "] : Pm_Enqueue (_input_queue, nested_pm_event)" << std::endl;\r
+        }\r
+        switch ( _incomplete_waves_midi_event->state ()) {\r
+            case WavesMidiEvent::BROKEN:\r
+                delete _incomplete_waves_midi_event;\r
+                _incomplete_waves_midi_event = NULL;\r
+                // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_read_midi (): " << _pm_device_id << "-[" << name () << "] : case WavesMidiEvent::BROKEN:" << std::endl;\r
+            break;\r
+            case WavesMidiEvent::COMPLETE:\r
+                // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_read_midi (): " << _pm_device_id << "-[" << name () << "] : Pm_Enqueue (_input_queue, _incomplete_waves_midi_event); " << std::hex << (void*)_incomplete_waves_midi_event << std::dec << std::endl;\r
+                Pm_Enqueue (_input_queue, &_incomplete_waves_midi_event);\r
+                _incomplete_waves_midi_event = NULL;\r
+            break;\r
+            default:\r
+            break;\r
+        }\r
+    }\r
+}\r
+\r
+\r
+void\r
+WavesMidiDevice::write_midi ()\r
+{\r
+    if (NULL == _output_pm_stream) {\r
+        return;\r
+    }\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_write_midi (): " << _pm_device_id << "-[" << name () << "]" << std::endl;\r
+\r
+    PmError err;\r
+    WavesMidiEvent *waves_midi_event;\r
+\r
+    while (1 == Pm_Dequeue (_output_queue, &waves_midi_event)) {\r
+        if (waves_midi_event->sysex ()) {\r
+            // LATENCY compensation\r
+            err = Pm_WriteSysEx (_output_pm_stream, waves_midi_event->timestamp () - LATENCY, waves_midi_event->data ());\r
+            if (0 > err) {\r
+                std::cout << "WavesMidiDevice::write_event_to_device (): [" << name () << "] Pm_WriteSysEx () failed (" << err << ")!" << std::endl;\r
+            };\r
+            // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_write_midi (): SYSEX used, ev->tm:" << waves_midi_event->timestamp () - LATENCY << std::endl;\r
+        }\r
+        else\r
+        {\r
+            err = Pm_WriteShort (_output_pm_stream, waves_midi_event->timestamp () - LATENCY, * (PmMessage*)waves_midi_event->data ());\r
+            if (0 > err) {\r
+                std::cout << "WavesMidiDevice::write_event_to_device (): [" << name () << "] Pm_WriteShort () failed (" << err << ")!" << std::endl;\r
+            }\r
+            // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_write_midi (): SHORTMSG used, ev->tm:" << waves_midi_event->timestamp () - LATENCY <<  std::endl;\r
+        }\r
+        delete waves_midi_event;\r
+    }\r
+    return;\r
+}\r
+\r
+int\r
+WavesMidiDevice::enqueue_output_waves_midi_event (const WavesMidiEvent* waves_midi_event)\r
+{\r
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::enqueue_output_waves_midi_event (): " << _pm_device_id << "-[" << name () << "]" << std::endl;\r
+\r
+    if (waves_midi_event == NULL) {\r
+        std::cerr << "WavesMidiDevice::put_event_to_callback (): 'waves_midi_event' is NULL!" << std::endl;\r
+        return -1;\r
+    }\r
+\r
+    PmError err = Pm_Enqueue (_output_queue, &waves_midi_event);\r
+\r
+    if (0 > err) {\r
+        std::cerr << "WavesMidiDevice::put_event_to_callback (): Pm_Enqueue () failed (" << err << ")!" << std::endl;\r
+        return -1;\r
+    };\r
+\r
+    return 0;\r
+}\r
+\r
+WavesMidiEvent* \r
+WavesMidiDevice::dequeue_input_waves_midi_event ()\r
+{\r
+    WavesMidiEvent* waves_midi_event;\r
+    if (Pm_Dequeue (_input_queue, &waves_midi_event) == 1) {\r
+        return waves_midi_event;\r
+    }\r
+    return NULL;\r
+}\r
+\r
diff --git a/libs/backends/wavesaudio/waves_midi_device.h b/libs/backends/wavesaudio/waves_midi_device.h
new file mode 100644 (file)
index 0000000..a8b7347
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+    Copyright (C) 2014 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_waves_midi_device_h__
+#define __libardour_waves_midi_device_h__
+
+#include <portmidi/portmidi.h>
+#include <portmidi/pmutil.h>
+#include <portmidi/porttime.h>
+
+#include "ardour/types.h"
+
+namespace ARDOUR {
+
+class WavesMidiEvent;
+
+class WavesMidiDevice {
+public:
+    WavesMidiDevice (const std::string& name);
+    ~WavesMidiDevice ();
+
+    inline const std::string& name () const { return _name; }
+
+    int open (PmTimeProcPtr time_proc, void* time_info);
+    void close ();
+    void do_io ();
+    void read_midi ();
+    void write_midi ();
+
+    int enqueue_output_waves_midi_event (const WavesMidiEvent* waves_midi_event);
+    WavesMidiEvent* dequeue_input_waves_midi_event ();
+
+    inline bool is_input () const { return _pm_input_id != pmNoDevice; };
+    inline bool is_output () const { return _pm_output_id != pmNoDevice; };
+    void validate ();
+
+private:
+
+
+    PmDeviceID _pm_input_id;
+    PmDeviceID _pm_output_id;
+    const std::string _name;
+
+    /* shared queues */
+    PmQueue* _input_queue;
+    PmQueue* _output_queue;
+
+    PmStream* _input_pm_stream;
+    PmStream* _output_pm_stream;
+    WavesMidiEvent *_incomplete_waves_midi_event;
+};
+
+} // namespace
+
+#endif /* __libardour_waves_midi_device_h__ */
+    
diff --git a/libs/backends/wavesaudio/waves_midi_device_manager.cc b/libs/backends/wavesaudio/waves_midi_device_manager.cc
new file mode 100644 (file)
index 0000000..84667a2
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+    Copyright (C) 2014 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "waves_midi_device_manager.h"
+#include "waves_audiobackend.h"
+
+#ifdef __WINDOWS__
+
+#include "windows.h"
+#include "mmsystem.h"
+
+#elif __MACOS__
+
+#include <CoreMIDI/MIDIServices.h>
+
+#define midiInGetNumDevs MIDIGetNumberOfSources
+#define midiOutGetNumDevs MIDIGetNumberOfDestinations
+
+#endif
+
+using namespace ARDOUR;
+
+WavesMidiDeviceManager::WavesMidiDeviceManager (WavesAudioBackend& audiobackend)
+    : _active (false)
+    , _streaming (false)
+    , _input_device_count (0)
+    , _output_device_count (0)
+    , _audiobackend (audiobackend)
+{
+}
+
+
+WavesMidiDeviceManager::~WavesMidiDeviceManager ()
+{
+}
+
+
+int
+WavesMidiDeviceManager::start ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDeviceManager::stream ():" << std::endl;
+    if ( _active == true ) {
+        return -1;
+    }
+
+    if (Pm_Initialize () != pmNoError) {
+        return -1;
+    }
+
+    _create_devices ();
+
+    _input_device_count = midiInGetNumDevs ();
+    _output_device_count = midiOutGetNumDevs ();
+
+    _active = true;
+
+    return 0;
+}
+
+
+int
+WavesMidiDeviceManager::stream (bool yn)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDeviceManager::stream ():" << std::endl;
+    if (!_active) {
+        std::cerr << "WavesMidiDeviceManager::stream (): the midi device manager is not started up !" << std::endl;
+        return -1;
+    }
+
+    if (_streaming == yn) {
+        return 0;
+    }
+
+    if (yn)    {
+        if ( Pt_Start (1, __portmidi_callback, this) != ptNoError) {
+            std::cerr << "WavesMidiDeviceManager::stream (): Pt_Start () failed!" << std::endl;
+            return -1;
+        }
+    }
+    else {
+        if (Pt_Stop () != ptNoError) {
+            std::cerr << "WavesMidiDeviceManager::stream (): Pt_Stop () failed!" << std::endl;
+            return -1;
+        }
+    }
+
+    _streaming = yn;
+    return 0;
+}
+
+
+int
+WavesMidiDeviceManager::stop ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDeviceManager::stop ():" << std::endl;
+
+    if ( _active == false )
+        return 0;
+    
+    stream (false);
+
+    _close_devices ();
+    _active = false;
+
+    if (Pm_Terminate () != pmNoError) {
+        std::cerr << "WavesMidiDeviceManager::stop (): Pt_Terminate () failed!" << std::endl;
+        return -1;
+    }
+
+    return 0;
+}
+
+void 
+WavesMidiDeviceManager::__portmidi_callback (PtTimestamp timestamp, void * userData)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDeviceManager::__portmidi_callback ():" << std::endl;
+    WavesMidiDeviceManager *dm = (WavesMidiDeviceManager *)userData;
+    
+    if (dm == NULL) {
+        return;
+    }
+    
+    dm->_portmidi_callback (timestamp);
+}
+
+void
+WavesMidiDeviceManager::_portmidi_callback (PtTimestamp timestamp)
+{
+    if ((!_active) || (!_streaming)) {
+        return;
+    }
+
+    if ((_input_device_count != midiInGetNumDevs ()) || (_output_device_count != midiOutGetNumDevs ())) {
+        _audiobackend._changed_midi_devices ();
+        return;
+    }
+}
+
+void WavesMidiDeviceManager::do_read ()
+{
+    for (std::vector<WavesMidiDevice *>::const_iterator it = _devices.begin ();  it != _devices.end (); ++it) {
+        (*it)->read_midi ();
+    }
+}
+
+
+void WavesMidiDeviceManager::do_write ()
+{
+    for (std::vector<WavesMidiDevice *>::const_iterator it = _devices.begin ();  it != _devices.end (); ++it) {
+        (*it)->write_midi ();
+    }
+}
+
+
+PmTimestamp
+WavesMidiDeviceManager::__get_time_ms (void *time_info)
+{ 
+    return ((WavesAudioBackend*)time_info)->sample_time ();
+}
+
+
+WavesMidiDevice* WavesMidiDeviceManager::_get_device (const std::string& name)
+{
+    for (size_t i = 0; i < _devices.size (); i++) {
+        if (name == _devices[i]->name ()) {
+            return _devices[i];
+        }
+    }
+    return NULL;
+}
+
+
+int
+WavesMidiDeviceManager::_create_devices ()
+{
+    int count = Pm_CountDevices ();
+
+    for (int i = 0; i < count; i++) {
+
+        const PmDeviceInfo* pm_device_info = Pm_GetDeviceInfo (i);
+
+        if (pm_device_info == NULL) {
+            std::cerr << "WavesMidiDeviceManager::_create_devices (): Pm_GetDeviceInfo (" << i << ") failed!" << std::endl;
+            continue;
+        }
+
+        WavesMidiDevice *device = _get_device (pm_device_info->name);
+        if (device) {
+            device->validate ();
+        }
+        else
+        {
+            device = new WavesMidiDevice (pm_device_info->name);
+            _devices.push_back (device);
+        }
+
+        if (device->open (__get_time_ms, (void*)&_audiobackend)) {
+            std::cerr << "WavesMidiDeviceManager::_create_devices (): [" << device->name () << "]->open () failed!" << std::endl;
+        }
+    }
+
+    return 0;
+}
+
+
+int
+WavesMidiDeviceManager::_delete_devices ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDeviceManager::_delete_devices ():" << std::endl;
+    while (!_devices.empty ()) {
+        WavesMidiDevice * device = _devices.back ();
+        _devices.pop_back ();
+        delete device;
+    }
+    return 0;
+}
+
+
+void
+WavesMidiDeviceManager::_close_devices ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDeviceManager::_delete_devices ():" << std::endl;
+    for (size_t i = 0; i < _devices.size (); i++) {
+        _devices[i]->close ();
+    }
+}
diff --git a/libs/backends/wavesaudio/waves_midi_device_manager.h b/libs/backends/wavesaudio/waves_midi_device_manager.h
new file mode 100644 (file)
index 0000000..75a2757
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+    Copyright (C) 2014 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_waves_midi_device_manager_h__
+#define __libardour_waves_midi_device_manager_h__
+
+#include "waves_midi_device.h"
+
+namespace ARDOUR {
+
+class WavesAudioBackend;
+
+class WavesMidiDeviceManager {
+public:
+    WavesMidiDeviceManager (WavesAudioBackend& audiobackend);
+    ~WavesMidiDeviceManager ();
+
+    inline const std::vector<WavesMidiDevice *>& devices () const 
+    {
+        return _devices;
+    }
+
+    int start ();
+    int stop ();
+    int stream (bool yn);
+    int is_streaming () { return _streaming; }
+    void do_read ();
+    void do_write ();
+
+private:
+
+    int _create_devices ();
+    void _close_devices ();
+
+    int _delete_devices ();
+    static void __portmidi_callback (PtTimestamp timestamp, void * userData);
+    void _portmidi_callback (PtTimestamp timestamp);
+    /** __get_time_ms is given to Pm_Open functions (see WavesMidiDevice.cc)
+     *  to provide the time in milliseconds using the time of audio
+     *  transport. 
+     *  time_info is a pointer on the backend instance, which agregates the
+     *  audio and miditransports. It's not checked for correctness to consume
+     *  no time. 
+     */
+    static PmTimestamp __get_time_ms (void *time_info);
+
+    WavesMidiDevice* _get_device (const std::string& name);
+
+    std::vector<WavesMidiDevice*> _devices; // Vector for midi devices
+    bool _active;
+    bool _streaming;
+
+    size_t _input_device_count;
+    size_t _output_device_count;
+    WavesAudioBackend& _audiobackend;
+};
+
+} // namespace
+
+#endif /* __libardour_waves_midi_device_manager_h__ */
+    
diff --git a/libs/backends/wavesaudio/waves_midi_event.cc b/libs/backends/wavesaudio/waves_midi_event.cc
new file mode 100644 (file)
index 0000000..532555c
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+    Copyright (C) 2014 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "memory.h"
+#include "waves_midi_event.h"
+
+using namespace ARDOUR;
+
+WavesMidiEvent::WavesMidiEvent (PmTimestamp timestamp)
+    : _size (0)
+    , _timestamp (timestamp)
+    , _data (NULL)
+    , _state (INCOMPLETE) 
+{
+
+}
+
+
+WavesMidiEvent::WavesMidiEvent (PmTimestamp timestamp, const uint8_t* data, size_t datalen)
+    : _size (datalen)
+    , _timestamp (timestamp)
+    , _data (data && datalen ? new uint8_t[ (datalen < sizeof (PmMessage)) ? sizeof (PmMessage) : datalen] : NULL)
+    , _state (data && datalen ? COMPLETE : BROKEN) 
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesMidiEvent::WavesMidiEvent (const WavesMidiEvent& source) : Size=" << _size << "---" << datalen << std::endl;
+    if (_state == COMPLETE) {
+        // COMMENTED DBG LOGS */ std::cout  << "\t\t\t Allocated Size=" << ((datalen < sizeof (PmMessage)) ? sizeof (PmMessage) : datalen) << std::endl;
+        memcpy (_data, data, datalen);
+    }
+}
+
+
+WavesMidiEvent::WavesMidiEvent (const WavesMidiEvent& source)
+    : _size (source.size ())
+    , _timestamp (source.timestamp ())
+    , _data ((source.size () && source.const_data ()) ? new uint8_t[ (source.size () < sizeof (PmMessage)) ? sizeof (PmMessage) : source.size ()] : NULL)
+    , _state (source.state () ) 
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesMidiEvent::WavesMidiEvent (const WavesMidiEvent& source) : Size=" << _size << "---" << source.size () << std::endl;
+    // COMMENTED DBG LOGS */ std::cout  << "\t\t\t Allocated Size=" << ((source.size () < sizeof (PmMessage)) ? sizeof (PmMessage) : source.size ()) << std::endl;
+    if (_data && source.const_data ()) {
+        memcpy (_data, source.const_data (), source.size ());
+    }
+}
+
+
+WavesMidiEvent::~WavesMidiEvent ()
+{
+    delete _data;
+}
+
+
+WavesMidiEvent *WavesMidiEvent::append_data (const PmEvent &midi_event)
+{
+    switch ( _state ) {
+        case INCOMPLETE: 
+            break;
+        default:
+            // COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::append_data (): NO case INCOMPLETE" << std::endl;
+            _state = BROKEN;
+            return NULL;
+    }
+
+    size_t message_size = _midi_message_size (midi_event.message);
+    uint8_t message_status = Pm_MessageStatus (midi_event.message);
+
+    if (_data == NULL) { // This is a first event to add
+        bool sysex = (message_status == SYSEX);
+        _data = new unsigned char [sysex ? PM_DEFAULT_SYSEX_BUFFER_SIZE : sizeof (PmMessage)];
+        if (!sysex)
+        {
+            // COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::append_data (): SHORT MSG" << std::endl;
+            * (PmMessage*)_data = 0; 
+            switch (message_size) {
+                case 1:
+                case 3:
+                    _size = message_size;
+                    // COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::append_data (): size = " << _size << std::endl;
+                break;
+                default:
+                    // COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::append_data (): WRONG MESSAGE SIZE (" << message_size << ") in the message: ";
+                    // COMMENTED DBG LOGS */ std::cout << std::hex << (int) ((unsigned char*)&midi_event)[0] << " " << (int) ((unsigned char*)&midi_event)[1] << " " << (int) ((unsigned char*)&midi_event)[2] << " " << (int) ((unsigned char*)&midi_event)[3] << std::dec << std::endl;
+                    _state = BROKEN;
+                return NULL;
+            }
+            // COMMENTED DBG LOGS */ std::cout << "\t size = " << _size << std::endl;
+            memcpy (_data, &midi_event.message, _size);
+            // COMMENTED DBG LOGS */ std::cout << "\t\t size = " << _size << std::endl;
+            _state = COMPLETE;
+            // COMMENTED DBG LOGS */ std::cout << "\t\t\t size = " << _size << std::endl;
+            return NULL;
+        }
+    }
+
+    // Now let's parse to sysex msg
+    if (message_status >= REAL_TIME_FIRST) { // Nested Real Time MIDI event
+        WavesMidiEvent *waves_midi_message = new WavesMidiEvent (midi_event.timestamp);
+        waves_midi_message->append_data (midi_event);
+        return waves_midi_message;
+    }
+
+    if (message_status >= STATUS_FIRST && (message_status != EOX) && _size) { // Certainly it's a broken SYSEX case
+        WavesMidiEvent *waves_midi_message = new WavesMidiEvent (midi_event.timestamp);
+        waves_midi_message->append_data (midi_event);
+        return waves_midi_message;
+    }
+
+    const uint8_t* source_data ((uint8_t*)&midi_event.message);
+    
+    for (size_t i = 0; i < sizeof (midi_event.message); ++i) {
+        _data[_size] = source_data[i];
+        _size++;
+        
+        if (source_data[i] == EOX) { // Ended SYSEX message
+            _state = COMPLETE;
+            return NULL;
+        }
+    }
+    return NULL;
+}
+
+
+size_t WavesMidiEvent::_midi_message_size (PmMessage midi_message)
+{
+    static int high_lengths[] = {
+        1, 1, 1, 1, 1, 1, 1, 1,         /* 0x00 through 0x70 */
+        3, 3, 3, 3, 2, 2, 3, 1          /* 0x80 through 0xf0 */
+    };
+
+    static int low_lengths[] = {
+        1, 2, 3, 2, 1, 1, 1, 1,         /* 0xf0 through 0xf7 */
+        1, 1, 1, 1, 1, 1, 1, 1          /* 0xf8 through 0xff */
+    };
+
+    int midi_message_status = Pm_MessageStatus (midi_message);
+
+    if (midi_message_status < STATUS_FIRST) {
+        return sizeof (midi_message);
+    }
+
+    int high = midi_message_status >> 4;
+    int low = midi_message_status & 0xF;
+
+    return (high != 0xF) ? high_lengths[high] : low_lengths[low];
+}
diff --git a/libs/backends/wavesaudio/waves_midi_event.h b/libs/backends/wavesaudio/waves_midi_event.h
new file mode 100644 (file)
index 0000000..9015a2c
--- /dev/null
@@ -0,0 +1,75 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+#ifndef __libardour_waves_midi_event_h__\r
+#define __libardour_waves_midi_event_h__\r
+\r
+#include <stdlib.h>\r
+#include <portmidi/portmidi.h>\r
+#include "ardour/types.h"\r
+\r
+namespace ARDOUR {\r
+\r
+class WavesMidiEvent\r
+{\r
+public:\r
+    enum State {\r
+        INCOMPLETE,\r
+        BROKEN,\r
+        COMPLETE\r
+    };\r
+\r
+    WavesMidiEvent (PmTimestamp timestamp);\r
+    WavesMidiEvent (PmTimestamp timestamp, const uint8_t* data, size_t datalen);\r
+    WavesMidiEvent (const WavesMidiEvent& source);\r
+    ~WavesMidiEvent ();\r
+    \r
+    WavesMidiEvent *append_data (const PmEvent &midi_event);\r
+\r
+    inline State state () const { return _state; };\r
+    inline size_t size () const { return _size; };\r
+    inline PmTimestamp timestamp () const { return _timestamp; };\r
+    inline void set_timestamp (PmTimestamp time_stamp) { _timestamp = time_stamp; };\r
+    inline const unsigned char* const_data () const { return _data; };\r
+    inline unsigned char* data () { return _data; };\r
+    inline bool operator< (const WavesMidiEvent &other) const { return timestamp () < other.timestamp (); };\r
+    inline bool sysex () const { return _data && (*_data == SYSEX); };\r
+\r
+private:\r
+\r
+    enum\r
+    {\r
+        SYSEX = 0xF0,\r
+        EOX = 0xF7,\r
+        REAL_TIME_FIRST = 0xF8,\r
+        STATUS_FIRST = 0x80\r
+    };\r
+\r
+    size_t _size;\r
+    PmTimestamp _timestamp;\r
+    uint8_t *_data;\r
+    State _state;\r
+\r
+    static size_t _midi_message_size (PmMessage midi_message);\r
+};\r
+\r
+\r
+} // namespace\r
+\r
+#endif /* __libardour_waves_midi_event_h__ */\r
diff --git a/libs/backends/wavesaudio/waves_midiport.cc b/libs/backends/wavesaudio/waves_midiport.cc
new file mode 100644 (file)
index 0000000..8a77776
--- /dev/null
@@ -0,0 +1,61 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+#include "waves_midiport.h"\r
+#include "waves_midi_event.h"\r
+\r
+using namespace ARDOUR;\r
+\r
+WavesMidiPort::WavesMidiPort (const std::string& port_name, PortFlags flags)\r
+    : WavesDataPort (port_name, flags)\r
+    , _midi_device (NULL)\r
+    , _waves_midi_buffer (port_name)\r
+{       \r
+}\r
+\r
+void* \r
+WavesMidiPort::get_buffer (pframes_t nframes)\r
+{\r
+    if (is_input ()) {\r
+               std::vector<WavesDataPort*>::const_iterator cit = get_connections ().begin ();\r
+        if (cit != get_connections ().end ()) {\r
+                       _waves_midi_buffer.clear ();\r
+                       WavesMidiBuffer& target = _waves_midi_buffer;\r
+\r
+                       do      {\r
+                               /* In fact, the static casting to (const WavesMidiPort*) is not that safe.\r
+                                * However, mixing the buffers is assumed in the time critical conditions.\r
+                                * Base class WavesDataPort is supposed to provide enough consistentcy\r
+                                * of the connections.\r
+                                */\r
+                               target += ((const WavesMidiPort*)*cit)->const_buffer ();\r
+                       }while((++cit) != get_connections ().end ());\r
+\r
+                       std::sort (target.begin (), target.end ());\r
+               }\r
+       }\r
+\r
+    return &_waves_midi_buffer;\r
+}\r
+\r
+void\r
+WavesMidiPort::_wipe_buffer()\r
+{\r
+       _waves_midi_buffer.clear ();\r
+}\r
diff --git a/libs/backends/wavesaudio/waves_midiport.h b/libs/backends/wavesaudio/waves_midiport.h
new file mode 100644 (file)
index 0000000..6df1c2b
--- /dev/null
@@ -0,0 +1,64 @@
+/*\r
+    Copyright (C) 2014 Waves Audio Ltd.\r
+\r
+    This program is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+\r
+*/\r
+\r
+#ifndef __libardour_waves_midiport_h__\r
+#define __libardour_waves_midiport_h__\r
+\r
+#include "waves_dataport.h"\r
+#include "waves_midi_buffer.h"\r
+\r
+namespace ARDOUR {\r
+\r
+class WavesMidiEvent;\r
+class WavesMidiDevice;\r
+class WavesMidiEvent;\r
+\r
+class WavesMidiPort : public WavesDataPort {\r
+public:\r
+    enum BufferSize {\r
+        // This value has nothing to do with reality as buffer of MIDI Port is not a flat array.\r
+        // It's an iterated list.\r
+        MAX_BUFFER_SIZE_BYTES = 8192\r
+    };\r
+\r
+    WavesMidiPort (const std::string& port_name, PortFlags flags);\r
+    virtual ~WavesMidiPort (){};\r
+\r
+    virtual DataType type () const {    return DataType::MIDI; };\r
+\r
+    virtual void* get_buffer (pframes_t nframes);\r
+\r
+    inline WavesMidiBuffer& buffer () { return _waves_midi_buffer; }\r
+    inline const WavesMidiBuffer& const_buffer () const { return _waves_midi_buffer; }\r
+\r
+    inline void set_midi_device (WavesMidiDevice* midi_device) { _midi_device = midi_device; };\r
+    inline WavesMidiDevice* midi_device () const { return _midi_device; };\r
+\r
+protected:\r
+       virtual void _wipe_buffer();\r
+\r
+private:\r
+    WavesMidiDevice * _midi_device;\r
+    WavesMidiBuffer _waves_midi_buffer;\r
+};\r
+\r
+} // namespace\r
+\r
+#endif /* __libardour_waves_midiport_h__ */\r
+    \r
diff --git a/libs/backends/wavesaudio/wavesapi/BasicTypes/WCFourCC.h b/libs/backends/wavesaudio/wavesapi/BasicTypes/WCFourCC.h
new file mode 100644 (file)
index 0000000..165acc3
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __WCFourCC_h__
+       #define __WCFourCC_h__
+       
+/* Copy to include
+#include "BasicTypes/WCFourCC.h"
+*/
+
+//#include "BasicTypes/WTByteOrder.h"
+#include "WCFixedString.h"
+
+
+// These are preprocessor macros rather than inline functions because most compilers can't
+// resolve functions at compile-time.
+#if _BYTEORDER_BIG_ENDIAN==1
+       #define FOURCC_BIG(a, b, c, d)    ((uint32_t(a)<<24)|(uint32_t(b)<<16)|(uint32_t(c)<< 8)|(uint32_t(d)<< 0))
+       #define FOURCC_LITTLE(a, b, c, d) ((uint32_t(a)<< 0)|(uint32_t(b)<< 8)|(uint32_t(c)<<16)|(uint32_t(d)<<24))
+       #define FOURCC_COMPILER(a, b, c, d) FOURCC_BIG(a,b,c,d)
+#elif _BYTEORDER_BIG_ENDIAN==0
+       #define FOURCC_BIG(a, b, c, d)    ((uint32_t(a)<< 0)|(uint32_t(b)<< 8)|(uint32_t(c)<<16)|(uint32_t(d)<<24))
+       #define FOURCC_LITTLE(a, b, c, d) ((uint32_t(a)<<24)|(uint32_t(b)<<16)|(uint32_t(c)<< 8)|(uint32_t(d)<< 0))
+       #define FOURCC_COMPILER(a, b, c, d) FOURCC_LITTLE(a,b,c,d)
+#else
+       #error _BYTEORDER_BIG_ENDIAN not defined proparly
+#endif // _BYTEORDER_HPP_BIG_ENDIAN
+
+typedef uint32_t WTFourCharCode;
+
+#ifndef kEnableWCFourCCDebug
+       #define kEnableWCFourCCDebug 0 // set to 1 to enable debug members
+#endif
+
+
+class WCFourCC
+{
+private:
+       template<class _iter> 
+       static WTFourCharCode stored_from_iter(_iter& i)
+       {
+               return s_stored_byte_order==wvNS::wvBO::byte_order_big_endian ? FOURCC_BIG(i[0], i[1], i[2], i[3]) : FOURCC_LITTLE(i[0], i[1], i[2], i[3]);
+       }
+
+public:
+
+       //      static const WCFourCC kDefaultFourCC_prv;
+
+       static WCFourCC kDefaultFourCC_prv() { return WCFourCC(); }
+
+       // change this line will change the byte order in which WCFourCC keeps the four char code
+       static const wvNS::wvBO::byte_order_type s_stored_byte_order = wvNS::wvBO::compiler_byte_order;
+
+       WCFourCC(const char a, const char b, const char c, const char d) : 
+               m_stored_value(s_stored_byte_order==wvNS::wvBO::compiler_byte_order ? FOURCC_BIG(a,b,c,d) : FOURCC_LITTLE(a,b,c,d))
+       {
+#if kEnableWCFourCCDebug == 1
+               m_c_str_stored_value[sizeof(WTFourCharCode)] = '\0';
+#endif
+       }
+
+       WCFourCC() :
+               m_stored_value(FOURCC_BIG('?','?','?','?'))      // since the four chars are the same, there is no need to choose between big & little
+       {
+#if kEnableWCFourCCDebug == 1
+               m_c_str_stored_value[sizeof(WTFourCharCode)] = '\0';
+#endif
+       }
+
+       WCFourCC(const WTFourCharCode in_fourCharCode, const wvNS::wvBO::byte_order_type in_byteOrder = wvNS::wvBO::compiler_byte_order) :
+               m_stored_value(in_byteOrder==s_stored_byte_order ? in_fourCharCode : wvNS::wvBO::swap32(in_fourCharCode))
+       {
+#if kEnableWCFourCCDebug == 1
+               m_c_str_stored_value[sizeof(WTFourCharCode)] = '\0';
+#endif
+       }
+
+       explicit WCFourCC(const char* in_source_string) :
+               m_stored_value(stored_from_iter(in_source_string))
+       {
+#if kEnableWCFourCCDebug == 1
+               m_c_str_stored_value[sizeof(WTFourCharCode)] = '\0';
+#endif
+       }
+
+       explicit WCFourCC(const WCFixedStringBase& in_source_string) :
+               m_stored_value(stored_from_iter(in_source_string))
+       {
+#if kEnableWCFourCCDebug == 1
+               m_c_str_stored_value[sizeof(WTFourCharCode)] = '\0';
+#endif
+       }
+
+       WTFourCharCode GetAsSomeEndian(const wvNS::wvBO::byte_order_type in_byteOrder) const
+       {
+               return s_stored_byte_order==in_byteOrder ? m_stored_value : wvNS::wvBO::swap32(m_stored_value);
+       }
+
+       WTFourCharCode GetAsBigEndian() const
+       {
+               return s_stored_byte_order==wvNS::wvBO::byte_order_big_endian ? m_stored_value : wvNS::wvBO::swap32(m_stored_value);
+       }
+
+       WTFourCharCode GetAsLittleEndian() const
+       {
+               return s_stored_byte_order==wvNS::wvBO::byte_order_little_endian ? m_stored_value : wvNS::wvBO::swap32(m_stored_value);
+       }
+
+       WTFourCharCode GetAsCompilerEndian() const
+       {
+               return s_stored_byte_order==wvNS::wvBO::compiler_byte_order ? m_stored_value : wvNS::wvBO::swap32(m_stored_value);
+       }
+
+       WTFourCharCode GetAsStored() const
+       {
+               return m_stored_value;
+       }
+
+       char operator[](const unsigned int in_character_index) const
+       {
+               return char(m_stored_value >> (8 * (s_stored_byte_order==wvNS::wvBO::compiler_byte_order ? 3-in_character_index : in_character_index)));
+       }
+
+       char& operator[](const unsigned int in_character_index)
+       {
+               return reinterpret_cast<char*>(&m_stored_value)[s_stored_byte_order==wvNS::wvBO::byte_order_little_endian ? 3-in_character_index : in_character_index];
+       }
+    
+    static size_t size()
+    {
+        return sizeof(WTFourCharCode);
+    }
+
+       static size_t max_size()
+       {
+               return size();
+       }
+    
+       static size_t capacity()
+       {
+               return size();
+       }
+    
+       WCFixedString4 GetString() const
+       {
+               WCFixedString4 retVal;
+               retVal << operator[](0) << operator[](1) << operator[](2) << operator[](3);
+
+               return retVal;
+       }
+
+#if kEnableWCFourCCDebug == 1
+       const char* c_str() const
+       {
+               return m_c_str_stored_value;
+       }
+#endif
+
+protected:
+
+private:
+#if kEnableWCFourCCDebug == 1
+       union
+       {
+#endif
+               WTFourCharCode m_stored_value;
+#if kEnableWCFourCCDebug == 1
+               char m_c_str_stored_value[sizeof(WTFourCharCode)+1];
+       };
+#endif
+
+       WCFourCC& operator=(const WTFourCharCode); // we want initialization from literal to be dome through the constructor
+};
+
+inline bool operator<(const WCFourCC in_left, const WCFourCC in_right)
+{
+       return in_left.GetAsSomeEndian(WCFourCC::s_stored_byte_order) < in_right.GetAsSomeEndian(WCFourCC::s_stored_byte_order);
+}
+inline bool operator==(const WCFourCC in_left, const WCFourCC in_right)
+{
+       return in_left.GetAsSomeEndian(WCFourCC::s_stored_byte_order) == in_right.GetAsSomeEndian(WCFourCC::s_stored_byte_order);
+}
+
+inline bool operator!=(const WCFourCC in_left, const WCFourCC in_right)
+{
+       return ! operator==(in_left, in_right);
+}
+
+
+#define kDefaultFourCC WCFourCC::kDefaultFourCC_prv()
+
+static const WCFourCC kZeroFourCC(0, wvNS::wvBO::compiler_byte_order);
+       
+#endif //#if !defined(__WCFourCC_h__)
+
+
+
diff --git a/libs/backends/wavesaudio/wavesapi/BasicTypes/WTByteOrder.h b/libs/backends/wavesaudio/wavesapi/BasicTypes/WTByteOrder.h
new file mode 100644 (file)
index 0000000..7d7fd8c
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#if !defined(__WTByteOrder_h__)
+#define __WTByteOrder_h__
+
+/* Copy to include
+#include "BasicTypes/WTByteOrder.h"
+*/
+
+#include "WavesPublicAPI/wstdint.h"
+#include "BasicTypes/WUDefines.h"
+
+// Stuff concerning little/big endian and the conversion between them.
+// most of the code here was copied from NetShell with some modifications
+// Written by Udi on Nov-2005
+// Adjusted to Cross platform by Shai Mar-2006
+
+// Macros to determine endian.  __BIG_ENDIAN__ & __LITTLE_ENDIAN__ should come from the compiler.
+// We try to set the macro _BYTEORDER_BIG_ENDIAN to 1 if big-endian or to 0 if little-endian.
+
+// if the compiler properly has set either __BIG_ENDIAN__ or __LITTLE_ENDIAN__
+#if defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__)
+#if defined(__BIG_ENDIAN__) && defined(__LITTLE_ENDIAN__) //if both defined, check them as booleans
+#if __BIG_ENDIAN__ && !__LITTLE_ENDIAN__
+#define _BYTEORDER_BIG_ENDIAN 1
+#elif !__BIG_ENDIAN__ && __LITTLE_ENDIAN__
+#define _BYTEORDER_BIG_ENDIAN 0
+#else
+#error I am confused. Is this big-endian or little-endian?
+#endif  // stupid compiler defines both __LITTLE_ENDIAN__ and __BIG_ENDIAN__
+#elif defined(__BIG_ENDIAN__)
+#define _BYTEORDER_BIG_ENDIAN 1
+#else
+#define _BYTEORDER_BIG_ENDIAN 0
+#endif // big/little switch
+#else // if the compiler proparly has NOT set either __BIG_ENDIAN__ or __LITTLE_ENDIAN__
+// http://msdn.microsoft.com/en-us/library/b0084kay.aspx for all preprocessor defs. _M_X64: 64 bit. _M_IA64: Itanium 64bit 
+#if defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(__INTEL__) || defined(__x86_64__) || defined(_M_X64) || defined(_M_IA64)
+#define _BYTEORDER_BIG_ENDIAN 0
+#elif defined(_M_PPC) || defined(__POWERPC__ ) || defined(__ppc__)
+#define _BYTEORDER_BIG_ENDIAN 1
+#else
+#error Cannot detect compiler byte-order. Please add a test for your compiler appropriate symbol to this header file.
+#endif // symbol search
+#endif // standard preprocessor symbol found
+
+// code to determine which assembly code we can use
+#if defined(_MSC_VER) && defined(_M_IX86)
+#define _BYTEORDER_ASM_MSVC_I386  1  // Windows
+#elif defined(__GNUC__) && defined(__i386__)
+#define _BYTEORDER_ASM_GNUC_I386  1  // Linux, or MacOS with MacIntel on Xcode
+#define _BYTEORDER_ASM_NONE              1      // Currently we have no assebley for GNU i386, so use the C version
+#elif defined(__GNUC__) && defined(__POWERPC__)
+#define _BYTEORDER_ASM_GNUC_PPC   1  // MacOS with PPC on Xcode
+#define _BYTEORDER_ASM_NONE              1      // Currently we have no assebley for GNU PPC, so use the C version
+#else
+#define _BYTEORDER_ASM_NONE       1  // don't know the compiler and processor, use C implementation
+#endif
+
+namespace wvNS {
+       
+namespace wvBO // namespace Waves::ByteOrder
+{
+    typedef int                byte_order_type;   // we use int rather than enum because some compilers cannot resolve enum constants at compile-time. There are only two options anyway :-)
+    static const       byte_order_type byte_order_little_endian = 0;
+    static const       byte_order_type byte_order_big_endian    = 1;
+
+
+    // We try to use this static const rather than preprocessor symbols in our code wherever possible.
+#if _BYTEORDER_BIG_ENDIAN == 1
+    static const       byte_order_type compiler_byte_order = byte_order_big_endian;
+#else 
+    static const       byte_order_type compiler_byte_order = byte_order_little_endian;
+#endif
+
+
+    //---------------------------------------------------------------------------------
+    // swap functions - best if implemented in inline assembly code
+    // The following are very slow swappers when compiled, do not use in loops
+#if _BYTEORDER_ASM_MSVC_I386
+
+    // assembly implementation for Intel386 on Visual Studio
+    inline uint16_t swap16(uint16_t x)
+    {
+        __asm MOV AX,x;
+        __asm XCHG AL,AH;
+        __asm MOV x,AX;
+        return x;
+    }
+
+    inline uint32_t swap32(uint32_t x)
+    {
+        __asm MOV EAX,x;
+        __asm BSWAP EAX;
+        __asm MOV x,EAX;
+        return x;
+    }
+    inline uint64_t swap64(uint64_t x)  // TODO: To be replaced
+    {   
+        return 
+            ((x>>7*8)&0xFF)<<0*8 | ((x>>6*8)&0xFF)<<1*8 | ((x>>5*8)&0xFF)<<2*8 | ((x>>4*8)&0xFF)<<3*8 |
+            ((x>>3*8)&0xFF)<<4*8 | ((x>>2*8)&0xFF)<<5*8 | ((x>>1*8)&0xFF)<<6*8 | ((x>>0*8)&0xFF)<<7*8 ;
+    }
+
+    /* the ASM code for swap64 does not compile
+    inline uint64_t swap64(uint64_t x)
+    {
+    __asm MOV EBX, OFFSET x;
+    __asm MOV EAX, [EBX];
+    __asm MOV EDX, [EBX+4];
+    __asm BSWAP EAX;
+    __asm BSWAP EDX;
+    __asm MOV [EBX],EDX;
+    __asm MOV [EBX+4],EAX;
+    return x;
+    }
+    */
+#endif // _BYTEORDER_ASM_MSVC_I386
+
+#if _BYTEORDER_ASM_GNUC_I386
+    // assembly implementation for Intel386 on GCC (Linux)
+    // TODO
+#endif // _BYTEORDER_ASM_GNUC_I386
+
+#if _BYTEORDER_ASM_GNUC_PPC
+    // assembly implementation for PowerPC on GCC (XCode)
+    // TODO
+#endif // _BYTEORDER_ASM_GNUC_PPC
+
+#if _BYTEORDER_ASM_NONE 
+    inline uint16_t swap16(uint16_t x) { return (x>>8) | ((x&0xFF)<<8); }
+    inline uint32_t swap32(uint32_t x) { return (x&0xFF)<<24 | (x&0xFF00)<<8 | (x&0xFF0000)>>8 | (x&0xFF000000)>>24; }
+    inline uint64_t swap64(uint64_t x)
+    {   
+        return 
+            ((x>>7*8)&0xFF)<<0*8 | ((x>>6*8)&0xFF)<<1*8 | ((x>>5*8)&0xFF)<<2*8 | ((x>>4*8)&0xFF)<<3*8 |
+            ((x>>3*8)&0xFF)<<4*8 | ((x>>2*8)&0xFF)<<5*8 | ((x>>1*8)&0xFF)<<6*8 | ((x>>0*8)&0xFF)<<7*8 ;
+    }
+#endif // _BYTEORDER_ASM_NONE
+
+
+
+
+    //---------------------------------------------------------------------------------
+
+    // order conversion functions
+    //    may want to overload for float and double as well. 
+    //    overload for signed ints is ambiguous and should be done only if no other choice exists.
+    // - - - - - - - - - - - - - - - - - - - -
+    inline uint16_t compiler_to_big_16(uint16_t x)
+    {
+        return compiler_byte_order==byte_order_big_endian ? x : swap16(x);
+    }
+    inline uint16_t big_to_compiler_16(uint16_t x)
+    {
+        return compiler_byte_order==byte_order_big_endian ? x : swap16(x);
+    }
+    inline uint16_t compiler_to_little_16(uint16_t x)
+    {
+        return compiler_byte_order==byte_order_little_endian ? x : swap16(x);
+    }
+    inline uint16_t little_to_compiler_16(uint16_t x)
+    {
+        return compiler_byte_order==byte_order_little_endian ? x : swap16(x);
+    }
+    // - - - - - - - - - - - - - - - - - - - -
+    inline uint32_t compiler_to_big_32(uint32_t x)
+    {
+        return compiler_byte_order==byte_order_big_endian ? x : swap32(x);
+    }
+    inline uint32_t big_to_compiler_32(uint32_t x)
+    {
+        return compiler_byte_order==byte_order_big_endian ? x : swap32(x);
+    }
+    inline uint32_t compiler_to_little_32(uint32_t x)
+    {
+        return compiler_byte_order==byte_order_little_endian ? x : swap32(x);
+    }
+    inline uint32_t little_to_compiler_32(uint32_t x)
+    {
+        return compiler_byte_order==byte_order_little_endian ? x : swap32(x);
+    }
+    // - - - - - - - - - - - - - - - - - - - -
+    inline uint64_t compiler_to_big_64(uint64_t x)
+    {
+        return compiler_byte_order==byte_order_big_endian ? x : swap64(x);
+    }
+    inline uint64_t big_to_compiler_64(uint64_t x)
+    {
+        return compiler_byte_order==byte_order_big_endian ? x : swap64(x);
+    }
+    inline uint64_t compiler_to_little_64(uint64_t x)
+    {
+        return compiler_byte_order==byte_order_little_endian ? x : swap64(x);
+    }
+    inline uint64_t little_to_compiler_64(uint64_t x)
+    {
+        return compiler_byte_order==byte_order_little_endian ? x : swap64(x);
+    }
+
+} // namespace wvBO
+
+} // namespace wvNS {
+
+#endif // #if !defined(__WTByteOrder_h__)
+
diff --git a/libs/backends/wavesaudio/wavesapi/BasicTypes/WUComPtr.h b/libs/backends/wavesaudio/wavesapi/BasicTypes/WUComPtr.h
new file mode 100644 (file)
index 0000000..6193da3
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __WUComPtr_h__
+#define __WUComPtr_h__
+       
+/* Copy to include
+#include "BasicTypes/WUComPtr.h"
+*/
+
+#include "WavesPublicAPI/wstdint.h"
+
+typedef int32_t wvComPtr[2]; 
+
+// ConvertDPtr has the exact format of a vfp callback function, but it is a local function, native only.
+// It converts a pointer in either 32 bits or 64 bits to a place-holder of 64 bits in coefs/states/external memory.
+// pData is expected to point to a pre-allocate space enough for storing a pointer (posibly two single-precision coefs).
+// Since pointers are not transferable between hardwares, at preset time no need for a shell callback.
+// We keep this as a cALGORITHM for compatibility with the rest of the convert functions
+//================================================================================
+inline uint32_t vfpConvertDPtr(const void* InPointer, void* pData)
+//================================================================================
+{      
+    uint64_t *pL = (uint64_t *)pData;
+    *pL = (uint64_t)InPointer;
+    return (uint32_t)sizeof(uint64_t);
+}
+
+
+/*
+{
+       // data in that struct must be the same type of the Coefs/States type!
+       int32_t LSW; // Least significant word
+       int32_t MSW; // Most  significant word
+};
+
+inline wvComPtr PackToComPtr(const intptr_t in_PtrToPack)
+// take ptr that hosted in intptr_t type
+// and pack it to wvComPtr container type (MSW and LSW of 32bit each)
+{
+       wvComPtr retVal;
+       int64_t t_PtrToPack = static_cast<int64_t>(in_PtrToPack);
+       // This packing is xPlatform coding for x32 and x64
+       // #ifdef for x64 - intptr_t is 64 bit
+       retVal.LSW = static_cast<int32_t>(t_PtrToPack & intptr_t(0xFFFFFFFF));
+       retVal.MSW = (static_cast<int32_t>(t_PtrToPack>>32));
+
+       // #ifdef for x32 - intptr_t is 32 bit
+//     retVal.LSW = int32_t(in_PtrToPack);
+//     retVal.MSW = 0;
+       
+       return retVal;
+}
+
+inline intptr_t UnpackComPtr( const wvComPtr in_ComPtrToUnpack)
+// take wvComPtr with MSW and LSW of 32bit each
+// and unpack it to intptr_t type
+{
+       intptr_t retVal;
+       
+       // This unpacking is xPlatform coding for x32 and x64
+       // #ifdef for x64 - intptr_t is 64 bit so use intptr_t instead of int64_t
+       int64_t PtrAt64 = static_cast<int64_t>(in_ComPtrToUnpack.MSW);
+       PtrAt64 <<= 32;
+       PtrAt64 |= static_cast<int64_t>(in_ComPtrToUnpack.LSW);
+       retVal = static_cast<intptr_t>(PtrAt64);
+
+
+       // #ifdef for x32 - intptr_t is 32 bit
+//     retVal = static_cast<intptr_t>(retVal.LSW);
+
+       return retVal;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+inline uint32_t  ComPtr_to_DSP( const intptr_t PtrToConvert, char* pDataStruct )
+{
+
+       *(reinterpret_cast<wvComPtr *>(pDataStruct)) = PackToComPtr(PtrToConvert);
+
+       return uint32_t(sizeof(wvComPtr));
+}
+//////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////
+inline uint32_t  DSP_to_ComPtr( const char* pDataStruct, intptr_t *ThePtr)
+// pDataStruct is pointing to wvComPtr in the Coefs/States
+// the function reconstruct the pointer into ThePtr 
+{
+
+       *ThePtr = UnpackComPtr(*(reinterpret_cast<const wvComPtr *>(pDataStruct)));
+
+       return uint32_t(sizeof(wvComPtr));
+}
+//////////////////////////////////////////////////////////////////////////
+*/
+
+#endif //#if !defined(__WUComPtr_h__)
+
+
+
diff --git a/libs/backends/wavesaudio/wavesapi/BasicTypes/WUDefines.h b/libs/backends/wavesaudio/wavesapi/BasicTypes/WUDefines.h
new file mode 100644 (file)
index 0000000..ea5c840
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __WUDefines_h__
+    #define __WUDefines_h__
+
+/*Copy to include
+#include "BasicTypes/WUDefines.h"
+*/
+
+#include "1.0/WavesPublicAPI_Defines.h"
+
+// When changing wvNS value also do the same change in Objective_C_MangledNames.h
+// because CWSAUCocoaViewFactoryAsString is hard coded there
+#define wvNS wvWavesV9_3 
+#ifdef __MACOS__
+    #define ObjCNameSpace(__className__) wvWavesV9_3_ ## __className__
+#endif
+
+#ifdef INSIDE_NETSHELL
+    #define DllExport
+#else
+    #define DllExport   WPAPI_DllExport 
+#endif
+
+#define __CDECL     __WPAPI_CDECL
+#define __STDCALL   __WPAPI_STDCALL
+
+
+#ifndef NULL
+    #define NULL (0)
+#endif
+
+#ifndef nil
+    #define nil NULL
+#endif
+
+#define PASCAL_MAC_ONLY #error do not use PASCAL_MAC_ONLY. See defintions in WavesFTT.h for replacment.
+#define CALLCON #error do not use CALLCON. See defintions in WavesFTT.h for replacment.
+#define FUNCEXP #error do not use FUNCEXP. See defintions in WavesFTT.h for replacment.
+
+#define WUNUSED_PARAM(__SOME_UNUSED_PARAM__) ((void)__SOME_UNUSED_PARAM__)
+
+#ifdef __MACOS__
+    const char* const  OS_NAME = "Mac";
+
+    #define WIN_ONLY(__Something_only_for_windows__)
+    #define MAC_ONLY(__Something_only_for_mac__) __Something_only_for_mac__
+    
+    #if defined(i386) || defined(__i386) || defined(__i386__)
+        #define kNumArchBits 32
+    #endif
+    #if defined(__x86_64) || defined(__x86_64__)
+        #define kNumArchBits 64
+    #endif 
+
+    #if (__i386 || __x86_64) && !defined(__LITTLE_ENDIAN__)
+        #define __LITTLE_ENDIAN__ 
+    #endif
+    #if !(__i386 || __x86_64) && !defined(__BIG_ENDIAN__)
+        #define __BIG_ENDIAN__
+    #endif
+    #ifdef __GNUC__
+        #define STD_EXCEPT_WIN std
+        #define FAR 
+        #define PASCAL 
+        // #define HINSTANCE void*
+        #define WINAPI
+    
+    #else
+    
+        #define DllExport_WinOnly
+        #define STD_EXCEPT_WIN std
+        #define FAR 
+        #define PASCAL          // windows' pascal
+        #define HINSTANCE void*
+        #define WINAPI
+
+    #endif
+    #define THROW_SPEC(THROW_OBJ) throw (THROW_OBJ)
+
+    #define WUNUSED_PARAM_ON_MAC(__SOME_UNUSED_PARAM__) WUNUSED_PARAM(__SOME_UNUSED_PARAM__)
+    #define WUNUSED_PARAM_ON_WIN(__SOME_UNUSED_PARAM__)
+#endif
+
+
+#ifdef _WINDOWS
+    const char* const  OS_NAME = "Win";
+
+    #define WIN_ONLY(__Something_only_for_windows__) __Something_only_for_windows__
+    #define MAC_ONLY(__Something_only_for_mac__)
+
+    #if defined(_M_X64)
+        #define kNumArchBits 64
+    #else // not sure what are the VisualStudio macros for 32 bits
+        #define kNumArchBits 32
+    #endif
+
+    #define DllExport_WinOnly DllExport     // help solve window specific link errors
+    #define STD_EXCEPT_WIN
+
+    #if !defined(__MINGW64__)
+               #define round(x) (floor(x+0.5))
+       #endif
+
+    #define __LITTLE_ENDIAN__
+    #define THROW_SPEC(THROW_OBJ) throw (...)
+
+    #define WUNUSED_PARAM_ON_MAC(__SOME_UNUSED_PARAM__)
+    #define WUNUSED_PARAM_ON_WIN(__SOME_UNUSED_PARAM__) WUNUSED_PARAM(__SOME_UNUSED_PARAM__)
+
+#endif 
+
+#ifdef __linux__
+    const char* const  OS_NAME = "Linux";
+
+    #define WIN_ONLY(__Something_only_for_windows__)
+    #define MAC_ONLY(__Something_only_for_mac__)
+
+    #define DllExport_WinOnly
+    #define STD_EXCEPT_WIN std
+    #define FAR 
+    #define PASCAL 
+    // #define HINSTANCE void*
+    #define WINAPI
+    #if __i386 && !defined(__LITTLE_ENDIAN__)
+        #define __LITTLE_ENDIAN__ 
+    #endif
+    #if !__i386 && !defined(__BIG_ENDIAN__)
+        #define __BIG_ENDIAN__
+    #endif
+    #define THROW_SPEC(THROW_OBJ) throw (THROW_OBJ)
+    
+    #if defined(__x86_64) || defined(__LP64__)
+        #error "64 bit not suported yet on linux"
+    #else
+        #define kNumArchBits 32
+    #endif
+#endif
+
+#ifndef _WU_DECL
+    #define _WU_DECL __CDECL // the default is calling model is cdecl, but you can also set this macro from the outside to something different 
+#endif
+
+#ifndef _XML_DECL
+    #define _XML_DECL __CDECL // the default is calling model is cdecl, but you can also set this macro from the outside to something different 
+#endif
+
+#ifndef kNumArchBits
+    #error Macro kNumArchBits was not defined
+#endif
+
+#if kNumArchBits == 64
+    const char* const kNumArchBits_c_str = "64";
+#endif
+#if kNumArchBits == 32
+    const char* const kNumArchBits_c_str = "32";
+#endif
+
+#endif //__WUDefines_h__
diff --git a/libs/backends/wavesaudio/wavesapi/BasicTypes/WUMathConsts.h b/libs/backends/wavesaudio/wavesapi/BasicTypes/WUMathConsts.h
new file mode 100644 (file)
index 0000000..6f51bfa
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __WUMathConsts_h__
+       #define __WUMathConsts_h__
+       
+/* Copy to include:
+#include "BasicTypes/WUMathConsts.h"
+*/
+
+const float kfPI =  3.1415926535898f; // PI, single precision
+const double kdPI = 3.1415926535897932384626433832795; // PI, double precision
+
+const float kf2PI =  6.2831853071796f; // 2*PI
+const double kd2PI = 6.283185307179586476925286766559; // 2*PI
+
+const float kfhalfPI =  1.5707963267949f; // 0.5*PI
+const double kdhalfPI = 1.57079632679489661923; // 0.5*PI
+
+const double kdLn2 = 0.69314718055994530942;   // natural log(2.0)
+const double kdOneOverLn2 = 1.4426950408889634073599246810019; // natural (1.0/log(2.0)) - for multiply log() to get it as with base 2
+
+const double kdLog2 = 0.301029995663981;       // log10(2.0)
+const double kdOneOverLog2 = 3.321928094887363;        // (1.0/log10(2.0)) - for multiply log() to get it as with base 2
+
+const double kdExponent = 2.718281828459045235360287471352; // e
+
+const double kdSqrt2 = 1.41421356237309504880; // sqrt(2)
+
+
+
+#endif //__WUMathConsts_h__
diff --git a/libs/backends/wavesaudio/wavesapi/BasicTypes/WUTypes.h b/libs/backends/wavesaudio/wavesapi/BasicTypes/WUTypes.h
new file mode 100644 (file)
index 0000000..c28547e
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __WUTypes_h__
+       #define __WUTypes_h__
+
+/* Copy to include:
+#include "BasicTypes/WUTypes.h"
+*/
+
+#include "WavesPublicAPI/WTErr.h"
+#include "WavesPublicAPI/wstdint.h"
+#include "BasicTypes/WUDefines.h"
+#include "BasicTypes/WCFourCC.h"       // declares WTFourCharCode & WCFourCC
+#include "BasicTypes/WUComPtr.h"       // Communication Ptr for x64 compatibility
+#include "WCFixedString.h"
+#include <ctime>
+#include <vector>
+/********************************************************************************
+    Atoms
+*********************************************************************************/
+
+#define WTSInt64    "WTSInt64 is obsolete, please use int64_t instead"; 
+#define WTUInt64    "WTUInt64 is obsolete, please use uint64_t instead"; 
+#define WTSInt32    "WTSInt32 is obsolete, please use int32_t instead"; 
+#define WTUInt32    "WTUInt32 is obsolete, please use uint32_t instead"; 
+#define WTSInt16    "WTSInt16 is obsolete, please use int16_t instead"; 
+#define WTUInt16    "WTUInt16 is obsolete, please use uint16_t instead"; 
+#define WTSInt8     "WTSInt8 is obsolete, please use int8_t instead"; 
+#define WTUInt8     "WTUInt8 is obsolete, please use uint8_t instead"; 
+#define WTFloat32   "WTFloat32 is obsolete, please use float instead"; 
+#define WTByte      "WTByte is obsolete, please use uint8_t instead"; 
+
+/********************************************************************************
+    Consts
+*********************************************************************************/
+//#define PI 3.1415926535897 // ... Was moved to WUMathConsts.h under the name kPI
+const uint32_t kDefaultCircleSlices = 100;
+
+
+/********************************************************************************
+    Utilities
+*********************************************************************************/
+
+// SCOPED_ENUM is a macro that defines an enum inside a class with a given name, thus declaring the enum values
+// inside a named scope. This allows declaring:
+//      SCOPED_ENUM(SomeType)
+//      {
+//          Val1,
+//          Val2,
+//          Val3
+//      }
+//      SCOPED_ENUM_END
+// And then you can reference SomeType::Val1, SomeType::Val2, SomeType::Val3 for the various values, unlike
+// a regular enum on which Val1, Val2 and Val3 would become global names.
+// Additionally, you get SomeType::Type to specify the type of the whole enum in case you want to transfer it to
+// a function.
+// Don't forget to close the enum with SCOPED_ENUM_END, otherwise you'll get bogus compilation errors.
+// This requirement can probably be removed some day, but it will make the SCOPED_ENUM macro much less readable...
+#define SCOPED_ENUM(name) \
+class name \
+{ \
+public: enum Type
+
+#define SCOPED_ENUM_END ;};
+
+
+//********************************************************************************
+//    Files
+
+//! file (and resource container) opening permissions                  
+// Note: When opening with eFMWriteOnly on existing file, writing to the file will append, not overwrite, Shai, 9/8/2007.
+enum   WEPermitions{ eFMReadOnly, eFMWriteOnly, eFMReadWrite};
+
+// File cursor positions
+enum   WEPositionMode{eFMFileBegin, eFMFileCurrent, eFMFileEnd};
+
+// File creation types
+enum   WECreateFlags {
+       eFMCreateFile_DontOverrideIfAlreadyExists,      // Create a new file , If the file exists leaves the existing data intact
+       eFMCreateFile_FailIfAlreadyExists,                      // Attempt to create a new file, if file already exists - fail.
+       eFMCreateFile_OverrideIfAlreadyExists       // Create a new file , If the file exists, overwrite the file and clear the existing data
+};
+
+
+enum WEFoldersDomain{
+       eSystemDomain,
+       eLocalDomain,
+       eUserDomain,
+
+       eNumberOfFoldersDomains
+};
+enum WEArchBits{
+    e32Bits,
+    e64Bits,
+    eNumberOfArchBits
+};
+
+enum WESystemFolders{
+       eSystemFolder,
+       eDesktopFolder,
+       ePreferencesFolder,
+       eWavesPreferencesFolder, //deprecated use eWavesPreferencesFolder2
+       eTemporaryFolder,
+       eTrashFolder,
+       eCurrentFolder,
+       eRootFolder,
+       eLibrariesFolder,
+       eAudioComponentsFolder, // MacOS only 
+       eCacheFolder,
+       eWavesCacheFolder,
+       eAppDataFolder,
+       eWavesAppDataFolder,
+       eSharedUserDataFolder,
+       eWavesSharedUserDataFolder,
+       eWavesScanViewFolder,
+
+       eWavesPreferencesFolder2, // Mac: "/Users/username/Library/Preferences/Waves Audio"
+                              // Win: "C:\Users\username\AppData\Roaming\Waves Audio\Preferences"
+               
+       eNumberOfSystemFolders
+};
+
+//********************************************************************************
+//    Process
+
+#ifdef __MACOS__
+       typedef uint32_t WTProcessID; // actually pid_t which is __darwin_pid_t which is __uint32_t
+#endif
+#ifdef _WINDOWS
+       typedef int             WTProcessID;
+#endif
+#ifdef __linux__
+       typedef uint32_t WTProcessID;
+#endif
+
+enum WEManagerInitOptions
+{
+    eUnknown_ManagerInitOption,
+    eMacOS_Carbon_Runtime,
+    eMacOS_Cocoa_Runtime,
+    eLinuxOS_gtk_Runtime,
+    eLinuxOS_X_Runtime,
+    eWindowsOS_GoodOld_Runtime,         // good old windows API
+    eWindowsOS_DotNET_Runtime,
+    eVerticalFliped_Graphics,
+    eInit_RM,
+    eInit_GMConfig,
+    eInit_PVM,
+    eInit_UM,
+    eInit_BKG
+};
+#ifdef __MACOS__
+    #if __LP64__ || NS_BUILD_32_LIKE_64        // in 64bit (or when NS_BUILD_32_LIKE_64 is specified) we decline Carbon implementation.
+        const WEManagerInitOptions eDefaultRuntime = eMacOS_Cocoa_Runtime;
+    #else
+        const WEManagerInitOptions eDefaultRuntime = eMacOS_Carbon_Runtime;
+    #endif
+#endif
+#ifdef _WINDOWS
+    const WEManagerInitOptions eDefaultRuntime = eWindowsOS_GoodOld_Runtime;
+#endif
+#ifdef __linux__
+    const WEManagerInitOptions eDefaultRuntime = eLinuxOS_gtk_Runtime;
+#endif
+
+
+//********************************************************************************
+//    Files
+
+const uint32_t kMaxPathLength = 1023;      // maximum length of a path 
+const uint32_t kMaxFileNameLength = 255;    // maximum length of a file name including extension
+typedef WCFixedString<kMaxPathLength> WTPathString;
+typedef WCFixedString<kMaxFileNameLength> WTFileNameString;
+
+typedef uint64_t WTFileSize;
+const WTFileSize kIllegalFileSize = (WTFileSize)-1;
+
+typedef off_t WTFileOffset;
+
+typedef std::time_t WTFileTime;
+const WTFileTime kIllegalFileTime = (WTFileTime)-1;
+
+typedef struct WTPathType* WTPathRef;                          // represents a path, path need not exists
+typedef struct WTOpenFileType* WTOpenFileRef;          // represents a real, open file
+typedef struct WTNativeDLLRefType* WTNativeDLLRef;     // define WTNativeDLLRef as a unique type CFBundleRef on Mac, HINSTANCE on Windows
+const WTNativeDLLRef kIllegalNativeDLLRef = 0;
+//********************************************************************************
+//    Resources
+
+const size_t kMaxResTypeLength = 31;
+typedef WCFixedString31 WTResType;
+typedef short      WTResID;
+const   WTResID     kIllegalResID = -1;
+
+
+typedef struct WTResContainerType*                     WTResContainerRef;
+typedef struct WTResourceType*                                 WTResRef;
+const WTResContainerRef kIllegalContainerRef = 0;
+const WTResRef kIllegalResourceRef = 0;
+
+#ifdef __MACOS__
+       typedef struct WTNativeResourceType*    WTNativeResourceRef;    // for use when need to have access to the native resource without going though resource manager caching anf conversion.
+    const WTNativeResourceRef          kIllegalNativeResourceRef = 0;
+#endif
+#ifdef _WINDOWS
+       typedef struct WTNativeResourceType*    WTNativeResourceRef; //HGLOBAL  // for use when need to have access to the native resource without going though resource manager caching anf conversion.
+    const WTNativeResourceRef          kIllegalNativeResourceRef = 0;
+#endif
+#ifdef __linux__
+typedef void*                                  WTNativeResourceRef;   // WTOpenFileRef // for use when need to have access to the native resource without going though resource manager caching anf conversion.
+    const WTNativeResourceRef          kIllegalNativeResourceRef = 0;
+#endif
+
+//********************************************************************************
+//    OpenGL
+
+typedef struct WCOGLContext*                   WCOGLContextRef;
+typedef struct WCOGLTexture*                   WCOGLTextureRef;
+typedef struct WSPluginView*            WCPluginViewRef;
+typedef struct WSMenu*                  WCMenuRef;
+typedef struct WCPluginNativeView*      WCPluginNativeViewRef;
+
+const WCOGLContextRef kIllegalOGLContextRef = 0;
+const WCOGLTextureRef kIllegalOGLTextureRef = 0;
+const WCPluginViewRef kIllegalPluginViewRef = 0;
+const WCMenuRef kIllegalWCMenuRef = 0;
+
+const intptr_t kIllegalTexturesMaster = -1;        
+
+
+typedef unsigned int WTTextureRef;
+const WTTextureRef kIllegalTextureRef = 0;
+
+// type for storing pointer to functions. Used to avoid warning such as "C++ forbids conversion between pointer to function and pointer to object"
+typedef void (*DUMMY_FUNC_PTR)(void);
+
+// type for a generic callback function with one parameter
+typedef intptr_t (*CALLBACK_1_PARAM_FUNC_PTR)(intptr_t);
+
+//////////////////////////////////////////////////////////////
+// Timer
+typedef intptr_t WTTimerRef;
+const WTTimerRef kIllegalTimerRef = 0;
+typedef void (*WTTimerCallback)(intptr_t);
+
+// generic type for OS native pointer
+typedef void* WTPtr;
+
+#endif //__WUTypes_h__
diff --git a/libs/backends/wavesaudio/wavesapi/akupara/basics.hpp b/libs/backends/wavesaudio/wavesapi/akupara/basics.hpp
new file mode 100644 (file)
index 0000000..a25e0dd
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  basics.hpp
+ *  Akupara
+ *
+ *  Created by Udi on 12/19/06.
+ *  Copyright 2006 __MyCompanyName__. All rights reserved.
+ *
+ */
+#if !defined(_AKUPARA_BASICS_HPP__INCLUDED_)
+#define _AKUPARA_BASICS_HPP__INCLUDED_
+
+#include "WavesPublicAPI/wstdint.h"
+
+namespace Akupara
+{
+       // The ultimate nothingness
+       // This is useful for writing constructors that nullify their object, and for testing nullness
+       struct null_type 
+       {
+               null_type() {}
+               null_type(const null_type *) {} // this allows 0 to be implicitly converted to null_type
+       };
+       inline null_type null() { return null_type(); }
+       
+
+       // This is a byte, guaranteed to be unsigned regardless of your compiler's char signedness
+       typedef uint8_t byte_type;
+
+
+       // derive from this if your class needs to be noncopyable
+       class noncopyable_type
+       {
+       private:
+               noncopyable_type(const noncopyable_type &);
+               noncopyable_type &operator=(const noncopyable_type &);
+       public:
+               noncopyable_type() {}
+       };
+
+
+} // namespace Akupara
+
+
+#if defined(__GNUC__)
+#define AKUPARA_EXPECT_FALSE(x) __builtin_expect(x,false)
+#define AKUPARA_EXPECT_TRUE(x)  __builtin_expect(x,true )
+#else
+#define AKUPARA_EXPECT_FALSE(x) x
+#define AKUPARA_EXPECT_TRUE(x)  x
+#endif // __GNUC__
+
+
+#endif // _AKUPARA_BASICS_HPP__INCLUDED_
diff --git a/libs/backends/wavesaudio/wavesapi/akupara/compiletime_functions.hpp b/libs/backends/wavesaudio/wavesapi/akupara/compiletime_functions.hpp
new file mode 100644 (file)
index 0000000..85eee8f
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+*  compiletime_functions.hpp
+*  Akupara
+*
+*  Created by Udi on 12/19/06.
+*
+*/
+#if !defined(_AKUPARA_COMPILETIME_FUNCTIONS_HPP__INCLUDED_)
+#define _AKUPARA_COMPILETIME_FUNCTIONS_HPP__INCLUDED_
+
+//#include "WavesPublicAPIs/wstdint.h"
+
+namespace Akupara
+{
+    // For templates that "return" a value, use template_name<arguments>::value
+    // For templates that "return" a type, use template_name<arguments>::type
+
+
+    // Integer log2 functions
+    //------------------------------------------------------------------------
+    template<unsigned int n> 
+    struct compiletime_bit_count_to_represent { static const unsigned int value = 1+compiletime_bit_count_to_represent<(n>>1)>::value; };
+
+    template<> 
+    struct compiletime_bit_count_to_represent<0> { static const unsigned int value = 0; };
+    //------------------------------------------------------------------------
+    template<unsigned int n> 
+    struct compiletime_log2_ceiling  { static const unsigned int value=compiletime_bit_count_to_represent<n-1>::value; };
+
+    template<> 
+    struct compiletime_log2_ceiling<0> {}; // no value for 0 argument
+    //------------------------------------------------------------------------
+    template<unsigned int n> 
+    struct compiletime_log2_floor { static const unsigned int value=compiletime_bit_count_to_represent<n>::value-1; };
+
+    template<> 
+    struct compiletime_log2_floor<0> {}; // no value for 0 argument
+    //------------------------------------------------------------------------
+
+
+
+    // Assertion - accessing 'value' will generate a compile-time error if the argument evaluates to false
+    //------------------------------------------------------------------------
+    template<bool> 
+    struct compiletime_assert;
+
+    template<>
+    struct compiletime_assert<true> { static const bool value=true; };
+
+    template<> 
+    struct compiletime_assert<false> {}; // no value member for false assertion -> compile time error
+    //------------------------------------------------------------------------
+
+
+    // Select type - selects one of two types based on a boolean
+    //------------------------------------------------------------------------
+    template<bool, typename, typename>
+    struct compiletime_select_type;
+
+    template<typename _true_type, typename _false_type>
+    struct compiletime_select_type<true,  _true_type, _false_type> { typedef _true_type  type; };
+
+    template<typename _true_type, typename _false_type> 
+    struct compiletime_select_type<false, _true_type, _false_type> { typedef _false_type type; };
+    //------------------------------------------------------------------------
+
+
+
+
+
+    // Integer types by byte count
+    //------------------------------------------------------------------------
+    namespace detail
+    {
+        template<unsigned int _size, bool _signed> 
+        struct integer_with_byte_count_base;
+
+        template<>
+        struct integer_with_byte_count_base<1,true> { typedef int8_t  type; };
+
+        template<>
+        struct integer_with_byte_count_base<2,true> { typedef int16_t type; };
+
+        template<>
+        struct integer_with_byte_count_base<4,true> { typedef int32_t type; };
+
+        template<>
+        struct integer_with_byte_count_base<8,true> { typedef int64_t type; };
+
+        template<>
+        struct integer_with_byte_count_base<1,false> { typedef uint8_t  type; };
+
+        template<>
+        struct integer_with_byte_count_base<2,false> { typedef uint16_t type; };
+
+        template<>
+        struct integer_with_byte_count_base<4,false> { typedef uint32_t type; };
+
+        template<>
+        struct integer_with_byte_count_base<8,false> { typedef uint64_t type; };
+    } // namespace detail
+    //------------------------------------------------------------------------
+    template<unsigned int _size, bool _signed=true>
+    struct integer_with_byte_count : public detail::integer_with_byte_count_base<_size,_signed>
+    {
+        typedef typename detail::integer_with_byte_count_base<_size,_signed>::type type; // not required but makes the statement below less messy
+        static const bool s_correct_size = compiletime_assert<sizeof(type)==_size>::value;  // if you get a compilation error here then integer_with_byte_count is not defined correctly
+    };
+    //------------------------------------------------------------------------
+    template<unsigned int _size>
+    struct signed_integer_with_byte_count : public integer_with_byte_count<_size,true> {};
+
+    template<unsigned int _size>
+    struct unsigned_integer_with_byte_count : public integer_with_byte_count<_size,false> {};
+    //------------------------------------------------------------------------
+
+
+
+    // The following are TR1 compatible, until we get decent TR1 library support on all platforms
+    //------------------------------------------------------------------------
+    template<typename _T, _T _v>
+    struct integral_constant
+    {
+        static const _T                    value = _v;
+        typedef _T                         value_type;
+        typedef integral_constant<_T, _v>  type;
+    }; // struct integral_constant
+    typedef integral_constant<bool, false> false_type;
+    typedef integral_constant<bool, true > true_type;
+    //------------------------------------------------------------------------
+    template<typename _T, typename _U> struct is_same : public false_type {};
+    template<typename _T> struct is_same<_T,_T> : public true_type {};
+    //------------------------------------------------------------------------
+
+
+
+    // These are NOT TR1 but make use of some TR1 stuff
+    //------------------------------------------------------------------------
+    namespace detail
+    {
+        struct no_type;   // if you end up getting this type, it means that you asked for something that doesn't exist
+        template<unsigned int _pair_index> struct signed_unsigned_pair;
+#define AKUPARA_SIGNED_UNSIGNED_INTEGER_PAIR(index, base_type_name) \
+    template<> struct signed_unsigned_pair<index> { typedef signed base_type_name signed_type; typedef unsigned base_type_name unsigned_type; };
+#define AKUPARA_SIGNED_UNSIGNED_FLOAT_PAIR(index, type_name) \
+    template<> struct signed_unsigned_pair<index> { typedef type_name signed_type; typedef no_type unsigned_type; };
+        AKUPARA_SIGNED_UNSIGNED_INTEGER_PAIR(1, char     )
+            AKUPARA_SIGNED_UNSIGNED_INTEGER_PAIR(2, short    )
+            AKUPARA_SIGNED_UNSIGNED_INTEGER_PAIR(3, int      )
+                       
+                       //AKUPARA_SIGNED_UNSIGNED_INTEGER_PAIR(4, int32_t     )// 64BitConversion
+                       template<> 
+                       struct 
+                       signed_unsigned_pair<4> 
+                       { 
+                               typedef int32_t signed_type; 
+                               typedef uint32_t  unsigned_type; 
+                       };
+            
+            
+                       AKUPARA_SIGNED_UNSIGNED_INTEGER_PAIR(5, long long)
+            AKUPARA_SIGNED_UNSIGNED_FLOAT_PAIR  (6, float      )
+            AKUPARA_SIGNED_UNSIGNED_FLOAT_PAIR  (7, double     )
+            AKUPARA_SIGNED_UNSIGNED_FLOAT_PAIR  (8, long double)
+            const unsigned int k_signed_unsigned_pair_count = 8;
+
+        // eliminate the no_type type
+        template<typename _T> struct filtered_type { typedef _T type; };
+        template<> struct filtered_type<no_type> {}; // no type defined
+
+        // search for _T in signed type list
+        template<unsigned int _index, typename _T> struct find_in_signed_type_list_from_index
+        {
+            static const unsigned int value = is_same< _T, typename signed_unsigned_pair<_index>::signed_type >::value ? _index : find_in_signed_type_list_from_index<_index-1,_T>::value;
+        };
+        template<typename _T> struct find_in_signed_type_list_from_index<0, _T> { static const unsigned int value = 0; };
+        template<typename _T> struct find_in_signed_type_list : public find_in_signed_type_list_from_index<k_signed_unsigned_pair_count, _T> {};
+
+        // search for _T in unsigned type list
+        template<unsigned int _index, typename _T> struct find_in_unsigned_type_list_from_index
+        {
+            static const unsigned int value = is_same< _T, typename signed_unsigned_pair<_index>::unsigned_type >::value ? _index : find_in_unsigned_type_list_from_index<_index-1,_T>::value;
+        };
+        template<typename _T> struct find_in_unsigned_type_list_from_index<0, _T> { static const unsigned int value = 0; };
+        template<typename _T> struct find_in_unsigned_type_list : public find_in_unsigned_type_list_from_index<k_signed_unsigned_pair_count, _T> {};
+
+        template<bool _is_signed, bool _is_unsigned, typename _T> struct equivalent_signed_type;
+        template<typename _T> struct equivalent_signed_type  <true, false, _T> { typedef _T type; };
+        template<typename _T> struct equivalent_signed_type  <false, true, _T> { typedef typename filtered_type< typename signed_unsigned_pair< find_in_unsigned_type_list<_T>::value >::signed_type >::type type; };
+
+        template<bool _is_signed, bool _is_unsigned, typename _T> struct equivalent_unsigned_type;
+        template<typename _T> struct equivalent_unsigned_type<true, false, _T> { typedef typename filtered_type< typename signed_unsigned_pair< find_in_signed_type_list<_T>::value >::unsigned_type >::type type; };
+        template<typename _T> struct equivalent_unsigned_type<false, true, _T> { typedef _T type; };
+    } // namespace detail
+    //------------------------------------------------------------------------
+    template<typename _T> struct is_signed   { static const bool value = detail::find_in_signed_type_list  <_T>::value != 0; };
+    template<typename _T> struct is_unsigned { static const bool value = detail::find_in_unsigned_type_list<_T>::value != 0; };
+    //------------------------------------------------------------------------
+    template<typename _T> struct equivalent_signed_type   : public detail::equivalent_signed_type  < is_signed<_T>::value, is_unsigned<_T>::value, _T > {};
+    template<typename _T> struct equivalent_unsigned_type : public detail::equivalent_unsigned_type< is_signed<_T>::value, is_unsigned<_T>::value, _T > {};
+    //------------------------------------------------------------------------
+
+} // namespace Akupara
+
+#endif // _AKUPARA_COMPILETIME_FUNCTIONS_HPP__INCLUDED_
diff --git a/libs/backends/wavesaudio/wavesapi/akupara/threading/atomic_ops.hpp b/libs/backends/wavesaudio/wavesapi/akupara/threading/atomic_ops.hpp
new file mode 100644 (file)
index 0000000..e87f548
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+*  Akupara/threading/atomic_ops.hpp
+*  
+*
+*  Created by Udi Barzilai on 06/06.
+*  Copyright 2006 __MyCompanyName__. All rights reserved.
+*
+*/
+#if !defined(_AKUPARA_THREADING_ATOMIC_OPS_HPP__INCLUDED_)
+#define _AKUPARA_THREADING_ATOMIC_OPS_HPP__INCLUDED_
+
+#include "Akupara/basics.hpp"  // for EXPECT macro
+#include "Akupara/compiletime_functions.hpp" // for TR1 stuff, signed/unsigned stuff
+
+namespace Akupara
+{
+    namespace threading
+    {
+        namespace atomic
+        {
+            namespace machine
+            {
+                // Machine capabilities
+                // The following templates are specialized by the machine-specific headers to indicate
+                // the capabilities of the machine being compiled for. A true 'value' member for a given
+                // byte count means that there is an implementation of the corresponding atomic operation.
+                //-------------------------------------
+                template<unsigned int _byte_count> struct implements_load          : public false_type {};  // simple assignment from memory (assumes naturally aligned address)
+                template<unsigned int _byte_count> struct implements_store         : public false_type {};  // simple assignment to memory (assumes naturally aligned address)
+                template<unsigned int _byte_count> struct implements_CAS           : public false_type {};  // compare_and_store()
+                template<unsigned int _byte_count> struct implements_LL_SC         : public false_type {};  // load_linked(), store_conditional()
+                template<unsigned int _byte_count> struct implements_add           : public false_type {};  // add(), subtract()
+                template<unsigned int _byte_count> struct implements_fetch_and_add : public false_type {};  // fetch_and_add(), fetch_and_subtract()
+                template<unsigned int _byte_count> struct implements_add_and_fetch : public false_type {};  // add_and_fetch(), subtract_and_fetch()
+                //-------------------------------------
+
+
+                //-------------------------------------
+                // functions in this namespace may or may not be implemented, for any integer types, as specified by the machine capabilities templates above
+                template<typename _integer_type> bool compare_and_store(volatile _integer_type * operand_address, const _integer_type & expected_value, const _integer_type & value_to_store);
+
+                template<typename _integer_type> _integer_type load_linked(volatile _integer_type * operand_address);
+                template<typename _integer_type> bool store_conditional(volatile _integer_type * operand_address, const _integer_type & value_to_store);
+
+                template<typename _integer_type> void add(volatile _integer_type * operand_address, const _integer_type & addend);
+                template<typename _integer_type> void subtract(volatile _integer_type * operand_address, const _integer_type & subtrahend);
+
+                template<typename _integer_type> _integer_type fetch_and_add(volatile _integer_type * operand_address, const _integer_type & addend);
+                template<typename _integer_type> _integer_type fetch_and_subtract(volatile _integer_type * operand_address, const _integer_type & subtrahend);
+
+                template<typename _integer_type> _integer_type add_and_fetch(volatile _integer_type * operand_address, const _integer_type & addend);
+                template<typename _integer_type> _integer_type subtract_and_fetch(volatile _integer_type * operand_address, const _integer_type & subtrahend);
+
+                void memory_barrier_read();
+                void memory_barrier_write();
+                void memory_barrier_readwrite();
+                //-------------------------------------
+
+            } // namespace machine
+        } // namespace atomic
+    } // namespace threading
+} // namespace Akupara
+
+// Include the machine-specific implementations; these only implement the templates above for some of the _signed_ integer types
+#if defined(__GNUC__) && defined(__POWERPC__)
+#include "atomic_ops_gcc_ppc.hpp"
+#endif // defined(__GNUC__) && defined(__POWERPC__)
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#include "atomic_ops_gcc_x86.hpp"
+#endif // defined(__GNUC__) && defined(__i386__)
+
+#if defined(_MSC_VER) && defined(_M_IX86)
+#include "atomic_ops_msvc_x86.hpp"
+#endif // defined(_MSC_VER) && defined(_M_IX86)
+
+#if defined(_MSC_VER) && defined(_M_X64)
+#include "atomic_ops_msvc_x86_64.hpp"
+#endif // defined(_MSC_VER) && defined(_M_X64)
+
+namespace Akupara
+{
+    namespace threading
+    {
+        namespace atomic
+        {
+
+
+            // Select the most convenient atomic integer type based on the machine's ability to load/store atomically
+            // The definition below selects that largest atomically accessible integer up to the size of int
+            //----------------------------------------------------------------------------------------
+            namespace detail
+            {
+                template<unsigned int _byte_count> 
+                struct largest_atomic_byte_count_upto 
+                { 
+                    static const unsigned int value = 
+                        machine::implements_load<_byte_count>::value && machine::implements_store<_byte_count>::value ? 
+_byte_count : 
+                    largest_atomic_byte_count_upto<_byte_count/2>::value; 
+                };
+
+                template<> 
+                struct largest_atomic_byte_count_upto<0> { static const unsigned int value = 0; };
+
+                const unsigned int k_byte_count_best_atomic = largest_atomic_byte_count_upto<sizeof(int)>::value;
+            }
+            typedef   signed_integer_with_byte_count< detail::k_byte_count_best_atomic >::type signed_integer_type;
+            typedef unsigned_integer_with_byte_count< detail::k_byte_count_best_atomic >::type unsigned_integer_type;
+            typedef signed_integer_type integer_type;
+            //----------------------------------------------------------------------------------------
+
+            //----------------------------------------------------------------------------------------
+            // These need to be implemented by all machines
+            using machine::memory_barrier_read;
+            using machine::memory_barrier_write;
+            using machine::memory_barrier_readwrite;
+            //----------------------------------------------------------------------------------------
+
+            //----------------------------------------------------------------------------------------
+            // These may or may not be implemented, but if they aren't, we can't help much
+            using machine::load_linked;
+            using machine::store_conditional;
+            //----------------------------------------------------------------------------------------
+
+
+            //----------------------------------------------------------------------------------------
+            // CAS implementation
+            namespace detail
+            {
+                template<
+                    typename _integer_type, 
+                    bool _implements_CAS   = machine::implements_CAS  <sizeof(_integer_type)>::value,
+                    bool _implements_LL_SC = machine::implements_LL_SC<sizeof(_integer_type)>::value>
+                struct implementation_CAS
+                {
+                    static const bool s_exists = false;
+                };
+                // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+                // specialization for native CAS support
+                template<typename _integer_type, bool _implements_LL_SC> 
+                struct implementation_CAS<_integer_type, true, _implements_LL_SC>
+                {
+                    static const bool s_exists = true;
+                    static inline bool compare_and_store(volatile _integer_type * operand_address, const _integer_type & expected_value, const _integer_type & value_to_store)
+                    {
+                        return machine::compare_and_store(operand_address, expected_value, value_to_store);
+                    }
+                };
+                // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+                // specialization for cases with no CAS but with LL/SC
+                template<typename _integer_type>
+                struct implementation_CAS<_integer_type, false, true>
+                {
+                    static const bool s_exists = true;
+                    static inline bool compare_and_store(volatile _integer_type * operand_address, const _integer_type & expected_value, const _integer_type & value_to_store)
+                    {
+                        while (machine::load_linked(operand_address) == expected_value)
+                            if (AKUPARA_EXPECT_TRUE(machine::store_conditional(operand_address, value_to_store)))
+                                return true;
+                        return false;
+                    }
+                };
+                // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+            } // namespace detail
+            // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+            template<typename _integer_type> 
+            inline bool compare_and_store(volatile _integer_type * operand_address, const _integer_type & expected_value, const _integer_type & value_to_store)
+            {
+                // if your compiler can't find the function to call here then there is no implementation available for your machine
+                return detail::implementation_CAS<_integer_type>::compare_and_store(operand_address, expected_value, value_to_store);
+            }
+            //----------------------------------------------------------------------------------------
+
+
+
+
+
+            //----------------------------------------------------------------------------------------
+            // fetch_and_add
+            namespace detail
+            {
+                template<
+                    typename _integer_type, 
+                    bool _0 = machine::implements_fetch_and_add<sizeof(_integer_type)>::value,
+                    bool _1 = machine::implements_add_and_fetch<sizeof(_integer_type)>::value,
+                    bool _2 = machine::implements_LL_SC        <sizeof(_integer_type)>::value,
+                    bool _3 = machine::implements_CAS          <sizeof(_integer_type)>::value>
+                struct implementation_FAA
+                {
+                    static const bool s_exists = false;
+                };
+                // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+                // specialization for native support
+                template<typename _integer_type, bool _1, bool _2, bool _3>
+                struct implementation_FAA<_integer_type, true, _1, _2, _3>
+                {
+                    static const bool s_exists = true;
+                    static inline _integer_type fetch_and_add(volatile _integer_type * operand_address, const _integer_type & addend)
+                    {
+                        return machine::fetch_and_add(operand_address, addend);
+                    }
+                };
+                // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+                // specialization using add_and_fetch
+                template<typename _integer_type, bool _2, bool _3>
+                struct implementation_FAA<_integer_type, false, true, _2, _3>
+                {
+                    static const bool s_exists = true;
+                    static inline _integer_type fetch_and_add(volatile _integer_type * operand_address, const _integer_type & addend)
+                    {
+                        return machine::add_and_fetch(operand_address, addend) - addend;
+                    }
+                };
+                // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+                // specialization using LL/SC
+                template<typename _integer_type, bool _3>
+                struct implementation_FAA<_integer_type, false, false, true, _3>
+                {
+                    static const bool s_exists = true;
+                    static inline _integer_type fetch_and_add(volatile _integer_type * operand_address, const _integer_type & addend)
+                    {
+                        _integer_type old_value;
+                        do
+                        old_value  = machine::load_linked(operand_address);
+                        while (!machine::store_conditional(operand_address, old_value+addend));
+                        return old_value;
+                    }
+                };
+                // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+                // specialization using CAS
+                template<typename _integer_type>
+                struct implementation_FAA<_integer_type, false, false, false, true>
+                {
+                    static const bool s_exists = true;
+                    static inline _integer_type fetch_and_add(volatile _integer_type * operand_address, const _integer_type & addend)
+                    {
+                        _integer_type old_value;
+                        do
+                        old_value  = *operand_address;
+                        while (!machine::compare_and_store(operand_address, old_value, old_value+addend));
+                        return old_value;
+                    }
+                };
+                // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+            } // namespace detail
+            template<typename _integer_type> 
+            inline _integer_type fetch_and_add(volatile _integer_type * operand_address, const _integer_type & addend)
+            {
+                // if your compiler can't find the function to call here then there is no implementation available for your machine
+                return detail::implementation_FAA<_integer_type>::fetch_and_add(operand_address, addend);
+            }
+            //----------------------------------------------------------------------------------------
+
+
+
+
+            //----------------------------------------------------------------------------------------
+            // add_and_fetch
+            namespace detail
+            {
+                template<
+                    typename _integer_type, 
+                    bool _0 = machine::implements_add_and_fetch<sizeof(_integer_type)>::value,
+                    bool _1 = machine::implements_fetch_and_add<sizeof(_integer_type)>::value,
+                    bool _2 = machine::implements_LL_SC        <sizeof(_integer_type)>::value,
+                    bool _3 = machine::implements_CAS          <sizeof(_integer_type)>::value>
+                struct implementation_AAF
+                {
+                    static const bool s_exists = false;
+                };
+                // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+                // specialization for native support
+                template<typename _integer_type, bool _1, bool _2, bool _3>
+                struct implementation_AAF<_integer_type, true, _1, _2, _3>
+                {
+                    static const bool s_exists = true;
+                    static inline _integer_type add_and_fetch(volatile _integer_type * operand_address, const _integer_type & addend)
+                    {
+                        return machine::add_and_fetch(operand_address, addend);
+                    }
+                };
+                // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+                // specialization using add_and_fetch
+                template<typename _integer_type, bool _2, bool _3>
+                struct implementation_AAF<_integer_type, false, true, _2, _3>
+                {
+                    static const bool s_exists = true;
+                    static inline _integer_type add_and_fetch(volatile _integer_type * operand_address, const _integer_type & addend)
+                    {
+                        return machine::fetch_and_add(operand_address, addend) + addend;
+                    }
+                };
+                // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+                // specialization using LL/SC
+                template<typename _integer_type, bool _3>
+                struct implementation_AAF<_integer_type, false, false, true, _3>
+                {
+                    static const bool s_exists = true;
+                    static inline _integer_type add_and_fetch(volatile _integer_type * operand_address, const _integer_type & addend)
+                    {
+                        _integer_type new_value;
+                        do
+                        new_value  = machine::load_linked(operand_address)+addend;
+                        while (!machine::store_conditional(operand_address, new_value));
+                        return new_value;
+                    }
+                };
+                // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+                // specialization using CAS
+                template<typename _integer_type>
+                struct implementation_AAF<_integer_type, false, false, false, true>
+                {
+                    static const bool s_exists = true;
+                    static inline _integer_type add_and_fetch(volatile _integer_type * operand_address, const _integer_type & addend)
+                    {
+                        _integer_type old_value, new_value;
+                        do
+                        old_value = *operand_address, new_value  = old_value + addend;
+                        while (!machine::compare_and_store(operand_address, old_value, new_value));
+                        return new_value;
+                    }
+                };
+                // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+            } // namespace detail
+            template<typename _integer_type> 
+            inline _integer_type add_and_fetch(volatile _integer_type * operand_address, const _integer_type & addend)
+            {
+                // if your compiler can't find the function to call here then there is no implementation available for your machine
+                return detail::implementation_AAF<_integer_type>::add_and_fetch(operand_address, addend);
+            }
+            //----------------------------------------------------------------------------------------
+
+
+
+            //----------------------------------------------------------------------------------------
+            // add
+            template<typename _integer_type> 
+            inline void add(volatile _integer_type * operand_address, const _integer_type & addend)
+            {
+                if (machine::implements_add<sizeof(_integer_type)>::value)
+                    machine::add(operand_address, addend);
+                else if (machine::implements_fetch_and_add<sizeof(_integer_type)>::value)
+                    machine::fetch_and_add(operand_address, addend);
+                else if (machine::implements_add_and_fetch<sizeof(_integer_type)>::value)
+                    machine::add_and_fetch(operand_address, addend);
+                else
+                    fetch_and_add(operand_address, addend); // this will simulate using CAS or LL/SC (or it will fail the compilation if neither is available)
+            }
+            //----------------------------------------------------------------------------------------
+
+
+
+            //----------------------------------------------------------------------------------------
+            // TODO: this is where we add implementations for:
+            // - functions not implemented by the machine
+            // - functions that take unsigned types (routed to call the signed versions with appropriate conversions)
+            // For now we add nothing, so developers will need to stick to what their machine can do, and use signed
+            // integers only.
+            using machine::subtract;
+            using machine::subtract_and_fetch;
+            using machine::fetch_and_subtract;
+            //----------------------------------------------------------------------------------------
+
+
+
+            //---------------------------------------------------------------------
+            template<class _base_type, unsigned int _bytes_per_cache_line=machine::k_bytes_per_cache_line>
+            struct pad_to_cache_line : public _base_type
+            {
+            private:
+                typedef pad_to_cache_line this_type;
+                typedef _base_type base_type;
+            public:
+                static const unsigned int s_bytes_per_cache_line = _bytes_per_cache_line;
+            private:
+                int m_padding[(s_bytes_per_cache_line - sizeof(base_type))/sizeof(int)];
+            public:
+                pad_to_cache_line() {}
+                template<typename _arg_type> pad_to_cache_line(_arg_type arg) : base_type(arg) {}
+            }; 
+            //---------------------------------------------------------------------
+
+        } // namespace atomic
+    } // namespace threading
+} // namespace Akupara
+
+#endif // _AKUPARA_THREADING_ATOMIC_OPS_HPP__INCLUDED_
diff --git a/libs/backends/wavesaudio/wavesapi/akupara/threading/atomic_ops_gcc_x86.hpp b/libs/backends/wavesaudio/wavesapi/akupara/threading/atomic_ops_gcc_x86.hpp
new file mode 100644 (file)
index 0000000..3039433
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ *  Akupara/threading/atomic_ops_gcc_x86.hpp
+ *  
+ *
+ *  Created by Udi Barzilai on 06/06.
+ *  Copyright 2006 __MyCompanyName__. All rights reserved.
+ *
+ */
+#if !defined(_AKUPARA_THREADING_ATOMIC_OPS_GCC_X86_HPP__INCLUDED_)
+#      define _AKUPARA_THREADING_ATOMIC_OPS_GCC_X86_HPP__INCLUDED_
+#      if defined(__GNUC__) && (defined(__i386__) ||  defined(__x86_64__))
+
+namespace Akupara
+{
+       namespace threading
+       {
+               namespace atomic
+               {
+                       namespace machine
+                       {
+                               const unsigned int k_bytes_per_cache_line = 64;  // this is true for P4 & K8
+       
+
+                               // Flags for operations supported by this machine
+                               //-------------------------------------
+                               template<> struct implements_load         <4> : public true_type {};
+                               template<> struct implements_store        <4> : public true_type {};
+                               template<> struct implements_CAS          <4> : public true_type {};
+                               template<> struct implements_CAS          <8> : public true_type {};
+                               template<> struct implements_add          <4> : public true_type {};
+                               template<> struct implements_fetch_and_add<4> : public true_type {};
+                               //-------------------------------------
+               
+
+
+                               // CAS
+                               //--------------------------------------------------------------------------------
+                               template<>
+                               inline bool compare_and_store<int64_t>(volatile int64_t * p, const int64_t & x, const int64_t & y)
+                               {
+                                       register int32_t evh=int32_t(x>>32), evl=int32_t(x);
+                                       register const int32_t nvh=int32_t(y>>32), nvl=int32_t(y);
+                                       register bool result;
+                                       __asm__ __volatile__ (
+                                                       "# CAS64\n"
+                                                       "       lock                       \n"
+                                                       "       cmpxchg8b %[location]  \n"
+                                                       "       sete %[result]         \n"
+                                                       : [location] "+m" (*p), [result] "=qm" (result), [expected_value_high] "+d" (evh), [expected_value_low] "+a" (evl)
+                                                       : [new_value_high] "c" (nvh), [new_value_low] "b" (nvl)
+                                                       : "cc"
+                                       );
+                                       return result;
+                               }
+                               //--------------------------------------------------------------------------------
+                               template<>
+                               inline bool compare_and_store<int32_t>(volatile int32_t *p, const int32_t & x, const int32_t & y)
+                               {
+                                       register int32_t expected_value = x;
+                                       register bool result;
+                                       __asm__ __volatile__ (
+                                                       "# CAS32\n"
+                                                       "       lock                             \n"
+                                                       "       cmpxchgl %[new_value],%[operand] \n"
+                                                       "       sete %[result]                   \n"
+                                                       : [operand] "+m" (*p), [result] "=qm" (result), [expected_value] "+a" (expected_value)
+                                                       : [new_value] "r" (y)
+                                                       : "cc"
+                                       );
+                                       return result;
+                               }
+                               //--------------------------------------------------------------------------------
+
+
+
+
+                               // Atomic add/sub
+                               //--------------------------------------------------------------------------------
+                               inline void increment(volatile int32_t * operand_address)
+                               {
+                                       __asm__ __volatile__ (
+                                       "# atomic_increment_32\n"
+                                       "       lock;             \n"
+                                       "       incl %[operand];  \n"
+                                       : [operand] "+m" (*operand_address)
+                                       :
+                                       : "cc"
+                                       );
+                               }
+                               //--------------------------------------------------------------------------------
+                               inline void decrement(volatile int32_t * operand_address)
+                               {
+                                       __asm__ __volatile__ (
+                                       "# atomic_decrement_32\n"
+                                       "       lock;             \n"
+                                       "       decl %[operand];  \n"
+                                       : [operand] "+m" (*operand_address)
+                                       :
+                                       : "cc"
+                                       );
+                               }
+                               //--------------------------------------------------------------------------------
+                               template<>
+                               inline void add<int32_t>(volatile int32_t * operand_address, const int32_t & addend)
+                               {
+                                       if (__builtin_constant_p(addend) && addend==1)
+                                               increment(operand_address);
+                                       else if (__builtin_constant_p(addend) && addend==-1)
+                                               decrement(operand_address);
+                                       else
+                                               __asm__ __volatile__ (
+                                               "# atomic_add_32               \n"
+                                               "       lock                       \n"
+                                               "       addl %[addend], %[operand] \n"
+                                               : [operand] "+m" (*operand_address)
+                                               : [addend] "ir" (addend)
+                                               : "cc"
+                                               );
+                               }
+                               //--------------------------------------------------------------------------------
+                               template<>
+                               inline void subtract<int32_t>(volatile int32_t * operand_address, const int32_t & subtrahend)
+                               {
+                                       if (__builtin_constant_p(subtrahend) && subtrahend==1)
+                                               decrement(operand_address);
+                                       else if (__builtin_constant_p(subtrahend) && subtrahend==-1)
+                                               increment(operand_address);
+                                       else
+                                               __asm__ __volatile__ (
+                                               "# atomic_subtract_32              \n"
+                                               "       lock                           \n"
+                                               "       subl %[subtrahend], %[operand] \n"
+                                               : [operand] "+m" (*operand_address)
+                                               : [subtrahend] "ir" (subtrahend)
+                                               : "cc"
+                                               );
+                               }
+                               //--------------------------------------------------------------------------------
+
+
+
+                               // Atomic fetch and add/sub
+                               //--------------------------------------------------------------------------------
+                               template<>
+                               inline int32_t fetch_and_add<int32_t>(volatile int32_t * operand_address, const int32_t & addend)
+                               {
+                                       register int32_t addend_and_fetched = addend;
+                                       __asm__ __volatile__ (
+                                       "# atomic_fetch_and_add_32       \n"
+                                       "       lock;                        \n"
+                                       "       xaddl %[addend], %[operand]; \n"
+                                       : [operand] "+m" (*operand_address), [addend] "+r" (addend_and_fetched)
+                                       :
+                                       : "cc"
+                                       );
+                                       return addend_and_fetched;
+                               }
+                               //--------------------------------------------------------------------------------
+                               template<>
+                               inline int32_t fetch_and_subtract<int32_t>(volatile int32_t * operand_address, const int32_t & subtrahend)
+                               {
+                                       return fetch_and_add(operand_address, -subtrahend);
+                               }
+                               //--------------------------------------------------------------------------------
+               
+
+
+                       
+                               // Memory barriers
+                               //--------------------------------------------------------------------------------
+                               inline void memory_barrier_readwrite()
+                               {
+                               #if _AKUPARA_X86_SSE_NOT_AVAILABLE
+                                       __asm__ __volatile__ (" lock; addl $0,0(%%esp); # memory_barrier_readwrite" : : : "memory");
+                               #else
+                                       __asm__ __volatile__ (" mfence;   # memory_barrier_readwrite" : : : "memory");
+                               #endif // _LOCKFREE_ATOMIC_OPS_X86_LFENCE_NOT_AVAILABLE
+                               }
+                               //--------------------------------------------------------------------------------
+                               inline void memory_barrier_read()
+                               {
+                               #if _AKUPARA_X86_SSE_NOT_AVAILABLE
+                                       __asm__ __volatile__ (" lock; addl $0,0(%%esp); # memory_barrier_read" : : : "memory");
+                               #else
+                                       __asm__ __volatile__ (" lfence;  # memory_barrier_read" : : : "memory");
+                               #endif // _LOCKFREE_ATOMIC_OPS_X86_LFENCE_NOT_AVAILABLE
+                               }
+                               //--------------------------------------------------------------------------------
+                               inline void memory_barrier_write()
+                               {
+                                       __asm__ __volatile__ (" sfence;  # memory_barrier_write" : : : "memory");
+                               }
+                               //--------------------------------------------------------------------------------
+
+                       } // namespace machine
+               } // namespace atomic
+       } // namespace threading
+} // namespace Akupara
+
+#      endif // defined(__GNUC__) && defined(__i386__)
+#endif // _AKUPARA_THREADING_ATOMIC_OPS_GCC_X86_HPP__INCLUDED_
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/IncludeWindows.h b/libs/backends/wavesaudio/wavesapi/devicemanager/IncludeWindows.h
new file mode 100644 (file)
index 0000000..5dd8f0e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __IncludeWindows_h__\r
+#define __IncludeWindows_h__\r
+\r
+#ifdef _WINDOWS\r
+\r
+/* Copy to include\r
+#include "IncludeWindows.h"\r
+*/\r
+\r
+#ifndef _WIN32_WINNT\r
+#define _WIN32_WINNT   0x0601   // Windows 7\r
+#endif\r
+\r
+#ifndef WINVER\r
+#define WINVER                 0x0601   // Windows 7\r
+#endif\r
+\r
+#ifndef WIN32_LEAN_AND_MEAN\r
+#define WIN32_LEAN_AND_MEAN\r
+#endif\r
+\r
+#ifndef NOMINMAX\r
+#define NOMINMAX // DO NOT REMOVE NOMINMAX - DOING SO CAUSES CONFLICTS WITH STD INCLUDES (<limits> ...)\r
+#endif\r
+\r
+#include <WinSock2.h>\r
+#include <Windows.h>\r
+#include <objbase.h>\r
+#endif // #if _WINDOWS \r
+#endif // #ifndef __IncludeWindows_h__\r
+\r
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.cpp b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.cpp
new file mode 100644 (file)
index 0000000..ae5ef3a
--- /dev/null
@@ -0,0 +1,743 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+//----------------------------------------------------------------------------------
+//
+//
+//! \file      WCMRAudioDeviceManager.cpp
+//!
+//! WCMRAudioDeviceManager and related class declarations
+//!
+//---------------------------------------------------------------------------------*/
+#include "WCMRAudioDeviceManager.h"
+
+
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::WCMRAudioDevice 
+//
+//! Constructor for the audio device. The derived classes will need to do more actual work, such
+//!            as determining supported sampling rates, buffer sizes, and channel counts. Connection
+//!            and streaming will also be provided by the derived implementations.
+//!
+//! \param *pManager : The audio device manager that's managing this device.
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+WCMRAudioDevice::WCMRAudioDevice (WCMRAudioDeviceManager *pManager)
+{
+       m_pMyManager = pManager;
+       m_DeviceName = "Unknown";
+
+       m_ConnectionStatus = DeviceDisconnected;
+       m_IsActive = false;
+       m_IsStreaming = false;
+       
+       m_CurrentSamplingRate = -1;
+       m_CurrentBufferSize = 0;
+       
+       m_LeftMonitorChannel = -1;
+       m_RightMonitorChannel = -1;
+       m_MonitorGain = 1.0f;
+       
+
+}
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::~WCMRAudioDevice 
+//
+//! Destructor for the audio device. It release all the connections that were created.
+//!
+//! \param none
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+WCMRAudioDevice::~WCMRAudioDevice ()
+{
+    AUTO_FUNC_DEBUG;
+       try 
+       {
+       }
+       catch (...)
+       {
+               //destructors should absorb exceptions, no harm in logging though!!
+               DEBUG_MSG ("Exception during destructor");
+       }
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::DeviceName 
+//
+//! Retrieves Device's name.
+//!
+//! \param none
+//! 
+//! \return The device name.
+//! 
+//**********************************************************************************************
+const std::string& WCMRAudioDevice::DeviceName () const
+{
+       return (m_DeviceName);
+       
+}
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::InputChannels 
+//
+//! Retrieves Input Channel information. Note that the list may be changed at run-time.
+//!
+//! \param none
+//! 
+//! \return A vector with Input Channel Names.
+//! 
+//**********************************************************************************************
+const std::vector<std::string>& WCMRAudioDevice::InputChannels ()
+{
+       return (m_InputChannels);
+       
+}
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::OutputChannels 
+//
+//! Retrieves Output Channel Information. Note that the list may be changed at run-time.
+//!
+//! \param none
+//! 
+//! \return A vector with Output Channel Names.
+//! 
+//**********************************************************************************************
+const std::vector<std::string>& WCMRAudioDevice::OutputChannels ()
+{
+       return (m_OutputChannels);
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::SamplingRates 
+//
+//! Retrieves supported sampling rate information.
+//!
+//! \param none
+//! 
+//! \return A vector with supported sampling rates.
+//! 
+//**********************************************************************************************
+const std::vector<int>& WCMRAudioDevice::SamplingRates ()
+{
+       return (m_SamplingRates);
+}
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::CurrentSamplingRate 
+//
+//! The device's current sampling rate. This may be overridden, if the device needs to 
+//!            query the driver for the current rate.
+//!
+//! \param none
+//! 
+//! \return The device's current sampling rate. -1 on error.
+//! 
+//**********************************************************************************************
+int WCMRAudioDevice::CurrentSamplingRate ()
+{
+       return (m_CurrentSamplingRate);
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::SetCurrentSamplingRate 
+//
+//! Change the sampling rate to be used by the device. This will most likely be overridden, 
+//!            the base class simply updates the member variable.
+//!
+//! \param newRate : The rate to use (samples per sec).
+//! 
+//! \return eNoErr always. The derived classes may return error codes.
+//! 
+//**********************************************************************************************
+WTErr WCMRAudioDevice::SetCurrentSamplingRate (int newRate)
+{
+       //changes the status.
+       m_CurrentSamplingRate = newRate;
+       return (eNoErr);
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::BufferSizes 
+//
+//! Retrieves supported buffer size information.
+//!
+//! \param none
+//! 
+//! \return A vector with supported buffer sizes.
+//! 
+//**********************************************************************************************
+const std::vector<int>& WCMRAudioDevice::BufferSizes ()
+{
+       return (m_BufferSizes);
+}
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::CurrentBufferSize
+//
+//! The device's current buffer size in use. This may be overridden, if the device needs to 
+//!            query the driver for the current size.
+//!
+//! \param none
+//! 
+//! \return The device's current buffer size. 0 on error.
+//! 
+//**********************************************************************************************
+int WCMRAudioDevice::CurrentBufferSize ()
+{
+       return (m_CurrentBufferSize);
+}
+
+//**********************************************************************************************
+// WCMRAudioDevice::CurrentBlockSize
+//
+//! Device's block size we use for holding the audio samples.
+//! Usually this is equal to the buffer size, but in some cases the buffer size holds additional
+//!   data other then the audio buffers, like frames info in SG, so it can be overriden
+//!
+//! \param none
+//! 
+//! \return The device's current block size. 0 on error.
+//! 
+//**********************************************************************************************
+int WCMRAudioDevice::CurrentBlockSize()
+{
+    // By default - return the buffer size
+    return CurrentBufferSize();
+}
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::SetCurrentBufferSize
+//
+//! Change the buffer size to be used by the device. This will most likely be overridden, 
+//!            the base class simply updates the member variable.
+//!
+//! \param newSize : The buffer size to use (in sample-frames)
+//! 
+//! \return eNoErr always. The derived classes may return error codes.
+//! 
+//**********************************************************************************************
+WTErr WCMRAudioDevice::SetCurrentBufferSize (int newSize)
+{
+       //This will most likely be overridden, the base class simply
+       //changes the member.
+       m_CurrentBufferSize = newSize;
+       return (eNoErr);
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::ConnectionStatus 
+//
+//! Retrieves the device's current connection status. This will most likely be overridden,
+//!            in case some driver communication is required to query the status.
+//!
+//! \param none
+//! 
+//! \return A ConnectionStates value.
+//! 
+//**********************************************************************************************
+WCMRAudioDevice::ConnectionStates WCMRAudioDevice::ConnectionStatus ()
+{
+       return (m_ConnectionStatus);
+       
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::Active 
+//
+//! Retrieves Device activation status.
+//!
+//! \param none
+//! 
+//! \return true if device is active, false otherwise.
+//! 
+//**********************************************************************************************
+bool WCMRAudioDevice::Active ()
+{
+       return (m_IsActive);
+       
+}
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::SetActive 
+//
+//! Sets the device's activation status.
+//!
+//! \param newState : Should be true to activate, false to deactivate. This roughly corresponds
+//!            to opening and closing the device handle/stream/audio unit.
+//! 
+//! \return eNoErr always, the derived classes may return appropriate error code.
+//! 
+//**********************************************************************************************
+WTErr WCMRAudioDevice::SetActive (bool newState)
+{
+       //This will most likely be overridden, the base class simply
+       //changes the member.
+       m_IsActive = newState;
+       return (eNoErr);
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::Streaming 
+//
+//! Retrieves Device streaming status.
+//!
+//! \param none
+//! 
+//! \return true if device is streaming, false otherwise.
+//! 
+//**********************************************************************************************
+bool WCMRAudioDevice::Streaming ()
+{
+       return (m_IsStreaming);
+}
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::SetStreaming
+//
+//! Sets the device's streaming status.
+//!
+//! \param newState : Should be true to start streaming, false to stop streaming. This roughly
+//!            corresponds to calling Start/Stop on the lower level interface.
+//! 
+//! \return eNoErr always, the derived classes may return appropriate error code.
+//! 
+//**********************************************************************************************
+WTErr WCMRAudioDevice::SetStreaming (bool newState)
+{
+       //This will most likely be overridden, the base class simply
+       //changes the member.
+       m_IsStreaming = newState;
+       return (eNoErr);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+// IsProcessActive - returns true if process code is running.
+// A normal audio device should return the Streaming() value
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+bool WCMRAudioDevice::IsProcessActive()
+{
+    return Streaming();
+}
+
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::DoIdle 
+//
+//! A place for doing idle time processing. The derived classes will probably do something
+//!            meaningful.
+//!
+//! \param none
+//! 
+//! \return eNoErr always.
+//! 
+//**********************************************************************************************
+WTErr WCMRAudioDevice::DoIdle ()
+{
+       //We don't need to do anything here...
+       //the derived classes may want to use this however.
+       return (eNoErr);
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::InputLevels 
+//
+//! Retrieve current input levels.
+//!
+//! \param none
+//! 
+//! \return A vector (the same size as input channels list) that contains current input levels.
+//! 
+//**********************************************************************************************
+const std::vector<float>& WCMRAudioDevice::InputLevels ()
+{
+       //The derived classes may override if they need to query
+       //the driver for the levels.
+       return (m_InputLevels);
+}
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::OutputLevels 
+//
+//! Retrieve current output levels.
+//!
+//! \param none
+//! 
+//! \return A vector (the same size as output channels list) that contains current output levels.
+//! 
+//**********************************************************************************************
+const std::vector<float>& WCMRAudioDevice::OutputLevels ()
+{
+       //The derived classes may override if they need to query
+       //the driver for the levels.
+       return (m_OutputLevels);
+}
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::GetMonitorInfo 
+//
+//! Retrieves current monitoring information.
+//!
+//! \param *pLeftChannel : Pointer to receive left monitor channel index.
+//! \param *pRightChannel : Pointer to receive right monitor channel index.
+//! \param *pGain : Pointer to receive the gain (linear) to be applied.
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+void WCMRAudioDevice::GetMonitorInfo (int *pLeftChannel, int *pRightChannel, float *pGain)
+{
+       if (pLeftChannel)
+               *pLeftChannel = m_LeftMonitorChannel;
+       if (pRightChannel)      
+               *pRightChannel = m_RightMonitorChannel;
+       if (pGain)      
+               *pGain = m_MonitorGain;
+       return; 
+}
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::SetMonitorChannels 
+//
+//! Used to set the channels to be used for monitoring.
+//!
+//! \param leftChannel : Left monitor channel index.
+//! \param rightChannel : Right monitor channel index.
+//! 
+//! \return eNoErr always, the derived classes may return appropriate errors.
+//! 
+//**********************************************************************************************
+WTErr WCMRAudioDevice::SetMonitorChannels (int leftChannel, int rightChannel)
+{
+       //This will most likely be overridden, the base class simply
+       //changes the member.
+       m_LeftMonitorChannel = leftChannel;
+       m_RightMonitorChannel = rightChannel;
+       return (eNoErr);
+}
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::SetMonitorGain 
+//
+//! Used to set monitor gain (or atten).
+//!
+//! \param newGain : The new gain or atten. value to use. Specified as a linear multiplier (not dB) 
+//! 
+//! \return eNoErr always, the derived classes may return appropriate errors.
+//! 
+//**********************************************************************************************
+WTErr WCMRAudioDevice::SetMonitorGain (float newGain)
+{
+       //This will most likely be overridden, the base class simply
+       //changes the member.
+       m_MonitorGain = newGain;
+       return (eNoErr);
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::ShowConfigPanel 
+//
+//! Used to show device specific config/control panel. Some interfaces may not support it.
+//!            Some interfaces may require the device to be active before it can display a panel.
+//!
+//! \param pParam : A device/interface specific parameter - optional.
+//! 
+//! \return eNoErr always, the derived classes may return errors.
+//! 
+//**********************************************************************************************
+WTErr WCMRAudioDevice::ShowConfigPanel (void *WCUNUSEDPARAM(pParam))
+{
+       //This will most likely be overridden...
+       return (eNoErr);
+}
+
+
+//**********************************************************************************************
+// WCMRAudioDevice::SendCustomCommand 
+//
+//! Used to Send a custom command to the audiodevice. Some interfaces may require the device 
+//!            to be active before it can do anything in this.
+//!
+//! \param customCommand : A device/interface specific command.
+//! \param pCommandParam : A device/interface/command specific parameter - optional.
+//! 
+//! \return eNoErr always, the derived classes may return errors.
+//! 
+//**********************************************************************************************
+WTErr WCMRAudioDevice::SendCustomCommand (int WCUNUSEDPARAM(customCommand), void *WCUNUSEDPARAM(pCommandParam))
+{
+       //This will most likely be overridden...
+       return (eNoErr);
+}
+
+//**********************************************************************************************
+// WCMRAudioDevice::GetLatency
+//
+//! Get Latency for device.
+//!
+//! Use 'kAudioDevicePropertyLatency' and 'kAudioDevicePropertySafetyOffset' + GetStreamLatencies
+//!
+//! \param isInput : Return latency for the input if isInput is true, otherwise the output latency
+//!                  wiil be returned.
+//! \return Latency in samples.
+//!
+//**********************************************************************************************
+uint32_t WCMRAudioDevice::GetLatency (bool isInput)
+{
+    //This will most likely be overridden...
+    return 0;
+}
+
+//**********************************************************************************************
+// WCMRAudioDeviceManager::WCMRAudioDeviceManager
+//
+//! The constructuor, most of the work will be done in the derived class' constructor.
+//!
+//! \param *pTheClient : 
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+WCMRAudioDeviceManager::WCMRAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter)
+       : m_pTheClient (pTheClient)
+       , m_eAudioDeviceFilter(eCurAudioDeviceFilter)
+{
+       //The derived classes will do lot more init!
+       return;
+}
+
+
+
+//**********************************************************************************************
+// WCMRAudioDeviceManager::~WCMRAudioDeviceManager
+//
+//! It clears the device list, releasing each of the device.
+//!
+//! \param none
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+WCMRAudioDeviceManager::~WCMRAudioDeviceManager()
+{
+    AUTO_FUNC_DEBUG;
+
+       try
+       {
+               //Need to call release on our devices, and erase them from list
+               std::vector<WCMRAudioDevice*>::iterator deviceIter;
+               while (m_Devices.size())
+               {
+                       WCMRAudioDevice *pDeviceToRelease = m_Devices.back();
+                       m_Devices.pop_back();
+                       if (pDeviceToRelease)
+                               SAFE_RELEASE (pDeviceToRelease);
+               }
+               
+               //The derived classes may want to do additional de-int!
+       }
+       catch (...)
+       {
+               //destructors should absorb exceptions, no harm in logging though!!
+               DEBUG_MSG ("Exception during destructor");
+       }
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDeviceManager::DoIdle_Private
+//
+//! Used for idle time processing. This calls each device's DoIdle so that it can perform it's own idle processing.
+//!
+//! \param none
+//! 
+//! \return noErr if no devices have returned an error. An error code if any of the devices returned error.
+//! 
+//**********************************************************************************************
+WTErr WCMRAudioDeviceManager::DoIdle_Private()
+{
+       WTErr retVal = eNoErr;
+       
+       //Need to call DoIdle of all our devices...
+       std::vector<WCMRAudioDevice*>::iterator deviceIter;
+       for (deviceIter = m_Devices.begin();  deviceIter != m_Devices.end(); deviceIter++)
+       {
+               WTErr thisDeviceErr = (*deviceIter)->DoIdle();
+               
+               if (thisDeviceErr != eNoErr)
+                       retVal = thisDeviceErr;
+       }
+       
+       return (retVal);
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDeviceManager::Devices_Private
+//
+//! Retrieve list of devices managed by this manager.
+//!
+//! \param none
+//! 
+//! \return A vector containing the list of devices.
+//! 
+//**********************************************************************************************
+const WCMRAudioDeviceList& WCMRAudioDeviceManager::Devices_Private() const
+{
+       return (m_Devices);
+}
+
+
+
+//**********************************************************************************************
+// *WCMRAudioDeviceManager::GetDeviceByName_Private
+//
+//! Locates a device based on device name.
+//!
+//! \param nameToMatch : Device to look for.
+//! 
+//! \return Pointer to the device object if found, NULL otherwise.
+//! 
+//**********************************************************************************************
+WCMRAudioDevice *WCMRAudioDeviceManager::GetDeviceByName_Private(const std::string& nameToMatch) const
+{
+       //Need to check all our devices...
+       WCMRAudioDevice *pRetVal = NULL;
+       
+       WCMRAudioDeviceListConstIter deviceIter;
+       for (deviceIter = m_Devices.begin();  deviceIter != m_Devices.end(); deviceIter++)
+       {
+               if ((*deviceIter)->DeviceName() == nameToMatch)
+               {
+                       pRetVal = *deviceIter;
+                       break;
+               }
+       }
+       
+       return (pRetVal);
+}
+
+//**********************************************************************************************
+// *WCMRAudioDeviceManager::GetDefaultDevice 
+//
+//! Locates a device based on device name.
+//! 
+//! \param nameToMatch : Device to look for.
+//! 
+//! \return Pointer to the device object if found, NULL otherwise.
+//! 
+//**********************************************************************************************
+WCMRAudioDevice *WCMRAudioDeviceManager::GetDefaultDevice_Private()
+{
+       //Need to check all our devices...
+       WCMRAudioDevice *pRetVal = NULL;
+       
+       WCMRAudioDeviceListIter deviceIter = m_Devices.begin();
+       if(deviceIter != m_Devices.end())
+       {
+               pRetVal = *deviceIter;
+       }
+       return (pRetVal);
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRAudioDeviceManager::NotifyClient 
+//
+//! A helper routine used to call the client for notification.
+//!
+//! \param forReason : The reason for notification.
+//! \param *pParam : A parameter (if required) for notification.
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+void WCMRAudioDeviceManager::NotifyClient (WCMRAudioDeviceManagerClient::NotificationReason forReason, void *pParam)
+{
+       if (m_pTheClient)
+               m_pTheClient->AudioDeviceManagerNotification (forReason, pParam);
+       return; 
+}
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.h b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.h
new file mode 100644 (file)
index 0000000..0d6aa55
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+//----------------------------------------------------------------------------------
+//
+//
+//! \file      WCMRAudioDeviceManager.h
+//!
+//! WCMRAudioDeviceManager and related class declarations
+//!
+//---------------------------------------------------------------------------------*/
+#ifndef __WCMRAudioDeviceManager_h_
+       #define __WCMRAudioDeviceManager_h_
+
+/* Copy to include
+#include "WCMRAudioDeviceManager.h"
+*/
+
+#define AUTO_FUNC_DEBUG
+#define DEBUG_MSG(a)
+#define ASSERT_ERROR(a, b)
+#define TRACE_MSG(a)
+
+#include <string>
+#include <vector>
+#include <map>
+#include "WCRefManager.h"
+#include "BasicTypes/WUTypes.h"
+#include "WUErrors.h"
+
+#define WCUNUSEDPARAM(a)
+
+//forward decl.
+class WCMRAudioConnection;
+class WCMRAudioDevice;
+class WCMRAudioDeviceManager;
+
+typedef std::vector<WCMRAudioDevice *> WCMRAudioDeviceList; ///< Vector for audio devices
+typedef std::vector<WCMRAudioDevice *>::iterator WCMRAudioDeviceListIter; ///< Vector iterator for audio devices
+typedef std::vector<WCMRAudioDevice *>::const_iterator WCMRAudioDeviceListConstIter; ///< Vector iterator for audio devices
+typedef std::vector<WCMRAudioConnection *> WCMRAudioConnectionsList; ///< Vector for audio devices
+
+
+/// for notification... A client must derive it's class from us.
+class WCMRAudioDeviceManagerClient
+{
+       public:
+       enum NotificationReason
+       {
+               DeviceListChanged,
+               Dropout,
+               RequestReset,
+               RequestResync,
+               SamplingRateChanged, //param has new SR, or -1 if not known
+        SamplingRateChangedSilent, //To indicate sampling rate changed but no need to notify user
+               BufferSizeChanged,
+               ClockSourceChanged,
+               DeviceStoppedStreaming,
+               DeviceDroppedSamples,
+               DeviceConnectionLost,
+               DeviceGenericError,
+               DeviceStatusChanged,
+               DeviceStatisticsUpdated,
+               DeviceDebugInfo, //param has c string
+               DeviceProgressInfo, //param has c string
+               MIDIData,
+               MIDINodeUp,
+               MIDINodeDown,
+               DeviceSampleRateMisMatch,
+               SystemSamplingRateChangedInfoOnly,
+               LostClockSource,
+               IODeviceDisconnected,
+               ChannelCountModified,
+               MasterUp,
+               MasterDown,
+               AudioDropFound,
+               ReflasherEvent,
+        AGDeviceSamplingRateChangedInfoOnly,
+               IODeviceNameChanged,
+        SetDisplayNameFromIOModule,
+        IOMStateChanged,    ///< This is used when IOM state is changed.
+        AudioCallback // VKamyshniy: param  is AudioCallbackDataData*
+       };
+
+       WCMRAudioDeviceManagerClient () {}
+       virtual ~WCMRAudioDeviceManagerClient () {}
+
+    // VKamyshniy: This is a structure to call the client's AudioDeviceManagerNotification
+    // every AudioCallback time
+    struct AudioCallbackData
+    {
+        const float *acdInputBuffer;
+        float *acdOutputBuffer;
+        size_t acdFrames;
+        uint32_t acdSampleTime;
+        uint64_t acdCycleStartTimeNanos;
+    };
+
+       virtual void AudioDeviceManagerNotification (NotificationReason WCUNUSEDPARAM(reason), void *WCUNUSEDPARAM(pParam)) {}
+};
+
+
+class WCMRAudioDevice : public WCRefManager
+{
+public:
+
+       enum ConnectionStates
+       {
+               DeviceAvailable,
+               DeviceDisconnected,
+               DeviceError
+       };
+
+       WCMRAudioDevice (WCMRAudioDeviceManager *pManager);///<Constructor
+       virtual ~WCMRAudioDevice ();///<Destructor
+
+       virtual const std::string& DeviceName() const;///<Name?
+       virtual const std::vector<std::string>& InputChannels();///<Current Input Channel List? - note that this may change with change in sampling rate.
+       virtual const std::vector<std::string>& OutputChannels();///<Current Output Channel List? - note that this may change with change in sampling rate.
+
+       virtual const std::vector<int>& SamplingRates();///<Supported Sampling Rate List?
+       virtual int CurrentSamplingRate(); ///<Current Sampling rate.?
+       virtual WTErr SetCurrentSamplingRate(int newRate);///<Change Current Sampling Rate : This is a requset, might not be successful at run time!
+
+       virtual const std::vector<int>& BufferSizes();///<Supported Buffer Size List? - note that this may change with change in sampling rate.
+       virtual int CurrentBufferSize();///<Current Buffer Size.? - note that this may change with change in sampling rate.
+       virtual WTErr SetCurrentBufferSize (int newSize);///<Change Current Buffer Size : This is a requset, might not be successful at run time!
+
+    virtual int CurrentBlockSize();
+
+       virtual ConnectionStates ConnectionStatus();///< Connection Status - device available, gone, disconnected
+
+       virtual bool Active();///<Active status - mainly significant for ASIO, as certain ops can only be performed on active devices!
+       virtual WTErr SetActive (bool newState);///<Prepare/Activate device.
+       
+       virtual bool Streaming();///<Streaming Status?
+       virtual WTErr SetStreaming (bool newState);///<Start/Stop Streaming - should reconnect connections when streaming starts!
+
+    virtual bool IsProcessActive();
+       
+       virtual WTErr DoIdle();///<Do Idle Processing
+       
+       virtual const std::vector<float>& InputLevels();///<Retrieve Input Levels (for VU display)?
+       
+       virtual const std::vector<float>& OutputLevels();///<Retrieve Output Levels (for VU display)?
+
+       void GetMonitorInfo (int *pLeftChannel = NULL, int *pRightChannel = NULL, float *pGain = NULL);///<Retrieve current monitor channel pair and gain - optional, will not be available with AG
+       virtual WTErr SetMonitorChannels (int leftChannel, int rightChannel);///<Set monitor channels. - optional, will not be available with AG
+       virtual WTErr SetMonitorGain (float newGain);///<Set monitor gain. - optional, will not be available with AG
+       
+       virtual WTErr ShowConfigPanel (void *pParam);///< Show Control Panel - in case of ASIO this will work only with Active device!
+       virtual WTErr SendCustomCommand (int customCommand, void *pCommandParam); ///< Send a custom command to the audiodevice...
+    
+    virtual uint32_t GetLatency (bool isInput); ///Get latency.
+    
+protected:
+       WCMRAudioDeviceManager *m_pMyManager; ///< The manager who's managing this device, can be used for sending notifications!
+       
+       std::string m_DeviceName; ///< Name of the device.
+       std::vector<std::string> m_InputChannels; ///< List of input channel names.
+       std::vector<std::string> m_OutputChannels; ///< List of output channel names.
+       std::vector<int> m_SamplingRates; ///< List of available sampling rates.
+       std::vector<int> m_BufferSizes; ///< List of available buffer sizes.
+       
+       int m_CurrentSamplingRate; ///< Currently selected sampling rate.
+       int m_CurrentBufferSize; ///< Currently selected buffer size.
+
+       ConnectionStates m_ConnectionStatus; ///< Status of device connection
+       bool m_IsActive; ///< Flag for teh active status.
+       bool m_IsStreaming; ///< Flag for streaming status.
+       std::vector<float> m_InputLevels; ///< List of input levels.
+       std::vector<float> m_OutputLevels; ///< List of output levels.
+       
+       int m_LeftMonitorChannel; ///< The device channel to use for monitoring left channel data.
+       int m_RightMonitorChannel; ///< The device channel to use for monitoring right channel data.
+       float m_MonitorGain; ///< Amount of gain to apply for monitoring signal.
+};
+
+// This enum is for choosing filter for audio devices scan
+typedef enum eAudioDeviceFilter
+{
+       eAllDevices = 0,        // Choose all audio devices
+       eInputOnlyDevices,      // Choose only input audio devices
+       eOutputOnlyDevices,     // Choose only output audio devices
+       eFullDuplexDevices,     // Choose audio devices that have both input and output channels on the same device
+       eMatchedDuplexDevices,  // Match(aggregate) audio devices that have both input and output channels but are considered different audio devices (For mac)
+       eAudioDeviceFilterNum   // Number of enums
+}      eAudioDeviceFilter;
+
+//! WCMRAudioDeviceManager
+/*! The Audio Device Manager class */
+class WCMRAudioDeviceManager : public WCRefManager
+{
+private://< Private version of class functions which will be called by class's public function after mutex lock acquistion.
+    WCMRAudioDevice* GetDefaultDevice_Private();
+    WTErr DoIdle_Private();
+    const WCMRAudioDeviceList& Devices_Private() const;        
+    WCMRAudioDevice* GetDeviceByName_Private(const std::string & nameToMatch) const;
+
+public://< Public functions for the class.
+    WCMRAudioDevice* GetDefaultDevice()
+    {
+               //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+        return GetDefaultDevice_Private();
+    }
+
+    virtual WTErr DoIdle()
+    {
+        //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+        return DoIdle_Private();
+    }
+
+    const WCMRAudioDeviceList& Devices() const
+    {
+        //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+        return Devices_Private();
+    }
+
+    WCMRAudioDevice* GetDeviceByName(const std::string & nameToMatch) const
+    {
+        //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+        return GetDeviceByName_Private(nameToMatch);
+    }
+
+public:
+       
+       WCMRAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter
+               ); ///< constructor
+       virtual ~WCMRAudioDeviceManager(void); ///< Destructor  
+    
+       virtual WTErr UpdateDeviceList () = 0; //has to be overridden!
+       
+       
+       //This is primarily for use by WCMRAudioDevice and it's descendants... We could have made it
+       //protected and made WCMRAudioDevice a friend, and then in some way found a way to extend 
+       //the friendship to WCMRAudioDevice's descendants, but that would require a lot of extra
+       //effort!
+       void NotifyClient (WCMRAudioDeviceManagerClient::NotificationReason forReason, void *pParam = NULL);
+    virtual void EnableVerboseLogging(bool /*bEnable*/, const std::string& /*logFilePath*/) { };
+
+protected:
+    
+    //< NOTE : Mutex protection is commented, but wrapper classes are still there, in case they are required in future.
+    //wvNS::wvThread::ThreadMutex   m_AudioDeviceManagerMutex;   ///< Mutex for Audio device manager class function access.
+       WCMRAudioDeviceManagerClient *m_pTheClient; ///< The device manager's client, used to send notifications.
+       
+       WCMRAudioDeviceList m_Devices; ///< List of all relevant devices devices
+       eAudioDeviceFilter m_eAudioDeviceFilter; // filter of 'm_Devices'
+};
+
+#endif //#ifndef __WCMRAudioDeviceManager_h_
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp
new file mode 100644 (file)
index 0000000..b66d251
--- /dev/null
@@ -0,0 +1,2717 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+//----------------------------------------------------------------------------------
+//
+//
+//! \file   WCMRCoreAudioDeviceManager.cpp
+//!
+//! WCMRCoreAudioDeviceManager and related class declarations
+//!
+//---------------------------------------------------------------------------------*/
+#include "WCMRCoreAudioDeviceManager.h"
+#include <CoreServices/CoreServices.h>
+#include "MiscUtils/safe_delete.h"
+#include <sstream>
+#include <syslog.h>
+
+// This flag is turned to 1, but it does not work with aggregated devices.
+// due to problems with aggregated devices this flag is not functional there
+#define ENABLE_DEVICE_CHANGE_LISTNER 1
+
+#define PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS 10
+#define PROPERTY_CHANGE_TIMEOUT_SECONDS 5 
+#define USE_IOCYCLE_TIMES 1 ///< Set this to 0 to use individual thread cpu measurement
+
+using namespace wvNS;
+///< Supported Sample rates
+static const double gAllSampleRates[] =
+{
+    44100.0, 48000.0, 88200.0, 96000.0, -1 /* negative terminated  list */
+};
+
+
+///< Default Supported Buffer Sizes.
+static const int gAllBufferSizes[] =
+{
+    32, 64, 96, 128, 192, 256, 512, 1024, 2048, -1 /* negative terminated  list */
+};
+    
+
+///< The default SR.
+static const int DEFAULT_SR = 44100;
+///< The default buffer size.
+static const int DEFAULT_BUFFERSIZE = 128;
+
+///< Number of stalls to wait before notifying user...
+static const int NUM_STALLS_FOR_NOTIFICATION = 2 * 50; // 2*50 corresponds to 2 * 50 x 42 ms idle timer - about 4 seconds.
+static const int CHANGE_CHECK_COUNTER_PERIOD = 100; // 120 corresponds to 120 x 42 ms idle timer - about 4 seconds.
+
+#define AUHAL_OUTPUT_ELEMENT 0  
+#define AUHAL_INPUT_ELEMENT 1
+
+#include <sys/sysctl.h>
+
+static int getProcessorCount() 
+{
+    int     count = 1;
+    size_t size = sizeof(count);
+
+    if (sysctlbyname("hw.ncpu", &count, &size, NULL, 0)) 
+        return 1;
+
+    //if something did not work, let's revert to a safe value...
+    if (count == 0)
+        count = 1;
+        
+    return count; 
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::WCMRCoreAudioDevice 
+//
+//! Constructor for the audio device. Opens the PA device and gets information about the device.
+//!     such as determining supported sampling rates, buffer sizes, and channel counts.
+//!
+//! \param *pManager : The audio device manager that's managing this device.
+//! \param deviceID : The port audio device ID.
+//! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true.
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+WCMRCoreAudioDevice::WCMRCoreAudioDevice (WCMRCoreAudioDeviceManager *pManager, AudioDeviceID deviceID, bool useMultithreading, bool bNocopy) 
+  : WCMRNativeAudioDevice (pManager, useMultithreading, bNocopy)
+  , m_SampleCountAtLastIdle (0)
+  , m_StalledSampleCounter(0)
+  , m_SampleCounter(0)
+  , m_BufferSizeChangeRequested (0)
+  , m_BufferSizeChangeReported (0)
+  , m_ResetRequested (0)
+  , m_ResetReported (0)
+  , m_ResyncRequested (0)
+  , m_ResyncReported (0)
+  , m_SRChangeRequested (0)
+  , m_SRChangeReported (0)
+  , m_ChangeCheckCounter(0)
+  , m_IOProcThreadPort (0)
+  , m_DropsDetected(0)
+  , m_DropsReported(0)
+  , m_IgnoreThisDrop(true)
+  , m_LastCPULog(0)
+#if WV_USE_TONE_GEN
+  , m_pToneData(0)
+  , m_ToneDataSamples (0)
+  , m_NextSampleToUse (0)
+#endif //WV_USE_TONE_GEN
+{
+    AUTO_FUNC_DEBUG;
+    UInt32 propSize = 0;
+    OSStatus err = kAudioHardwareNoError;
+
+    //Update device info...
+    m_DeviceID = deviceID;
+    
+    m_CurrentSamplingRate = DEFAULT_SR;
+    m_CurrentBufferSize = DEFAULT_BUFFERSIZE;
+    m_StopRequested = true;
+    m_pInputData = NULL;
+    
+    m_CPUCount = getProcessorCount();
+    m_LastCPULog = wvThread::now() - 10 * wvThread::ktdOneSecond;
+    
+    
+
+    /*
+      @constant       kAudioDevicePropertyNominalSampleRate
+      A Float64 that indicates the current nominal sample rate of the AudioDevice.
+    */
+    Float64 currentNominalRate;
+    propSize = sizeof (currentNominalRate);
+    err = kAudioHardwareNoError;
+    if (AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &currentNominalRate) != kAudioHardwareNoError)
+        err = AudioDeviceGetProperty(m_DeviceID, 0, 1, kAudioDevicePropertyNominalSampleRate, &propSize, &currentNominalRate);
+        
+    if (err == kAudioHardwareNoError)
+        m_CurrentSamplingRate = (int)currentNominalRate;
+        
+    /*
+      @constant       kAudioDevicePropertyBufferFrameSize
+      A UInt32 whose value indicates the number of frames in the IO buffers.
+    */
+
+    UInt32 bufferSize;
+    propSize = sizeof (bufferSize);
+    err = kAudioHardwareNoError;
+    if (AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyBufferFrameSize, &propSize, &bufferSize) != kAudioHardwareNoError)
+        err = AudioDeviceGetProperty(m_DeviceID, 0, 1, kAudioDevicePropertyBufferFrameSize, &propSize, &bufferSize);
+        
+    if (err == kAudioHardwareNoError)
+        m_CurrentBufferSize = (int)bufferSize;
+    
+    
+    UpdateDeviceInfo(true /*updateSRSupported*/, true /* updateBufferSizes */);
+
+    //should use a valid current SR...
+    if (m_SamplingRates.size())
+    {
+        //see if the current sr is present in the sr list, if not, use the first one!
+        std::vector<int>::iterator intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), m_CurrentSamplingRate);
+        if (intIter == m_SamplingRates.end())
+        {
+            //not found... use the first one
+            m_CurrentSamplingRate = m_SamplingRates[0];
+        }
+    }
+    
+    //should use a valid current buffer size
+    if (m_BufferSizes.size())
+    {
+        //see if the current sr is present in the buffersize list, if not, use the first one!
+        std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), m_CurrentBufferSize);
+        if (intIter == m_BufferSizes.end())
+        {
+            //not found... use the first one
+            m_CurrentBufferSize = m_BufferSizes[0];
+        }
+    }
+    
+    //build our input/output level lists
+    for (unsigned int currentChannel = 0; currentChannel < m_InputChannels.size(); currentChannel++)
+    {
+        m_InputLevels.push_back (0.0);
+    }
+
+    //build our input/output level lists
+    for (unsigned int currentChannel = 0; currentChannel < m_OutputChannels.size(); currentChannel++)
+    {
+        m_OutputLevels.push_back (0.0);
+    }
+    
+}
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::~WCMRCoreAudioDevice 
+//
+//! Destructor for the audio device. The base release all the connections that were created, if
+//!     they have not been already destroyed! Here we simply stop streaming, and close device
+//!     handles if necessary.
+//!
+//! \param none
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+WCMRCoreAudioDevice::~WCMRCoreAudioDevice ()
+{
+    AUTO_FUNC_DEBUG;
+
+    try
+    {
+        //If device is streaming, need to stop it!
+        if (Streaming())
+        {
+            SetStreaming (false);
+        }
+        
+        //If device is active (meaning stream is open) we need to close it.
+        if (Active())
+        {
+            SetActive (false);
+        }
+        
+    }
+    catch (...)
+    {
+        //destructors should absorb exceptions, no harm in logging though!!
+        DEBUG_MSG ("Exception during destructor");
+    }
+
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::UpdateDeviceInfo 
+//
+//! Updates Device Information about channels, sampling rates, buffer sizes.
+//!
+//! \param updateSRSupported : Is Sampling Rate support needs to be updated.
+//! \param updateBufferSizes : Is buffer size support needs to be updated.
+//! 
+//! \return WTErr.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::UpdateDeviceInfo (bool updateSRSupported, bool updateBufferSizes)
+{
+    AUTO_FUNC_DEBUG;
+    
+    WTErr retVal = eNoErr;  
+    
+    // Update all devices parts regardless of errors
+    WTErr errName = UpdateDeviceName();
+    WTErr errIn =   UpdateDeviceInputs();
+    WTErr errOut =  UpdateDeviceOutputs();
+    WTErr errSR =   eNoErr; 
+    WTErr errBS =   eNoErr; 
+    
+    if (updateSRSupported)
+    {
+        errSR = UpdateDeviceSampleRates();      
+    }
+    
+    //update SR list... This is done conditionally, because some devices may not like
+    //changing the SR later on, just to check on things.
+    if (updateBufferSizes)
+    {
+        errBS = UpdateDeviceBufferSizes();
+    }
+
+    if(errName != eNoErr || errIn != eNoErr || errOut != eNoErr || errSR != eNoErr || errBS != eNoErr)
+    {
+        retVal = eCoreAudioFailed;
+    }
+    
+    return retVal;  
+}
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::UpdateDeviceName 
+//
+//! Updates Device name.
+//!
+//! Use 'kAudioDevicePropertyDeviceName'
+//!
+//! 1. Get property name size.
+//! 2. Get property: name.
+//! 
+//! \return WTErr.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::UpdateDeviceName()
+{
+    AUTO_FUNC_DEBUG;
+    WTErr retVal = eNoErr;  
+    OSStatus err = kAudioHardwareNoError;
+    UInt32 propSize = 0;
+    
+    // Initiate name to unknown.
+    m_DeviceName = "Unknown";
+    
+    //! 1. Get property name size.
+    err = AudioDeviceGetPropertyInfo(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL);
+    if (err == kAudioHardwareNoError)
+    {
+        //! 2. Get property: name.
+        char* deviceName = new char[propSize];
+        err = AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceName, &propSize, deviceName);
+        if (err == kAudioHardwareNoError)
+        {
+            m_DeviceName = deviceName;
+        }
+        else
+        {
+            retVal = eCoreAudioFailed;
+            DEBUG_MSG("Failed to get device name. Device ID: " << m_DeviceID);
+        }
+        
+        delete [] deviceName;
+    }
+    else
+    {
+        retVal = eCoreAudioFailed;
+        DEBUG_MSG("Failed to get device name property size. Device ID: " << m_DeviceID);
+    }
+    
+    return retVal;
+}
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::UpdateDeviceInputs 
+//
+//! Updates Device Inputs.
+//!
+//! Use 'kAudioDevicePropertyStreamConfiguration'
+//! This property returns the stream configuration of the device in an
+//! AudioBufferList (with the buffer pointers set to NULL) which describes the
+//! list of streams and the number of channels in each stream. This corresponds
+//! to what will be passed into the IOProc.
+//!
+//! 1. Get property cannels input size.
+//! 2. Get property: cannels input.
+//! 3. Update input channels
+//! 
+//! \return WTErr.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::UpdateDeviceInputs()
+{
+    AUTO_FUNC_DEBUG;
+    WTErr retVal = eNoErr;  
+    OSStatus err = kAudioHardwareNoError;
+    UInt32 propSize = 0;
+    int maxInputChannels = 0;
+    
+    // 1. Get property cannels input size.
+    err = AudioDeviceGetPropertyInfo (m_DeviceID, 0, 1/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, NULL);
+    if (err == kAudioHardwareNoError)
+    {
+        //! 2. Get property: cannels input.
+
+        // Allocate size according to the property size. Note that this is a variable sized struct...
+        AudioBufferList *pStreamBuffers = (AudioBufferList *)malloc(propSize);
+        
+        if (pStreamBuffers)
+        {
+            memset (pStreamBuffers, 0, propSize);
+        
+            // Get the Input channels
+            err = AudioDeviceGetProperty (m_DeviceID, 0, 1/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers);
+            if (err == kAudioHardwareNoError)
+            {
+                // Calculate the number of input channels
+                for (UInt32 streamIndex = 0; streamIndex < pStreamBuffers->mNumberBuffers; streamIndex++)
+                {
+                    maxInputChannels += pStreamBuffers->mBuffers[streamIndex].mNumberChannels;
+                }
+            }
+            else
+            {
+                retVal = eCoreAudioFailed;
+                DEBUG_MSG("Failed to get device Input channels. Device Name: " << m_DeviceName.c_str());
+            }
+            
+            free (pStreamBuffers);
+        }
+        else
+        {
+            retVal = eMemOutOfMemory;
+            DEBUG_MSG("Faild to allocate memory. Device Name: " << m_DeviceName.c_str());
+        }
+    }
+    else
+    {
+        retVal = eCoreAudioFailed;
+        DEBUG_MSG("Failed to get device Input channels property size. Device Name: " << m_DeviceName.c_str());
+    }
+    
+    // Update input channels
+    m_InputChannels.clear();
+    for (int channel = 0; channel < maxInputChannels; channel++)
+    {
+        std::stringstream chNameStream;
+        //A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
+        chNameStream << "Input " << (channel+1);
+        m_InputChannels.push_back (chNameStream.str());
+    }
+    
+    return retVal;
+}
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::UpdateDeviceOutputs 
+//
+//! Updates Device Outputs.
+//!
+//! Use 'kAudioDevicePropertyStreamConfiguration'
+//! This property returns the stream configuration of the device in an
+//! AudioBufferList (with the buffer pointers set to NULL) which describes the
+//! list of streams and the number of channels in each stream. This corresponds
+//! to what will be passed into the IOProc.
+//!
+//! 1. Get property cannels output size.
+//! 2. Get property: cannels output.
+//! 3. Update output channels
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::UpdateDeviceOutputs()
+{
+    AUTO_FUNC_DEBUG;
+    
+    WTErr retVal = eNoErr;  
+    OSStatus err = kAudioHardwareNoError;
+    UInt32 propSize = 0;
+    int maxOutputChannels = 0;
+    
+    //! 1. Get property cannels output size.
+    err = AudioDeviceGetPropertyInfo (m_DeviceID, 0, 0/* Output */, kAudioDevicePropertyStreamConfiguration, &propSize, NULL);
+    if (err == kAudioHardwareNoError)
+    {
+        //! 2. Get property: cannels output.
+        
+        // Allocate size according to the property size. Note that this is a variable sized struct...
+        AudioBufferList *pStreamBuffers = (AudioBufferList *)malloc(propSize);
+        if (pStreamBuffers)
+        {
+            memset (pStreamBuffers, 0, propSize);
+        
+            // Get the Output channels
+            err = AudioDeviceGetProperty (m_DeviceID, 0, 0/* Output */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers);
+            if (err == kAudioHardwareNoError)
+            {
+                // Calculate the number of output channels
+                for (UInt32 streamIndex = 0; streamIndex < pStreamBuffers->mNumberBuffers; streamIndex++)
+                {
+                    maxOutputChannels += pStreamBuffers->mBuffers[streamIndex].mNumberChannels;
+                }
+            }
+            else
+            {
+                retVal = eCoreAudioFailed;
+                DEBUG_MSG("Failed to get device Output channels. Device Name: " << m_DeviceName.c_str());
+            }
+            free (pStreamBuffers);
+        }
+        else
+        {
+            retVal = eMemOutOfMemory;
+            DEBUG_MSG("Faild to allocate memory. Device Name: " << m_DeviceName.c_str());
+        }
+    }
+    else
+    {
+        retVal = eCoreAudioFailed;
+        DEBUG_MSG("Failed to get device Output channels property size. Device Name: " << m_DeviceName.c_str());
+    }
+    
+    // Update output channels
+    m_OutputChannels.clear();
+    for (int channel = 0; channel < maxOutputChannels; channel++)
+    {
+        std::stringstream chNameStream;
+        //A better implementation would be to retrieve the names from ASIO or CoreAudio interfaces
+        chNameStream << "Output " << (channel+1);
+        m_OutputChannels.push_back (chNameStream.str());
+    }
+    
+    return retVal;
+}
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::UpdateDeviceSampleRates 
+//
+//! Updates Device Sample rates.
+//!
+//! Use 'kAudioDevicePropertyAvailableNominalSampleRates'
+//!
+//! 1. Get sample rate property size.
+//! 2. Get property: sample rates.
+//! 3. Update sample rates
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::UpdateDeviceSampleRates()
+{
+    AUTO_FUNC_DEBUG;
+    
+    WTErr retVal = eNoErr;  
+    OSStatus err = kAudioHardwareNoError;
+    UInt32 propSize = 0;
+    
+    m_SamplingRates.clear();
+    
+    //! 1. Get sample rate property size.
+    err = AudioDeviceGetPropertyInfo(m_DeviceID, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, NULL);
+    if (err == kAudioHardwareNoError)
+    {
+        //! 2. Get property: cannels output.
+        
+        // Allocate size accrding to the number of audio values
+        int numRates = propSize / sizeof(AudioValueRange);
+        AudioValueRange* supportedRates = new AudioValueRange[numRates];
+        
+        // Get sampling rates from Audio device
+        err = AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, supportedRates);
+        if (err == kAudioHardwareNoError)
+        {
+            //! 3. Update sample rates
+            
+            // now iterate through our standard SRs
+            for(int ourSR=0; gAllSampleRates[ourSR] > 0; ourSR++)
+            {
+                //check to see if our SR is in the supported rates...
+                for (int deviceSR = 0; deviceSR < numRates; deviceSR++)
+                {
+                    if ((supportedRates[deviceSR].mMinimum <= gAllSampleRates[ourSR]) && 
+                        (supportedRates[deviceSR].mMaximum >= gAllSampleRates[ourSR]))
+                    {
+                        m_SamplingRates.push_back ((int)gAllSampleRates[ourSR]);
+                        break;
+                    }
+                }
+            }
+        }
+        else
+        {
+            retVal = eCoreAudioFailed;
+            DEBUG_MSG("Failed to get device Sample rates. Device Name: " << m_DeviceName.c_str());
+        }
+        
+        delete [] supportedRates;
+    }
+    else
+    {
+        retVal = eCoreAudioFailed;
+        DEBUG_MSG("Failed to get device Sample rates property size. Device Name: " << m_DeviceName.c_str());
+    }
+    
+    return retVal;
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::UpdateDeviceBufferSizes_Simple 
+//
+// Use kAudioDevicePropertyBufferFrameSizeRange
+//
+// in case of 'eMatchedDuplexDevices' and a matching device exists return common device name
+// in all other cases retur base class function implementation
+//
+// 1. Get buffer size range
+// 2. Run on all ranges and add them to the list
+// 
+// \return error code
+// 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::UpdateDeviceBufferSizes ()
+{
+    AUTO_FUNC_DEBUG;
+    
+    WTErr retVal = eNoErr;
+    OSStatus err = kAudioHardwareNoError;
+    UInt32 propSize = 0;
+    
+    // Clear buffer sizes
+    m_BufferSizes.clear();
+    
+    // 1. Get buffer size range
+    AudioValueRange bufferSizesRange;
+    propSize = sizeof (AudioValueRange);
+    err = AudioDeviceGetProperty (m_DeviceID, 0, 0, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &bufferSizesRange);
+    if(err == kAudioHardwareNoError)
+    {
+        // 2. Run on all ranges and add them to the list
+        for(int bsize=0; gAllBufferSizes[bsize] > 0; bsize++)
+        {
+            if ((bufferSizesRange.mMinimum <= gAllBufferSizes[bsize]) && (bufferSizesRange.mMaximum >= gAllBufferSizes[bsize]))
+            {
+                m_BufferSizes.push_back (gAllBufferSizes[bsize]);
+            }
+        }
+        
+        //if we didn't get a single hit, let's simply add the min. and the max...
+        if (m_BufferSizes.empty())
+        {
+            m_BufferSizes.push_back ((int)bufferSizesRange.mMinimum);
+            m_BufferSizes.push_back ((int)bufferSizesRange.mMaximum);
+        }
+    }
+    else
+    {
+        retVal = eCoreAudioFailed;
+        DEBUG_MSG("Failed to get device buffer sizes range. Device Name: " << m_DeviceName.c_str());
+    }
+    
+    return retVal;
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::DeviceName 
+//
+//! in case of 'eMatchedDuplexDevices' and a matching device exists return common device name
+//! in all other cases retur base class function implementation
+//!
+//! \param none
+//! 
+//! \return current device name
+//! 
+//**********************************************************************************************
+const std::string& WCMRCoreAudioDevice::DeviceName() const
+{
+    return WCMRAudioDevice::DeviceName();
+}
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::InputChannels 
+//
+//! return base class function implementation
+//!
+//! \param none
+//! 
+//! \return base class function implementation
+//! 
+//**********************************************************************************************
+const std::vector<std::string>& WCMRCoreAudioDevice::InputChannels()
+{
+    return WCMRAudioDevice::InputChannels();
+}
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::OutputChannels 
+//
+//! in case of 'eMatchedDuplexDevices' return matching device output channel if there is one
+//! in all other cases retur base class function implementation
+//!
+//! \param none
+//! 
+//! \return list of output channels of current device
+//! 
+//**********************************************************************************************
+const std::vector<std::string>& WCMRCoreAudioDevice::OutputChannels()
+{
+    return WCMRAudioDevice::OutputChannels();
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::SamplingRates 
+//
+//! in case of 'eMatchedDuplexDevices' and a matching device exists return common sample rate
+//! in all other cases retur base class function implementation
+//!
+//! \param none
+//! 
+//! \return current sample rate
+//! 
+//**********************************************************************************************
+const std::vector<int>& WCMRCoreAudioDevice::SamplingRates()
+{
+    return WCMRAudioDevice::SamplingRates();
+}
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::CurrentSamplingRate 
+//
+//! The device's current sampling rate. This may be overridden, if the device needs to 
+//!     query the driver for the current rate.
+//!
+//! \param none
+//! 
+//! \return The device's current sampling rate. -1 on error.
+//! 
+//**********************************************************************************************
+int WCMRCoreAudioDevice::CurrentSamplingRate ()
+{
+    AUTO_FUNC_DEBUG;
+    //ToDo: Perhaps for ASIO devices that are active, we should retrive the SR from the device...
+    UInt32 propSize = 0;
+    OSStatus err = kAudioHardwareNoError;
+
+    Float64 currentNominalRate;
+    propSize = sizeof (currentNominalRate);
+    err = kAudioHardwareNoError;
+    if (AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &currentNominalRate) != kAudioHardwareNoError)
+        err = AudioDeviceGetProperty(m_DeviceID, 0, 1, kAudioDevicePropertyNominalSampleRate, &propSize, &currentNominalRate);
+        
+    if (err == kAudioHardwareNoError)
+        m_CurrentSamplingRate = (int)currentNominalRate;
+    else
+    {
+        DEBUG_MSG("Unable to get sampling rate!");
+    }
+
+    return (m_CurrentSamplingRate);
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::SetCurrentSamplingRate 
+//
+//! Change the sampling rate to be used by the device. 
+//!
+//! \param newRate : The rate to use (samples per sec).
+//! 
+//! \return eNoErr always. The derived classes may return error codes.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::SetCurrentSamplingRate (int newRate)
+{
+    AUTO_FUNC_DEBUG;
+    std::vector<int>::iterator intIter;
+    WTErr retVal = eNoErr;
+
+    //changes the status.
+    int oldRate = CurrentSamplingRate();
+    bool oldActive = Active();
+    
+    //no change, nothing to do
+    if (oldRate == newRate)
+        goto Exit;
+
+    //see if this is one of our supported rates...
+    intIter = find(m_SamplingRates.begin(), m_SamplingRates.end(), newRate);
+    if (intIter == m_SamplingRates.end())
+    {
+        //Can't change, perhaps use an "invalid param" type of error
+        retVal = eCommandLineParameter;
+        goto Exit;
+    }
+    
+    if (Streaming())
+    {
+        //Can't change, perhaps use an "in use" type of error
+        retVal = eGenericErr;
+        goto Exit;
+    }
+
+    if (oldActive)
+    {
+        //Deactivate it for the change...
+        SetActive (false);
+    }
+    
+    retVal = SetAndCheckCurrentSamplingRate (newRate);
+    if(retVal == eNoErr)
+    {
+        retVal = UpdateDeviceInfo (false/*updateSRSupported*/, true/*updateBufferSizes*/);
+    }
+
+    //reactivate it.    
+    if (oldActive)
+    {
+        retVal = SetActive (true);
+    }
+    
+Exit:
+
+    return (retVal);
+        
+}
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::SetAndCheckCurrentSamplingRate 
+//
+//! Change the sampling rate to be used by the device. 
+//!
+//! \param newRate : The rate to use (samples per sec).
+//! 
+//! \return eNoErr always. The derived classes may return error codes.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::SetAndCheckCurrentSamplingRate (int newRate)
+{
+    AUTO_FUNC_DEBUG;
+    std::vector<int>::iterator intIter;
+    WTErr retVal = eNoErr;
+    OSStatus err = kAudioHardwareNoError;
+    UInt32 propSize = 0;
+    
+    // 1. Set new sampling rate
+    Float64 newNominalRate = newRate;
+    propSize = sizeof (Float64);
+    err = AudioDeviceSetProperty(m_DeviceID, NULL, 0, 0, kAudioDevicePropertyNominalSampleRate, propSize, &newNominalRate);
+    
+    m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Changed the Sampling Rate.");
+    
+    if (err != kAudioHardwareNoError)
+    {
+        retVal = eCoreAudioFailed;
+        DEBUG_MSG ("Unable to set SR! Device name: " << m_DeviceName.c_str());
+    }
+    else
+    {
+        // 2. wait for the SR to actually change...
+        
+        // Set total time out time
+        int tryAgain = ((PROPERTY_CHANGE_TIMEOUT_SECONDS * 1000) / PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS) ;
+        int actualWait = 0;
+        Float64 actualSamplingRate = 0.0;
+        
+        // Run as ling as time out is not finished
+        while (tryAgain)
+        {
+            // Get current sampling rate
+            err = AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &actualSamplingRate);
+            if (err == kAudioHardwareNoError)
+            {
+                if (actualSamplingRate == newNominalRate)
+                {
+                    //success, let's get out!
+                    break;
+                }
+            }
+            else
+            {
+                //error reading rate, but let's not complain too much!
+                m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Could not read Sampling Rate for verification.");
+                DEBUG_MSG ("Unable to get SR. Device name: " << m_DeviceName.c_str());
+            }
+            
+            // oh well...there's always another millisecond...
+            wvThread::sleep_milliseconds (PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS);
+            tryAgain--;
+            actualWait++;
+        }
+        
+        // If sample rate actually changed
+        if (tryAgain != 0)
+        {
+            // Update member with new rate
+            m_CurrentSamplingRate = newRate;
+            
+            char debugMsg[128];
+            snprintf (debugMsg, sizeof(debugMsg), "Actual Wait for SR Change was %d milliseconds", actualWait * PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS);
+            m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)debugMsg);
+        }
+        // If sample rate did not change after time out
+        else
+        {
+            // Update member with last read value
+            m_CurrentSamplingRate = static_cast<int>(actualSamplingRate);
+            
+            char debugMsg[128];
+            snprintf (debugMsg, sizeof(debugMsg), "Unable to change SR, even after waiting for %d milliseconds", actualWait * PROPERTY_CHANGE_SLEEP_TIME_MILLISECONDS);
+            m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)debugMsg);
+        }
+    }
+    
+    return (retVal);
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::BufferSizes 
+//
+//! in case of 'eMatchedDuplexDevices' and a matching device exists return common buffer sizes
+//! in all other cases retur base class function implementation
+//!
+//! \param none
+//! 
+//! \return current sample rate
+//! 
+//**********************************************************************************************
+const std::vector<int>& WCMRCoreAudioDevice::BufferSizes()
+{
+    return WCMRAudioDevice::BufferSizes();
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::CurrentBufferSize
+//
+//! The device's current buffer size in use. This may be overridden, if the device needs to 
+//!     query the driver for the current size.
+//!
+//! \param none
+//! 
+//! \return The device's current buffer size. 0 on error.
+//! 
+//**********************************************************************************************
+int WCMRCoreAudioDevice::CurrentBufferSize ()
+{
+    AUTO_FUNC_DEBUG;
+
+    return (m_CurrentBufferSize);
+}
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::SetCurrentBufferSize
+//
+//! Change the buffer size to be used by the device. This will most likely be overridden, 
+//!     the base class simply updates the member variable.
+//!
+//! \param newSize : The buffer size to use (in sample-frames)
+//! 
+//! \return eNoErr always. The derived classes may return error codes.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::SetCurrentBufferSize (int newSize)
+{
+    AUTO_FUNC_DEBUG;
+    WTErr retVal = eNoErr;
+    std::vector<int>::iterator intIter;
+
+    //changes the status.
+    int oldSize = CurrentBufferSize();
+    bool oldActive = Active();
+
+    //same size, nothing to do.
+    if (oldSize == newSize)
+        goto Exit;
+    
+    if (Streaming())
+    {
+        //Can't change, perhaps use an "in use" type of error
+        retVal = eGenericErr;
+        goto Exit;
+    }
+    
+    if (oldActive)
+    {
+        //Deactivate it for the change...
+        SetActive (false);
+    }
+    
+    // when audio device is inactive it is safe to set a working buffer size according to new buffer size
+    // if 'newSize' is not a valid buffer size, another valid buffer size will be set
+    retVal = SetWorkingBufferSize(newSize);
+    if(retVal != eNoErr)
+    {
+        DEBUG_MSG("Unable to set a working buffer size. Device Name: " << DeviceName().c_str());
+        goto Exit;
+    }
+
+    //reactivate it.    
+    if (oldActive)
+    {
+        retVal = SetActive (true);
+        if(retVal != eNoErr)
+        {
+            DEBUG_MSG("Unable to activate device. Device Name: " << DeviceName().c_str());
+            goto Exit;
+        }
+    }
+    
+Exit:
+    
+    return (retVal);
+}
+
+WTErr WCMRCoreAudioDevice::SetWorkingBufferSize(int newSize)
+{
+    AUTO_FUNC_DEBUG;
+    WTErr retVal = eNoErr;
+    OSStatus err = kAudioHardwareNoError;
+    
+    // 1. Set new buffer size
+    err = SetBufferSizesByIO(newSize);
+    
+    // If there's no error it means this buffer size is supported
+    if(err == kAudioHardwareNoError)
+    {
+        m_CurrentBufferSize = newSize;
+    }
+    // If there was an error it means that this buffer size was not supported
+    else
+    {
+        // In case the new buffer size could not be set, set another working buffer size
+
+        // Run on all buffer sizes:
+        
+        // Try setting buffer sizes that are bigger then selected buffer size first,
+        // Since bigger buffer sizes usually work safer 
+        for(std::vector<int>::const_iterator iter = m_BufferSizes.begin();iter != m_BufferSizes.end();++iter)
+        {
+            int nCurBS = *iter;
+            
+            if(nCurBS > newSize)
+            {
+                // Try setting current buffer size
+                err = SetBufferSizesByIO(nCurBS);
+                
+                // in case buffer size is valid
+                if(err == kAudioHardwareNoError)
+                {
+                    // Set current buffer size
+                    m_CurrentBufferSize = nCurBS;
+                    break;
+                }
+            }
+        }
+        
+        // If bigger buffer sizes failed, go to smaller buffer sizes
+        if(err != kAudioHardwareNoError)
+        {
+            for(std::vector<int>::const_iterator iter = m_BufferSizes.begin();iter != m_BufferSizes.end();++iter)
+            {
+                int nCurBS = *iter;
+                
+                if(nCurBS < newSize)
+                {
+                    // Try setting current buffer size
+                    err = SetBufferSizesByIO(*iter);
+                    
+                    // in case buffer size is valid
+                    if(err == kAudioHardwareNoError)
+                    {
+                        // Set current buffer size
+                        m_CurrentBufferSize = *iter;
+                        break;
+                    }
+                }
+            }
+        }
+        
+        // Check if a valid buffer size was found
+        if(err == kAudioHardwareNoError)
+        {
+            // Notify that a different sample rate is set
+            char debugMsg[256];
+            snprintf (debugMsg, sizeof(debugMsg), "Could not set buffer size: %d, Set buffer size to: %d.", newSize, m_CurrentBufferSize);
+            m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)debugMsg);
+        }
+        // if there was no buffer size that could be set
+        else
+        {
+            // Set the parameter buffer size by default, set a debug message
+            m_CurrentBufferSize = newSize;
+            DEBUG_MSG("Unable to set any buffer size. Device Name: " << m_DeviceName.c_str());
+        }
+    }
+    
+    return retVal;
+}
+
+OSStatus WCMRCoreAudioDevice::SetBufferSizesByIO(int newSize)
+{
+    OSStatus err = kAudioHardwareNoError;
+    
+    // 1. Set new buffer size
+    UInt32 bufferSize = (UInt32)newSize;
+    UInt32 propSize = sizeof (UInt32);
+    
+    // Set new buffer size to input
+    if (!m_InputChannels.empty())
+    {
+        err = AudioDeviceSetProperty(m_DeviceID, NULL, 0, 1, kAudioDevicePropertyBufferFrameSize, propSize, &bufferSize);
+    }
+    else
+    {
+        err = AudioDeviceSetProperty(m_DeviceID, NULL, 0, 0, kAudioDevicePropertyBufferFrameSize, propSize, &bufferSize);
+    }
+    
+    return err;
+}
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::ConnectionStatus 
+//
+//! Retrieves the device's current connection status. This will most likely be overridden,
+//!     in case some driver communication is required to query the status.
+//!
+//! \param none
+//! 
+//! \return A ConnectionStates value.
+//! 
+//**********************************************************************************************
+WCMRCoreAudioDevice::ConnectionStates WCMRCoreAudioDevice::ConnectionStatus ()
+{
+    AUTO_FUNC_DEBUG;
+    //ToDo: May want to do something more to extract the actual status!
+    return (m_ConnectionStatus);
+    
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::EnableAudioUnitIO
+//
+//! Sets up the AUHAL for IO, allowing changes to the devices to be used by the AudioUnit.
+//!
+//! \param none
+//! 
+//! \return eNoErr on success, an error code on failure.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::EnableAudioUnitIO()
+{
+    AUTO_FUNC_DEBUG;
+    WTErr retVal = eNoErr;
+    OSStatus err = kAudioHardwareNoError;
+    
+    UInt32 enableIO = 1;
+    if (!m_InputChannels.empty())
+    {
+        ///////////////
+        //ENABLE IO (INPUT)
+        //You must enable the Audio Unit (AUHAL) for input 
+        
+        //Enable input on the AUHAL
+        err =  AudioUnitSetProperty(m_AUHALAudioUnit, 
+                                    kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input,
+                                    AUHAL_INPUT_ELEMENT,
+                                    &enableIO, sizeof(enableIO));
+
+        if (err)
+        {
+            DEBUG_MSG("Couldn't Enable IO on input scope of input element, error = " << err);
+            retVal = eGenericErr;
+            goto Exit;
+        }
+    }
+    
+    //disable Output on the AUHAL if there's no output
+    if (m_OutputChannels.empty())
+        enableIO = 0;
+    else
+        enableIO = 1;
+        
+    err = AudioUnitSetProperty(m_AUHALAudioUnit,
+                               kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output,
+                               AUHAL_OUTPUT_ELEMENT,
+                               &enableIO, sizeof(enableIO));
+        
+    if (err)
+    {
+        DEBUG_MSG("Couldn't Enable/Disable IO on output scope of output element, error = " << err);
+        retVal = eGenericErr;
+        goto Exit;
+    }
+
+Exit:
+    return retVal;
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::EnableListeners
+//
+//! Sets up listeners to listen for Audio Device property changes, so that app can be notified.
+//!
+//! \param none
+//! 
+//! \return eNoErr on success, an error code on failure.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::EnableListeners()
+{
+    AUTO_FUNC_DEBUG;
+    WTErr retVal = eNoErr;
+    OSStatus err = kAudioHardwareNoError;
+
+    //listner for SR change...
+    err = AudioDeviceAddPropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate,
+                                         StaticPropertyChangeProc, this);
+    
+    if (err)
+    {
+        DEBUG_MSG("Couldn't Setup SR Property Listner, error = " << err);
+        retVal = eGenericErr;
+        goto Exit;
+    }
+
+#if ENABLE_DEVICE_CHANGE_LISTNER    
+    {
+        //listner for device change...
+        err = AudioDeviceAddPropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceHasChanged,
+                                             StaticPropertyChangeProc, this);
+        
+        if (err)
+        {
+            DEBUG_MSG("Couldn't Setup device change Property Listner, error = " << err);
+            retVal = eGenericErr;
+            goto Exit;
+        }
+    }
+#endif //ENABLE_DEVICE_CHANGE_LISTNER   
+    
+    //listner for dropouts...
+    err = AudioDeviceAddPropertyListener(m_DeviceID, 0, 0, kAudioDeviceProcessorOverload,
+                                         StaticPropertyChangeProc, this);
+        
+    if (err)
+    {
+        DEBUG_MSG("Couldn't Setup Processor Overload Property Listner, error = " << err);
+        retVal = eGenericErr;
+        goto Exit;
+    }
+    
+
+Exit:   
+    return retVal;
+}
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::DisableListeners
+//
+//! Undoes the work done by EnableListeners
+//!
+//! \param none
+//! 
+//! \return eNoErr on success, an error code on failure.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::DisableListeners()
+{
+    AUTO_FUNC_DEBUG;
+    WTErr retVal = eNoErr;
+    OSStatus err = kAudioHardwareNoError;
+
+    //listner for SR change...
+    err = AudioDeviceRemovePropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyNominalSampleRate,
+                                            StaticPropertyChangeProc);
+        
+    if (err)
+    {
+        DEBUG_MSG("Couldn't Cleanup SR Property Listner, error = " << err);
+        //not sure if we need to report this...
+    }
+
+#if ENABLE_DEVICE_CHANGE_LISTNER    
+    {
+        err = AudioDeviceRemovePropertyListener(m_DeviceID, 0, 0, kAudioDevicePropertyDeviceHasChanged,
+                                                StaticPropertyChangeProc);
+            
+        if (err)
+        {
+            DEBUG_MSG("Couldn't Cleanup device change Property Listner, error = " << err);
+            //not sure if we need to report this...
+        }
+    }
+#endif //ENABLE_DEVICE_CHANGE_LISTNER   
+
+    err = AudioDeviceRemovePropertyListener(m_DeviceID, 0, 0, kAudioDeviceProcessorOverload,
+                                            StaticPropertyChangeProc);
+        
+    if (err)
+    {
+        DEBUG_MSG("Couldn't Cleanup device change Property Listner, error = " << err);
+        //not sure if we need to report this...
+    }
+    
+
+    return retVal;
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::StaticPropertyChangeProc
+//
+//! The property change function called (as a result of EnableListeners) when device properties change.
+//!     It calls upon the non-static PropertyChangeProc to do the work.
+//!
+//! \param inDevice : The audio device in question.
+//! \param inChannel : The channel on which the property has change.
+//! \param isInput : If the change is for Input.
+//! \param inPropertyID : The property that has changed.
+//! \param inClientData: What was passed when listener was enabled, in our case teh WCMRCoreAudioDevice object.
+//! 
+//! \return 0 always.
+//! 
+//**********************************************************************************************
+OSStatus WCMRCoreAudioDevice::StaticPropertyChangeProc (AudioDeviceID /*inDevice*/, UInt32 /*inChannel*/, Boolean /*isInput*/,
+                                                        AudioDevicePropertyID inPropertyID, void *inClientData)
+{
+    if (inClientData)
+    {
+        WCMRCoreAudioDevice* pCoreDevice = (WCMRCoreAudioDevice *)inClientData;
+        pCoreDevice->PropertyChangeProc (inPropertyID);
+    }
+        
+    return 0;
+}
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::PropertyChangeProc
+//
+//! The non-static property change proc. Gets called when properties change. Since this gets called
+//!     on an arbitrary thread, we simply update the request counters and return.
+//!
+//! \param none
+//! 
+//! \return nothing.
+//! 
+//**********************************************************************************************
+void WCMRCoreAudioDevice::PropertyChangeProc (AudioDevicePropertyID inPropertyID)
+{
+    switch (inPropertyID)
+    {
+    case kAudioDevicePropertyNominalSampleRate:
+        m_SRChangeRequested++;
+        break;
+#if ENABLE_DEVICE_CHANGE_LISTNER    
+    case kAudioDevicePropertyDeviceHasChanged:
+        {
+            m_ResetRequested++;
+        }
+        break;
+#endif //ENABLE_DEVICE_CHANGE_LISTNER   
+    case kAudioDeviceProcessorOverload:
+        if (m_IgnoreThisDrop)
+            m_IgnoreThisDrop = false; //We'll ignore once, just once!
+        else
+            m_DropsDetected++;
+        break;
+    default:
+        break;
+    }
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::SetupAUHAL
+//
+//! Sets up the AUHAL AudioUnit for device IO.
+//!
+//! \param none
+//! 
+//! \return eNoErr on success, an error code on failure.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::SetupAUHAL()
+{
+    AUTO_FUNC_DEBUG;
+    WTErr retVal = eNoErr;
+    OSStatus err = kAudioHardwareNoError;
+    UInt32 propSize = 0;
+    Component comp;
+    ComponentDescription desc;
+    AudioStreamBasicDescription streamFormatToUse, auhalStreamFormat;
+
+    //There are several different types of Audio Units.
+    //Some audio units serve as Outputs, Mixers, or DSP
+    //units. See AUComponent.h for listing
+    desc.componentType = kAudioUnitType_Output;
+    
+    //Every Component has a subType, which will give a clearer picture
+    //of what this components function will be.
+    desc.componentSubType = kAudioUnitSubType_HALOutput;
+    
+    //all Audio Units in AUComponent.h must use 
+    //"kAudioUnitManufacturer_Apple" as the Manufacturer
+    desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+    desc.componentFlags = 0;
+    desc.componentFlagsMask = 0;
+    
+    //Finds a component that meets the desc spec's
+    comp = FindNextComponent(NULL, &desc);
+    if (comp == NULL)
+    {
+        DEBUG_MSG("Couldn't find AUHAL Component");
+        retVal = eGenericErr;
+        goto Exit;
+    }
+    
+    //gains access to the services provided by the component
+    OpenAComponent(comp, &m_AUHALAudioUnit);  
+
+    
+    retVal = EnableAudioUnitIO();
+    if (retVal != eNoErr)
+        goto Exit;
+
+    //Now setup the device to use by the audio unit...
+    
+    //input
+    if (!m_InputChannels.empty())
+    {
+        err = AudioUnitSetProperty(m_AUHALAudioUnit, kAudioOutputUnitProperty_CurrentDevice,
+                                   kAudioUnitScope_Global, AUHAL_INPUT_ELEMENT,
+                                   &m_DeviceID, sizeof(m_DeviceID));
+
+        if (err)
+        {
+            DEBUG_MSG("Couldn't Set the audio device property for Input Element Global scope, error = " << err);
+            retVal = eGenericErr;
+            goto Exit;
+        }
+    }
+
+    //output
+    if (!m_OutputChannels.empty())
+    {
+        err = AudioUnitSetProperty(m_AUHALAudioUnit, kAudioOutputUnitProperty_CurrentDevice,
+                                   kAudioUnitScope_Global, AUHAL_OUTPUT_ELEMENT,
+                                   &m_DeviceID, sizeof(m_DeviceID));
+
+        if (err)
+        {
+            DEBUG_MSG("Couldn't Set the audio device property for Output Element Global scope, error = " << err);
+            retVal = eGenericErr;
+            goto Exit;
+        }
+    }
+    
+    //also set Sample Rate...
+    {
+        retVal = SetAndCheckCurrentSamplingRate(m_CurrentSamplingRate);
+        if(retVal != eNoErr)
+        {
+            DEBUG_MSG ("Unable to set SR, error = " << err);
+            goto Exit;
+        }
+    }
+
+    //now set the buffer size...
+    {
+        err = SetWorkingBufferSize(m_CurrentBufferSize);
+        if (err)
+        {
+            DEBUG_MSG("Couldn't Set the buffer size property, error = " << err);
+            //we don't really quit here..., just keep going even if this does not work,
+            //the AUHAL is supposed to take care of this by way of slicing...
+            m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Could not set buffer size.");
+            
+        }
+    }
+    
+    //convertor quality
+    {
+        UInt32 quality = kAudioConverterQuality_Max;
+        propSize = sizeof (quality);
+        err = AudioUnitSetProperty(m_AUHALAudioUnit,
+                                   kAudioUnitProperty_RenderQuality, kAudioUnitScope_Global,
+                                   AUHAL_OUTPUT_ELEMENT,
+                                   &quality, sizeof (quality));
+            
+        if (err != kAudioHardwareNoError)
+        {
+            DEBUG_MSG ("Unable to set Convertor Quality, error = " << err);
+            retVal = eGenericErr;
+            goto Exit;
+        }
+    }
+    
+    memset (&auhalStreamFormat, 0, sizeof (auhalStreamFormat));
+    propSize = sizeof (auhalStreamFormat);
+    err = AudioUnitGetProperty(m_AUHALAudioUnit,
+                               kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
+                               AUHAL_INPUT_ELEMENT,
+                               &auhalStreamFormat, &propSize);
+    if (err != kAudioHardwareNoError)
+    {
+        DEBUG_MSG ("Unable to get Input format, error = " << err);
+        retVal = eGenericErr;
+        goto Exit;
+    }
+    
+    if (auhalStreamFormat.mSampleRate != (Float64)m_CurrentSamplingRate)
+    {
+        TRACE_MSG ("AUHAL's Input SR differs from expected SR, expected = " << m_CurrentSamplingRate << ", AUHAL's = " << (UInt32)auhalStreamFormat.mSampleRate);
+    }
+    
+    //format, and slice size...
+    memset (&streamFormatToUse, 0, sizeof (streamFormatToUse));
+    streamFormatToUse.mFormatID = kAudioFormatLinearPCM;
+    streamFormatToUse.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
+    streamFormatToUse.mFramesPerPacket = 1;
+    streamFormatToUse.mBitsPerChannel = sizeof (float) * 8;
+    streamFormatToUse.mSampleRate = auhalStreamFormat.mSampleRate;
+
+    if (!m_InputChannels.empty())
+    {
+        streamFormatToUse.mChannelsPerFrame = m_InputChannels.size();
+        streamFormatToUse.mBytesPerFrame = sizeof (float)*streamFormatToUse.mChannelsPerFrame;
+        streamFormatToUse.mBytesPerPacket = streamFormatToUse.mBytesPerFrame;
+        propSize = sizeof (streamFormatToUse);
+        err = AudioUnitSetProperty(m_AUHALAudioUnit,
+                                   kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
+                                   AUHAL_INPUT_ELEMENT,
+                                   &streamFormatToUse, sizeof (streamFormatToUse));
+
+        if (err != kAudioHardwareNoError)
+        {
+            DEBUG_MSG ("Unable to set Input format, error = " << err);
+            retVal = eGenericErr;
+            goto Exit;
+        }
+        
+        UInt32 bufferSize = m_CurrentBufferSize;
+        err = AudioUnitSetProperty(m_AUHALAudioUnit,
+                                   kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output,
+                                   AUHAL_INPUT_ELEMENT,
+                                   &bufferSize, sizeof (bufferSize));
+
+        if (err != kAudioHardwareNoError)
+        {
+            DEBUG_MSG ("Unable to set Input frames, error = " << err);
+            retVal = eGenericErr;
+            goto Exit;
+        }
+        
+    }
+
+    if (!m_OutputChannels.empty())
+    {
+        err = AudioUnitGetProperty(m_AUHALAudioUnit,
+                                   kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
+                                   AUHAL_OUTPUT_ELEMENT,
+                                   &auhalStreamFormat, &propSize);
+        if (err != kAudioHardwareNoError)
+        {
+            DEBUG_MSG ("Unable to get Output format, error = " << err);
+            retVal = eGenericErr;
+            goto Exit;
+        }
+        
+        if (auhalStreamFormat.mSampleRate != (Float64)m_CurrentSamplingRate)
+        {
+            TRACE_MSG ("AUHAL's Output SR differs from expected SR, expected = " << m_CurrentSamplingRate << ", AUHAL's = " << (UInt32)auhalStreamFormat.mSampleRate);
+        }
+        
+        
+        streamFormatToUse.mChannelsPerFrame = m_OutputChannels.size();
+        streamFormatToUse.mBytesPerFrame = sizeof (float)*streamFormatToUse.mChannelsPerFrame;
+        streamFormatToUse.mBytesPerPacket = streamFormatToUse.mBytesPerFrame;
+        streamFormatToUse.mSampleRate = auhalStreamFormat.mSampleRate;
+        propSize = sizeof (streamFormatToUse);
+        err = AudioUnitSetProperty(m_AUHALAudioUnit,
+                                   kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
+                                   AUHAL_OUTPUT_ELEMENT,
+                                   &streamFormatToUse, sizeof (streamFormatToUse));
+
+        if (err != kAudioHardwareNoError)
+        {
+            DEBUG_MSG ("Unable to set Output format, error = " << err);
+            retVal = eGenericErr;
+            goto Exit;
+        }
+
+        UInt32 bufferSize = m_CurrentBufferSize;
+        err = AudioUnitSetProperty(m_AUHALAudioUnit,
+                                   kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Input,
+                                   AUHAL_OUTPUT_ELEMENT,
+                                   &bufferSize, sizeof (bufferSize));
+
+        if (err != kAudioHardwareNoError)
+        {
+            DEBUG_MSG ("Unable to set Output frames, error = " << err);
+            retVal = eGenericErr;
+            goto Exit;
+        }
+
+    }
+    
+    //setup callback (IOProc)
+    {
+        AURenderCallbackStruct renderCallback;
+        memset (&renderCallback, 0, sizeof (renderCallback));
+        propSize = sizeof (renderCallback);
+        renderCallback.inputProc = StaticAudioIOProc;
+        renderCallback.inputProcRefCon = this;
+        
+        err = AudioUnitSetProperty(m_AUHALAudioUnit,
+                                   (m_OutputChannels.empty() ? (AudioUnitPropertyID)kAudioOutputUnitProperty_SetInputCallback : (AudioUnitPropertyID)kAudioUnitProperty_SetRenderCallback),
+                                   kAudioUnitScope_Output,
+                                   m_OutputChannels.empty() ? AUHAL_INPUT_ELEMENT : AUHAL_OUTPUT_ELEMENT,
+                                   &renderCallback, sizeof (renderCallback));
+            
+        if (err != kAudioHardwareNoError)
+        {
+            DEBUG_MSG ("Unable to set callback, error = " << err);
+            retVal = eGenericErr;
+            goto Exit;
+        }
+    }
+
+    retVal = EnableListeners();
+    if (retVal != eNoErr)
+        goto Exit;
+
+    //also prepare the buffer list for input...
+    if (!m_InputChannels.empty())
+    {
+        
+        //now setup the buffer list.
+        memset (&m_InputAudioBufferList, 0, sizeof (m_InputAudioBufferList));
+        m_InputAudioBufferList.mNumberBuffers = 1;
+        m_InputAudioBufferList.mBuffers[0].mNumberChannels = m_InputChannels.size();
+        m_InputAudioBufferList.mBuffers[0].mDataByteSize = m_InputAudioBufferList.mBuffers[0].mNumberChannels *
+            m_CurrentBufferSize * sizeof(float);
+        //allocate the data buffer...
+        try
+        {
+            m_pInputData = new float[m_InputAudioBufferList.mBuffers[0].mNumberChannels * m_CurrentBufferSize];
+        }
+        catch (...)
+        {
+            retVal = eMemNewFailed;
+            goto Exit;
+        }
+        
+        m_InputAudioBufferList.mBuffers[0].mData = m_pInputData;
+        
+        //zero it out...
+        memset (m_InputAudioBufferList.mBuffers[0].mData, 0, m_InputAudioBufferList.mBuffers[0].mDataByteSize);
+    
+    }
+
+    //initialize the audio-unit now!
+    err = AudioUnitInitialize(m_AUHALAudioUnit);
+    if (err != kAudioHardwareNoError)
+    {
+        DEBUG_MSG ("Unable to Initialize AudioUnit = " << err);
+        retVal = eGenericErr;
+        goto Exit;
+    }
+    
+Exit:
+    if (retVal != eNoErr)
+        TearDownAUHAL();
+        
+    return retVal;
+}
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::TearDownAUHAL
+//
+//! Undoes the work done by SetupAUHAL
+//!
+//! \param none
+//! 
+//! \return eNoErr on success, an error code on failure.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::TearDownAUHAL()
+{
+    WTErr retVal = eNoErr;
+
+    if (m_AUHALAudioUnit)
+    {
+        DisableListeners ();
+        AudioUnitUninitialize(m_AUHALAudioUnit);
+        CloseComponent(m_AUHALAudioUnit);
+        m_AUHALAudioUnit = NULL;
+    }
+    
+    safe_delete_array(m_pInputData);
+
+    return retVal;
+}
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::SetActive 
+//
+//! Sets the device's activation status. Essentially, opens or closes the PA device. 
+//!     If it's an ASIO device it may result in buffer size change in some cases.
+//!
+//! \param newState : Should be true to activate, false to deactivate. This roughly corresponds
+//!     to opening and closing the device handle/stream/audio unit.
+//! 
+//! \return eNoErr on success, an error code otherwise.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::SetActive (bool newState)
+{
+    AUTO_FUNC_DEBUG;
+
+    WTErr retVal = eNoErr;
+    
+    if (Active() == newState)
+        goto Exit;
+
+
+    if (newState)
+    {
+        
+        m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Setting up AUHAL.");
+        retVal = SetupAUHAL();
+
+        if (retVal != eNoErr)
+            goto Exit;
+
+        m_BufferSizeChangeRequested = 0;
+        m_BufferSizeChangeReported = 0;
+        m_ResetRequested = 0;
+        m_ResetReported = 0;
+        m_ResyncRequested = 0;
+        m_ResyncReported = 0;
+        m_SRChangeRequested = 0;
+        m_SRChangeReported = 0;
+        m_DropsDetected = 0;
+        m_DropsReported = 0;
+        m_IgnoreThisDrop = true;
+    }
+    else
+    {
+        if (Streaming())
+        {
+            SetStreaming (false);
+        }
+
+        m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Tearing down AUHAL.");
+        retVal = TearDownAUHAL();
+        if (retVal != eNoErr)
+            goto Exit;
+
+        m_BufferSizeChangeRequested = 0;
+        m_BufferSizeChangeReported = 0;
+        m_ResetRequested = 0;
+        m_ResetReported = 0;
+        m_ResyncRequested = 0;
+        m_ResyncReported = 0;
+        m_SRChangeRequested = 0;
+        m_SRChangeReported = 0;
+        m_DropsDetected = 0;
+        m_DropsReported = 0;
+        m_IgnoreThisDrop = true;
+
+        UpdateDeviceInfo(true /*updateSRSupported */, true /* updateBufferSizes#*/);
+
+    }
+    
+    m_IsActive = newState;
+    
+Exit:   
+    return (retVal);
+}
+
+
+#if WV_USE_TONE_GEN
+//**********************************************************************************************
+// WCMRCoreAudioDevice::SetupToneGenerator
+//
+//! Sets up the Tone generator - only if a file /tmp/tonegen.txt is present. If the file is
+//!     present, it reads the value in the file and uses that as the frequency for the tone. This
+//!     code attempts to create an array of samples that would constitute an integral number of
+//!     cycles - for the currently active sampling rate. If tonegen is active, then the input
+//!     from the audio device is ignored, instead a data is supplied from the tone generator's
+//!     array - for all channels. The array is in m_pToneData, the size of the array is in
+//!     m_ToneDataSamples, and m_NextSampleToUse holds the index in the array from where
+//!     the next sample is going to be taken.
+//!
+//!
+//! \return : Nothing
+//!
+//**********************************************************************************************
+void WCMRCoreAudioDevice::SetupToneGenerator ()
+{
+    safe_delete_array(m_pToneData);
+    m_ToneDataSamples = 0;
+
+    //if tonegen exists?
+    FILE *toneGenHandle = fopen ("/tmp/tonegen.txt", "r");
+    if (toneGenHandle)
+    {
+        int toneFreq = 0;
+        fscanf(toneGenHandle, "%d", &toneFreq);
+        if ((toneFreq <= 0) || (toneFreq > (m_CurrentSamplingRate/2)))
+        {
+            toneFreq = 1000;    
+        }
+        
+        
+        m_ToneDataSamples = m_CurrentSamplingRate / toneFreq;
+        int toneDataSamplesFrac = m_CurrentSamplingRate % m_ToneDataSamples;
+        int powerOfTen = 1;
+        while (toneDataSamplesFrac)
+        {
+            m_ToneDataSamples = (uint32_t)((pow(10, powerOfTen) * m_CurrentSamplingRate) / toneFreq);
+            toneDataSamplesFrac = m_CurrentSamplingRate % m_ToneDataSamples;
+            powerOfTen++;
+        }
+        
+        //allocate
+        m_pToneData = new float_t[m_ToneDataSamples];
+        
+        //fill with a -6dB Sine Tone
+        uint32_t numSamplesLeft = m_ToneDataSamples;
+        float_t *pNextSample = m_pToneData;
+        double phase = 0;
+        double phaseIncrement = (M_PI * 2.0 * toneFreq ) / ((double)m_CurrentSamplingRate);
+        while (numSamplesLeft)
+        {
+            *pNextSample = (float_t)(0.5 * sin(phase));
+            phase += phaseIncrement;
+            pNextSample++;
+            numSamplesLeft--;
+        }
+        
+        m_NextSampleToUse = 0;
+        
+        fclose(toneGenHandle);
+    }
+}
+#endif //WV_USE_TONE_GEN
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::SetStreaming
+//
+//! Sets the device's streaming status. Calls PA's Start/Stop stream routines.
+//!
+//! \param newState : Should be true to start streaming, false to stop streaming. This roughly
+//!     corresponds to calling Start/Stop on the lower level interface.
+//! 
+//! \return eNoErr always, the derived classes may return appropriate error code.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::SetStreaming (bool newState)
+{
+    AUTO_FUNC_DEBUG;
+    WTErr retVal = eNoErr;
+    ComponentResult err = 0;
+
+    if (Streaming () == newState)
+        goto Exit;
+
+    if (newState)
+    {
+#if WV_USE_TONE_GEN
+        SetupToneGenerator ();
+#endif //WV_USE_TONE_GEN
+
+        m_StopRequested = false;
+        m_SampleCountAtLastIdle = 0;
+        m_StalledSampleCounter = 0;
+        m_SampleCounter = 0;
+        m_IOProcThreadPort = 0;
+        m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Starting AUHAL.");
+        
+        if (m_UseMultithreading)
+        {
+            //set thread constraints...
+            unsigned int periodAndConstraintUS = (unsigned int)((1000000.0 * m_CurrentBufferSize) / m_CurrentSamplingRate);
+            unsigned int computationUS = (unsigned int)(0.8 * periodAndConstraintUS); //assuming we may want to use up to 80% CPU
+            //ErrandManager().SetRealTimeConstraintsForAllThreads (periodAndConstraintUS, computationUS, periodAndConstraintUS);
+        }
+        
+        err = AudioOutputUnitStart (m_AUHALAudioUnit);
+        
+        if(err)
+        {
+            DEBUG_MSG( "Failed to start AudioUnit, err " << err );
+            retVal = eGenericErr;
+            goto Exit;
+        }
+    }
+    else
+    {
+        m_StopRequested = true;
+        m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDebugInfo, (void *)"Stopping AUHAL.");
+        err = AudioOutputUnitStop (m_AUHALAudioUnit);
+        if (!err)
+        {
+            if (!m_InputChannels.empty());
+            {
+                err = AudioUnitReset (m_AUHALAudioUnit, kAudioUnitScope_Global, AUHAL_INPUT_ELEMENT);
+            }
+            if (!m_OutputChannels.empty());
+            {
+                err = AudioUnitReset (m_AUHALAudioUnit, kAudioUnitScope_Global, AUHAL_OUTPUT_ELEMENT);
+            }
+        }
+        
+        if(err)
+        {
+            DEBUG_MSG( "Failed to stop AudioUnit " << err );
+            retVal = eGenericErr;
+            goto Exit;
+        }
+        m_IOProcThreadPort = 0;
+    }
+
+    // After units restart, reset request for reset and SR change
+    m_SRChangeReported = m_SRChangeRequested;
+    m_ResetReported = m_ResetRequested;
+    
+    m_IsStreaming = newState;
+
+Exit:   
+    return (retVal);
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::DoIdle 
+//
+//! A place for doing idle time processing. The other derived classes will probably do something
+//!     meaningful.
+//!
+//! \param none
+//! 
+//! \return eNoErr always.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::DoIdle ()
+{
+    if (m_BufferSizeChangeRequested != m_BufferSizeChangeReported)
+    {
+        m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged);
+        m_BufferSizeChangeReported = m_BufferSizeChangeRequested;
+    }
+
+    if (m_ResetRequested != m_ResetReported)
+    {
+        m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
+        m_ResetReported = m_ResetRequested;
+    }
+
+
+    if (m_ResyncRequested != m_ResyncReported)
+    {
+        m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestResync);
+        m_ResyncReported = m_ResyncRequested;
+    }
+    
+    if (m_SRChangeReported != m_SRChangeRequested)
+    {
+        m_SRChangeReported = m_SRChangeRequested;
+        int newSR = CurrentSamplingRate();
+        m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::SamplingRateChanged, (void *)newSR);
+    }
+
+    if (m_DropsReported != m_DropsDetected)
+    {
+        m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceDroppedSamples);
+        m_DropsReported = m_DropsDetected;
+    }
+
+    
+    //Perhaps add checks to make sure a stream counter is incrementing if
+    //stream is supposed to be streaming!
+    if (Streaming())
+    {
+        //latch the value
+        int64_t currentSampleCount = m_SampleCounter;
+        if (m_SampleCountAtLastIdle == currentSampleCount)
+            m_StalledSampleCounter++;
+        else
+        {
+            m_SampleCountAtLastIdle = (int)currentSampleCount;
+            m_StalledSampleCounter = 0;
+        }
+
+        if (m_StalledSampleCounter > NUM_STALLS_FOR_NOTIFICATION)
+        {
+            m_StalledSampleCounter = 0;
+            m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStoppedStreaming, (void *)currentSampleCount);
+        }
+    }
+
+    
+    return (eNoErr);
+}
+
+
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::SetMonitorChannels 
+//
+//! Used to set the channels to be used for monitoring.
+//!
+//! \param leftChannel : Left monitor channel index.
+//! \param rightChannel : Right monitor channel index.
+//! 
+//! \return eNoErr always, the derived classes may return appropriate errors.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::SetMonitorChannels (int leftChannel, int rightChannel)
+{
+    AUTO_FUNC_DEBUG;
+    //This will most likely be overridden, the base class simply
+    //changes the member.
+    m_LeftMonitorChannel = leftChannel;
+    m_RightMonitorChannel = rightChannel;
+    return (eNoErr);
+}
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::SetMonitorGain 
+//
+//! Used to set monitor gain (or atten).
+//!
+//! \param newGain : The new gain or atten. value to use. Specified as a linear multiplier (not dB) 
+//! 
+//! \return eNoErr always, the derived classes may return appropriate errors.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::SetMonitorGain (float newGain)
+{
+    AUTO_FUNC_DEBUG;
+    //This will most likely be overridden, the base class simply
+    //changes the member.
+    
+    
+    m_MonitorGain = newGain;
+    return (eNoErr);
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::ShowConfigPanel 
+//
+//! Used to show device specific config/control panel. Some interfaces may not support it.
+//!     Some interfaces may require the device to be active before it can display a panel.
+//!
+//! \param pParam : A device/interface specific parameter, should be the app window handle for ASIO.
+//! 
+//! \return eNoErr always, the derived classes may return errors.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDevice::ShowConfigPanel (void */*pParam*/)
+{
+    AUTO_FUNC_DEBUG;
+    WTErr retVal = eNoErr;
+    
+    CFStringRef configAP;
+    UInt32 propSize = sizeof (configAP);
+    /*
+      @constant       kAudioDevicePropertyConfigurationApplication
+      A CFString that contains the bundle ID for an application that provides a
+      GUI for configuring the AudioDevice. By default, the value of this property
+      is the bundle ID for Audio MIDI Setup. The caller is responsible for
+      releasing the returned CFObject.
+    */
+    
+    if (AudioDeviceGetProperty(m_DeviceID, 0, 0, kAudioDevicePropertyConfigurationApplication, &propSize, &configAP) == kAudioHardwareNoError)
+    {
+        //  get the FSRef of the config app
+        FSRef theAppFSRef;
+        OSStatus theError = LSFindApplicationForInfo(kLSUnknownCreator, configAP, NULL, &theAppFSRef, NULL);
+        if (!theError)
+        {
+            LSOpenFSRef(&theAppFSRef, NULL);
+        }
+        CFRelease (configAP);
+    }
+    
+    return (retVal);
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::StaticAudioIOProc
+//
+//! The AudioIOProc that gets called when the AudioUnit is ready with recorded audio, and wants to get audio.
+//!     This one simply calls the non-static member.
+//!
+//! \param inRefCon : What was passed when setting up the Callback (in our case a pointer to teh WCMRCoreAudioDevice object).
+//! \param ioActionFlags : What actios has to be taken.
+//! \param inTimeStamp: When the data will be played back.
+//! \param inBusNumber : The AU element.
+//! \param inNumberFrames: Number af Audio frames that are requested.
+//! \param ioData : Where the playback data is to be placed.
+//! 
+//! \return 0 always
+//! 
+//**********************************************************************************************
+OSStatus WCMRCoreAudioDevice::StaticAudioIOProc(void *inRefCon, AudioUnitRenderActionFlags *    ioActionFlags,
+                                                const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
+                                                AudioBufferList *ioData)
+{
+    WCMRCoreAudioDevice *pMyDevice = (WCMRCoreAudioDevice *)inRefCon;
+    if (pMyDevice)
+        return pMyDevice->AudioIOProc (ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
+    else
+        return 0;
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::AudioIOProc
+//
+//! The non-static AudioIOProc that gets called when the AudioUnit is ready with recorded audio, and wants to get audio.
+//!     We retrieve the recorded audio, and then do our processing, to generate audio to be played back.
+//!
+//! \param ioActionFlags : What actios has to be taken.
+//! \param inTimeStamp: When the data will be played back.
+//! \param inBusNumber : The AU element.
+//! \param inNumberFrames: Number af Audio frames that are requested.
+//! \param ioData : Where the playback data is to be placed.
+//! 
+//! \return 0 always
+//! 
+//**********************************************************************************************
+OSStatus WCMRCoreAudioDevice::AudioIOProc(AudioUnitRenderActionFlags *  ioActionFlags,
+                                          const AudioTimeStamp *inTimeStamp, UInt32 /*inBusNumber*/, UInt32 inNumberFrames,
+                                          AudioBufferList *ioData)
+{
+    UInt64 theStartTime = AudioGetCurrentHostTime();
+
+    OSStatus retVal = 0;
+    
+    if (m_StopRequested)
+        goto Exit;
+
+    if (m_IOProcThreadPort == 0)
+        m_IOProcThreadPort = mach_thread_self ();
+    
+    //cannot really deal with it unless the number of frames are the same as our buffer size!
+    if (inNumberFrames != (UInt32)m_CurrentBufferSize)
+        goto Exit;
+    
+    //Retrieve the input data...
+    if (!m_InputChannels.empty())
+    {
+        retVal = AudioUnitRender(m_AUHALAudioUnit, ioActionFlags, inTimeStamp, AUHAL_INPUT_ELEMENT, inNumberFrames, &m_InputAudioBufferList);
+    }
+    
+    //is this an input only device?
+    if (m_OutputChannels.empty())
+        AudioCallback (NULL, inNumberFrames, (uint32_t)inTimeStamp->mSampleTime, theStartTime);
+    else if ((!m_OutputChannels.empty()) && (ioData->mBuffers[0].mNumberChannels == m_OutputChannels.size()))
+        AudioCallback ((float *)ioData->mBuffers[0].mData, inNumberFrames, (uint32_t)inTimeStamp->mSampleTime, theStartTime);
+    
+Exit:   
+    return retVal;
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::AudioCallback 
+//
+//! Here's where the actual audio processing happens. We call upon all the active connections' 
+//!     sinks to provide data to us which can be put/mixed in the output buffer! Also, we make the 
+//!     input data available to any sources that may call upon us during this time!
+//!
+//! \param *pOutputBuffer : Points to a buffer to receive playback data. For Input only devices, this will be NULL
+//! \param framesPerBuffer : Number of sample frames in input and output buffers. Number of channels,
+//!     which are interleaved, is fixed at Device Open (Active) time. In this implementation,
+//!     the number of channels are fixed to use the maximum available.
+//! 
+//! \return true
+//! 
+//**********************************************************************************************
+int WCMRCoreAudioDevice::AudioCallback (float *pOutputBuffer, unsigned long framesPerBuffer, uint32_t inSampleTime, uint64_t inCycleStartTime)
+{
+    struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData =
+    {
+        m_pInputData,
+        pOutputBuffer,
+        framesPerBuffer,
+        inSampleTime,
+        AudioConvertHostTimeToNanos(inCycleStartTime)
+    };
+    
+    m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData);
+    
+    m_SampleCounter += framesPerBuffer;
+    return m_StopRequested;
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::GetLatency
+//
+//! Get Latency for device.
+//!
+//! Use 'kAudioDevicePropertyLatency' and 'kAudioDevicePropertySafetyOffset' + GetStreamLatencies
+//!
+//! \param isInput : Return latency for the input if isInput is true, otherwise the output latency
+//!                  wiil be returned.
+//! \return Latency in samples.
+//!
+//**********************************************************************************************
+uint32_t WCMRCoreAudioDevice::GetLatency(bool isInput)
+{
+    WTErr retVal = eNoErr;
+    OSStatus err = kAudioHardwareNoError;
+
+    UInt32 propSize = sizeof(UInt32);
+    UInt32 value1 = 0;
+    UInt32 value2 = 0;
+    
+    UInt32 latency = 0;
+    std::vector<int> streamLatencies;
+    
+    
+    err = AudioDeviceGetProperty(m_DeviceID, 0, isInput, kAudioDevicePropertyLatency, &propSize, &value1);
+    if (err != kAudioHardwareNoError)
+    {
+        DEBUG_MSG("GetLatency kAudioDevicePropertyLatency err = " << err);
+    }
+
+    err = AudioDeviceGetProperty(m_DeviceID, 0, isInput, kAudioDevicePropertySafetyOffset, &propSize, &value2);
+    if (err != kAudioHardwareNoError)
+    {
+        DEBUG_MSG("GetLatency kAudioDevicePropertySafetyOffset err = " << err);
+    }
+
+    latency = value1 + value2;
+
+    err = GetStreamLatency(m_DeviceID, isInput, streamLatencies);
+    if (err == kAudioHardwareNoError)
+    {
+        for ( int i = 0; i < streamLatencies.size(); i++) {
+            latency += streamLatencies[i];
+        }
+    }
+    
+    return latency;
+}
+
+//**********************************************************************************************
+// WCMRCoreAudioDevice::GetStreamLatency
+//
+//! Get stream latency for device.
+//!
+//! \param deviceID : The audio device ID.
+//!
+//! \param isInput : Return latency for the input if isInput is true, otherwise the output latency
+//!                  wiil be returned.
+//**********************************************************************************************
+OSStatus WCMRCoreAudioDevice::GetStreamLatency(AudioDeviceID device, bool isInput, std::vector<int>& latencies)
+{
+    OSStatus err = kAudioHardwareNoError;
+    UInt32 outSize1, outSize2, outSize3;
+    Boolean    outWritable;
+    
+    err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, &outWritable);
+    if (err == noErr) {
+        int stream_count = outSize1 / sizeof(UInt32);
+        AudioStreamID streamIDs[stream_count];
+        AudioBufferList bufferList[stream_count];
+        UInt32 streamLatency;
+        outSize2 = sizeof(UInt32);
+        
+        err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreams, &outSize1, streamIDs);
+        if (err != noErr) {
+            DEBUG_MSG("GetStreamLatencies kAudioDevicePropertyStreams err = " << err);
+            return err;
+        }
+        
+        err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, &outWritable);
+        if (err != noErr) {
+            DEBUG_MSG("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = " << err);
+            return err;
+        }
+        
+        for (int i = 0; i < stream_count; i++) {
+            err = AudioStreamGetProperty(streamIDs[i], 0, kAudioStreamPropertyLatency, &outSize2, &streamLatency);
+            if (err != noErr) {
+                DEBUG_MSG("GetStreamLatencies kAudioStreamPropertyLatency err = " << err);
+                return err;
+            }
+            err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize3, bufferList);
+            if (err != noErr) {
+                DEBUG_MSG("GetStreamLatencies kAudioDevicePropertyStreamConfiguration err = " << err);
+                return err;
+            }
+            latencies.push_back(streamLatency);
+        }
+    }
+    return err;
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager
+//
+//! The constructuor, we initialize PA, and build the device list.
+//!
+//! \param *pTheClient : The manager's client object (which receives notifications).
+//! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true.
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter 
+                                                       , bool useMultithreading, eCABS_Method eCABS_method, bool bNocopy) 
+  : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter
+      )
+  , m_UpdateDeviceListRequested(0)
+  , m_UpdateDeviceListProcessed(0)
+  , m_UseMultithreading (useMultithreading)
+  , m_eCABS_Method(eCABS_method)
+  , m_bNoCopyAudioBuffer(bNocopy)
+{
+    AUTO_FUNC_DEBUG;
+
+    //first of all, tell HAL to use it's own run loop, not to wait for our runloop to do
+    //it's dirty work...
+    //Essentially, this makes the HAL on Snow Leopard behave like Leopard.
+    //It's not yet (as of October 2009 documented), but the following discussion
+    //has the information provided by Jeff Moore @ Apple:
+    // http://lists.apple.com/archives/coreaudio-api/2009/Oct/msg00214.html
+    //
+    // As per Jeff's suggestion, opened an Apple Bug on this - ID# 7364011
+    
+    CFRunLoopRef nullRunLoop = 0;
+    OSStatus err = AudioHardwareSetProperty (kAudioHardwarePropertyRunLoop, sizeof(CFRunLoopRef), &nullRunLoop);
+
+    if (err != kAudioHardwareNoError)
+    {
+        syslog (LOG_NOTICE, "Unable to set RunLoop for Audio Hardware");
+    }
+
+    //add a listener to find out when devices change...
+    AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, StaticPropertyChangeProc, this);
+
+    //Always add the None device first...
+    m_Devices.push_back (new WCMRNativeAudioNoneDevice(this));
+
+    //prepare our initial list...
+    UpdateDeviceList_Private();
+
+    return;
+}
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDeviceManager::~WCMRCoreAudioDeviceManager
+//
+//! It clears the device list, releasing each of the device.
+//!
+//! \param none
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+WCMRCoreAudioDeviceManager::~WCMRCoreAudioDeviceManager()
+{
+    AUTO_FUNC_DEBUG;
+
+    try
+    {
+        AudioHardwareRemovePropertyListener (kAudioHardwarePropertyDevices, StaticPropertyChangeProc);
+
+        //Note: We purposely release the device list here, instead of
+        //depending on the superclass to do it, as by the time the superclass'
+        //destructor executes, we will have called Pa_Terminate()!
+    
+        //Need to call release on our devices, and erase them from list
+        std::vector<WCMRAudioDevice*>::iterator deviceIter;
+        while (m_Devices.size())
+        {
+            WCMRAudioDevice *pDeviceToRelease = m_Devices.back();
+            m_Devices.pop_back();
+
+            SAFE_RELEASE (pDeviceToRelease);
+        }
+    
+        
+        //The derived classes may want to do additional de-int!
+
+    }
+    catch (...)
+    {
+        //destructors should absorb exceptions, no harm in logging though!!
+        DEBUG_MSG ("Exception during destructor");
+    }
+
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDeviceManager::StaticPropertyChangeProc
+//
+//! The property change listener for the Audio Device Manager. It calls upon (non-static) PropertyChangeProc
+//!     to do the actual work.
+//!
+//! \param iPropertyID : the property that has changed.
+//! \param inClientData : What was supplied at init time.
+//! 
+//! \return if parameters are incorrect, or the value returned by PropertyChangeProc.
+//! 
+//**********************************************************************************************
+OSStatus WCMRCoreAudioDeviceManager::StaticPropertyChangeProc (AudioHardwarePropertyID inPropertyID, void* inClientData)
+{
+    WCMRCoreAudioDeviceManager *pMyManager = (WCMRCoreAudioDeviceManager *)inClientData;
+    
+    if (pMyManager)
+        return pMyManager->PropertyChangeProc (inPropertyID);
+
+    return 0;
+}
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDeviceManager::PropertyChangeProc
+//
+//! The property change listener for the Audio Device Manager. Currently we only listen for the
+//!     device list change (device arrival/removal, and accordingly cause an update to the device list.
+//!     Note that the actual update happens from the DoIdle() call to prevent multi-threading related issues.
+//!
+//! \param 
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+OSStatus WCMRCoreAudioDeviceManager::PropertyChangeProc (AudioHardwarePropertyID inPropertyID)
+{
+    OSStatus retVal = 0;
+    switch (inPropertyID)
+    {
+    case kAudioHardwarePropertyDevices:
+        m_UpdateDeviceListRequested++;
+        break;
+    default:
+        break;
+    }
+    
+    return retVal;
+}
+
+//**********************************************************************************************
+// WCMRCoreAudioDeviceManager::remove_pattern
+//
+//! remove a substring from a given string
+//!
+//! \param original_str - original string
+//! \param pattern_str - pattern to find
+//! \param return_str - the return string - without the pattern substring
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+void WCMRCoreAudioDeviceManager::remove_pattern(const std::string& original_str, const std::string& pattern_str, std::string& return_str)
+{
+    char *orig_c_str = new char[original_str.size() + 1];
+    char* strSavePtr;
+    strcpy(orig_c_str, original_str.c_str());
+    char *p_splited_orig_str = strtok_r(orig_c_str," ", &strSavePtr);
+    
+    std::ostringstream stream_str;
+    while (p_splited_orig_str != 0) 
+    {
+        int cmp_res = strcmp(p_splited_orig_str, pattern_str.c_str()); // might need Ignore case ( stricmp OR strcasecmp)
+        if ( cmp_res != 0)
+            stream_str << p_splited_orig_str << " ";
+        p_splited_orig_str = strtok_r(NULL," ", &strSavePtr);
+    }
+    delete[] orig_c_str;
+    return_str = stream_str.str();
+}
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDeviceManager::UpdateDeviceList_Private
+//
+//! Updates the list of devices maintained by the manager. If devices have gone away, they are removed
+//!     if new devices have been connected, they are added to the list.
+//!
+//! \param none
+//! 
+//! \return eNoErr on success, an error code on failure.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDeviceManager::UpdateDeviceList_Private()
+{
+    AUTO_FUNC_DEBUG;
+    
+    
+    WTErr retVal = eNoErr;
+    OSStatus osErr = noErr;
+    AudioDeviceID* deviceIDs = 0;
+    size_t reportedDeviceIndex = 0;
+    
+    openlog("WCMRCoreAudioDeviceManager", LOG_PID | LOG_CONS, LOG_USER);
+
+    try 
+    {
+    
+        // Define 2 vectors for input and output - only for eMatchedDuplexDevices case
+        WCMRAudioDeviceList adOnlyIn;
+        WCMRAudioDeviceList adOnlyOut;
+    
+        //Get device count...
+        UInt32 propSize = 0;
+        osErr = AudioHardwareGetPropertyInfo (kAudioHardwarePropertyDevices, &propSize, NULL);
+        ASSERT_ERROR(osErr, "AudioHardwareGetProperty 1");
+        if (WUIsError(osErr))
+            throw osErr;
+    
+        size_t numDevices = propSize / sizeof (AudioDeviceID);
+        deviceIDs = new AudioDeviceID[numDevices];
+
+        //retrieve the device IDs
+        propSize = numDevices * sizeof (AudioDeviceID);
+        osErr = AudioHardwareGetProperty (kAudioHardwarePropertyDevices, &propSize, deviceIDs);
+        ASSERT_ERROR(osErr, "Error while getting audio devices: AudioHardwareGetProperty 2");
+        if (WUIsError(osErr))
+            throw osErr;
+    
+        //first go through our list of devices, remove the ones that are no longer present...
+        std::vector<WCMRAudioDevice*>::iterator deviceIter;
+        for (deviceIter = m_Devices.begin(); deviceIter != m_Devices.end(); /*This is purposefully blank*/)
+        {
+            WCMRCoreAudioDevice *pDeviceToWorkUpon = dynamic_cast<WCMRCoreAudioDevice *>(*deviceIter);
+
+            //it's possible that the device is actually not a core audio device - perhaps a none device...
+            if (!pDeviceToWorkUpon)
+            {
+                deviceIter++;
+                continue;
+            }
+
+            AudioDeviceID myDeviceID = pDeviceToWorkUpon->DeviceID();
+            bool deviceFound = false;
+            for (reportedDeviceIndex = 0; reportedDeviceIndex < numDevices; reportedDeviceIndex++)
+            {
+                if (myDeviceID == deviceIDs[reportedDeviceIndex])
+                {
+                    deviceFound = true;
+                    break;
+                }
+            }
+        
+            if (!deviceFound)
+            {
+                //it's no longer there, need to remove it!
+                WCMRAudioDevice *pTheDeviceToErase = *deviceIter;
+                deviceIter = m_Devices.erase (deviceIter);
+                if (pTheDeviceToErase->Active())
+                {
+                    NotifyClient (WCMRAudioDeviceManagerClient::DeviceConnectionLost);
+                }
+                SAFE_RELEASE (pTheDeviceToErase);
+            }
+            else
+                deviceIter++;
+        }
+
+        //now add the ones that are not there...
+        for (reportedDeviceIndex = 0; reportedDeviceIndex < numDevices; reportedDeviceIndex++)
+        {
+            bool deviceFound = false;
+            for (deviceIter = m_Devices.begin(); deviceIter != m_Devices.end(); deviceIter++)
+            {
+                WCMRCoreAudioDevice *pDeviceToWorkUpon = dynamic_cast<WCMRCoreAudioDevice *>(*deviceIter);
+                //it's possible that the device is actually not a core audio device - perhaps a none device...
+                if (!pDeviceToWorkUpon)
+                    continue;
+
+                if (pDeviceToWorkUpon->DeviceID() == deviceIDs[reportedDeviceIndex])
+                {
+                    deviceFound = true;
+                    break;
+                }
+            }
+        
+            if (!deviceFound)
+            {
+                //add it to our list...
+                //build a device object...
+                WCMRCoreAudioDevice *pNewDevice = new WCMRCoreAudioDevice (this, deviceIDs[reportedDeviceIndex], m_UseMultithreading, m_bNoCopyAudioBuffer);
+                bool bDeleteNewDevice = true;
+                
+                if (pNewDevice)
+                {
+
+                    // Don't delete the new device by default, since most cases use it
+                    bDeleteNewDevice = false;
+                    
+                    // Insert the new device to the device list according to its enum
+                    switch(m_eAudioDeviceFilter)
+                    {
+                    case eInputOnlyDevices:
+                        if ((int) pNewDevice->InputChannels().size() != 0)
+                        {
+                            m_Devices.push_back (pNewDevice);
+                        }
+                        else
+                        {
+                            // Delete unnecesarry device
+                            bDeleteNewDevice = true;
+                        }
+                        break;
+                    case eOutputOnlyDevices:
+                        if ((int) pNewDevice->OutputChannels().size() != 0)
+                        {
+                            m_Devices.push_back (pNewDevice);
+                        }
+                        else
+                        {
+                            // Delete unnecesarry device
+                            bDeleteNewDevice = true;
+                        }
+                        break;
+                    case eFullDuplexDevices:
+                        if ((int) pNewDevice->InputChannels().size() != 0 && (int) pNewDevice->OutputChannels().size() != 0)
+                        {
+                            m_Devices.push_back (pNewDevice);
+                        }
+                        else
+                        {
+                            // Delete unnecesarry device
+                            bDeleteNewDevice = true;
+                        }
+                        break;
+                    case eAllDevices:
+                    default:
+                        m_Devices.push_back (pNewDevice);
+                        break;
+                    }
+                }
+                
+                if(bDeleteNewDevice)
+                {
+                    syslog (LOG_NOTICE, "%s rejected, In Channels = %d, Out Channels = %d\n",
+                            pNewDevice->DeviceName().c_str(), (int) pNewDevice->InputChannels().size(),
+                            (int) pNewDevice->OutputChannels().size());
+                    // In case of Input and Output both channels being Zero, we will release memory; since we created CoreAudioDevice but we are Not adding it in list.
+                    SAFE_RELEASE(pNewDevice);
+                }
+            }
+        }
+    
+
+        //If no devices were found, that's not a good thing!
+        if (m_Devices.empty())
+        {
+            DEBUG_MSG ("No matching CoreAudio devices were found\n");
+        }
+    
+
+        m_UpdateDeviceListRequested = m_UpdateDeviceListProcessed = 0;
+    
+    }
+    catch (...)
+    {
+        if (WUNoError(retVal))
+            retVal = eCoreAudioFailed;
+    }
+
+    safe_delete_array(deviceIDs);
+    closelog();
+
+    return retVal;
+}
+
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDeviceManager::DoIdle
+//
+//! Used for idle time processing. This calls each device's DoIdle so that it can perform it's own idle processing.
+//!     Also, if a device list change is detected, it updates the device list.
+//!
+//! \param none
+//! 
+//! \return noErr if no devices have returned an error. An error code if any of the devices returned error.
+//! 
+//**********************************************************************************************
+WTErr WCMRCoreAudioDeviceManager::DoIdle()
+{
+    //WTErr retVal = eNoErr;
+    
+    {
+        //wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+
+        //If there's something specific to CoreAudio manager idle handling do it here...
+        if (m_UpdateDeviceListRequested != m_UpdateDeviceListProcessed)
+        {
+            m_UpdateDeviceListProcessed = m_UpdateDeviceListRequested;
+            UpdateDeviceList_Private();
+            NotifyClient (WCMRAudioDeviceManagerClient::DeviceListChanged);
+        }
+    }   
+
+    //Note that the superclass is going to call all the devices' DoIdle() anyway...
+    return (WCMRAudioDeviceManager::DoIdle());
+}
+
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h
new file mode 100644 (file)
index 0000000..96d2a9d
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+//----------------------------------------------------------------------------------
+//
+//
+//! \file      WCMRCoreAudioDeviceManager.h
+//!
+//! WCMRCoreAudioDeviceManager and related class declarations
+//!
+//---------------------------------------------------------------------------------*/
+#ifndef __WCMRCoreAudioDeviceManager_h_
+       #define __WCMRCoreAudioDeviceManager_h_
+
+#include "WCMRAudioDeviceManager.h"
+#include "WCMRNativeAudio.h"
+#include "Threads/WCThreadSafe.h"
+
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/AudioToolbox.h>
+
+#include <mach/mach.h>
+
+#include <CoreAudio/CoreAudio.h> 
+
+//forward decl.
+class WCMRCoreAudioDeviceManager;
+
+#define WV_USE_TONE_GEN 0 ///! Set this to 1 to use a tone generator for input. See description at SetupToneGenerator for details.
+
+// This enum is for choosing filter for audio devices scan
+typedef enum eCABS_Method
+{
+       eCABS_Simple = 0,       
+       eCABS_DestructiveCache,
+       eCABS_CacheOnDeviceSet,    
+       eCABS_MethodNum // Must be last
+}      eCABS_Method;
+
+//! Manages a port audio device, providing information
+//! about the device, and managing audio callbacks.
+class WCMRCoreAudioDevice : public WCMRNativeAudioDevice
+{
+public:
+
+       WCMRCoreAudioDevice (WCMRCoreAudioDeviceManager *pManager, AudioDeviceID deviceID, bool useMultithreading = true, bool bNocopy = false);///<Constructor
+       virtual ~WCMRCoreAudioDevice ();///<Destructor
+
+       virtual const std::string& DeviceName() const;///<Name?
+       virtual const std::vector<std::string>& InputChannels();///<Current Input Channel List? - note that this may change with change in sampling rate.
+       virtual const std::vector<std::string>& OutputChannels();///<Current Output Channel List? - note that this may change with change in sampling rate.
+    
+    
+       virtual const std::vector<int>& SamplingRates();///<Supported Sampling Rate List?
+       virtual int CurrentSamplingRate(); ///<Current Sampling rate.?
+       virtual WTErr SetCurrentSamplingRate(int newRate);///<Change Current Sampling Rate : This is a requset, might not be successful at run time!
+
+       virtual const std::vector<int>& BufferSizes();///<Supported Buffer Size List? - note that this may change with change in sampling rate.
+       virtual int CurrentBufferSize();///<Current Buffer Size.? - note that this may change with change in sampling rate.
+       virtual WTErr SetCurrentBufferSize (int newSize);///<Change Current Buffer Size : This is a requset, might not be successful at run time!
+
+       virtual ConnectionStates ConnectionStatus();///< Connection Status - device available, gone, disconnected
+
+       virtual WTErr SetActive (bool newState);///<Prepare/Activate device.
+       virtual WTErr SetStreaming (bool newState);///<Start/Stop Streaming - should reconnect connections when streaming starts!
+
+       virtual WTErr DoIdle();///<Do Idle Processing
+       
+       virtual WTErr SetMonitorChannels (int leftChannel, int rightChannel);///<Set monitor channels. - optional, will not be available with AG
+       virtual WTErr SetMonitorGain (float newGain);///<Set monitor gain. - optional, will not be available with AG
+       
+       virtual WTErr ShowConfigPanel (void *pParam);///< Show Control Panel - in case of ASIO this will work only with Active device!
+
+       virtual int AudioCallback (float *pOutputBuffer, unsigned long framesPerBuffer, uint32_t inSampleTime, uint64_t inCycleStartTime);
+       
+       AudioDeviceID DeviceID () {return m_DeviceID;}
+    
+    virtual uint32_t GetLatency (bool isInput); ///< Get latency.
+    virtual OSStatus GetStreamLatency(AudioDeviceID deviceID, bool isInput, std::vector<int>& latencies);
+
+    
+protected:
+
+       AudioDeviceID m_DeviceID; ///< The CoreAudio device id
+       bool m_StopRequested; ///< should be set to true when want to stop, set to false otherwise.
+       float *m_pInputData; ///< This is what came in with the most recent callback.
+       int m_SampleCounter; ///< The current running sample counter, updated by the audio callback.
+       int m_SampleCountAtLastIdle; ///< What was the sample count last time we checked...
+       int m_StalledSampleCounter; ///< The number of idle calls with same sample count detected
+       int m_ChangeCheckCounter; ///< The number of idle calls passed since we checked the buffer size change.
+
+       wvNS::wvThread::timestamp m_LastCPULog; ///< The time when the last CPU details log was sent as a notification.
+//     unsigned int m_IOCyclesTimesTaken[MAX_IOCYCLE_TIMES]; ///< This stores the times taken by each IOCycle, in host-time units.
+//     int m_CurrentIOCycle; ///< The location in m_IOCyclesTymesTaken array, where the next cycle's value will go.
+//     int m_CyclesToAccumulate; ///< The number of cycles to accumulate the values for - maximum for last one second.
+//     unsigned int m_CyclePeriod; ///< The number of host time units for a cycle period - determined by buffer size and sampling rate
+       
+       
+       
+       AudioBufferList m_InputAudioBufferList; ///< The buffer list used to get AHHAL to render input to.
+       AudioUnit m_AUHALAudioUnit;///< The AUHAL AudioUnit
+
+       int m_BufferSizeChangeRequested;
+       int m_BufferSizeChangeReported;
+       int m_ResetRequested;
+       int m_ResetReported;
+       int m_ResyncRequested;
+       int m_ResyncReported;
+       int m_SRChangeRequested;
+       int m_SRChangeReported;
+
+       int m_DropsDetected; ///< Number of times audio drops have been detected so far.
+       int m_DropsReported; ///< Number of times audio drops have been reported so far to the client.
+       bool m_IgnoreThisDrop; ///< Allows disregarding the first drop
+
+       thread_t m_IOProcThreadPort; ///< Thread handle to calculate CPU consumption.
+       int m_CPUCount; ///< Number of processors/core to normalize cpu consumption calculation.
+
+#if WV_USE_TONE_GEN
+       //The Tone Generator...
+       float_t *m_pToneData;
+       uint32_t m_ToneDataSamples;
+       uint32_t m_NextSampleToUse;
+#endif //WV_USE_TONE_GEN
+       
+       WTErr UpdateDeviceInfo (bool updateSRSupported, bool updateBufferSizes);
+       WTErr UpdateDeviceName();
+       WTErr UpdateDeviceInputs();
+       WTErr UpdateDeviceOutputs();
+       WTErr UpdateDeviceSampleRates();
+       WTErr UpdateDeviceBufferSizes();
+       WTErr SetWorkingBufferSize(int newSize);
+       OSStatus SetBufferSizesByIO(int newSize);
+       WTErr SetAndCheckCurrentSamplingRate (int newRate);
+
+       WTErr EnableAudioUnitIO();
+       WTErr virtual EnableListeners();
+       WTErr virtual DisableListeners();
+       WTErr SetupAUHAL();
+       WTErr TearDownAUHAL();
+
+#if WV_USE_TONE_GEN
+       void SetupToneGenerator ();
+#endif //WV_USE_TONE_GEN
+       
+       static OSStatus StaticAudioIOProc(void *inRefCon, AudioUnitRenderActionFlags *  ioActionFlags,
+               const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
+               AudioBufferList *ioData);
+       OSStatus AudioIOProc(AudioUnitRenderActionFlags *       ioActionFlags,
+               const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
+               AudioBufferList *ioData);
+               
+       static OSStatus StaticPropertyChangeProc (AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput,
+       AudioDevicePropertyID inPropertyID, void *inClientData);
+       void PropertyChangeProc (AudioDevicePropertyID inPropertyID);
+    
+private:
+
+};
+
+
+//! WCMRCoreAudioDeviceManager
+/*! The CoreAudio Device Manager class */
+class WCMRCoreAudioDeviceManager : public WCMRAudioDeviceManager
+{
+public:
+
+       WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter,
+               bool useMultithreading = true, eCABS_Method eCABS_method = eCABS_Simple, bool bNocopy = false); ///< constructor
+       virtual ~WCMRCoreAudioDeviceManager(void); ///< Destructor
+       
+
+       virtual WTErr UpdateDeviceList() //has to be overridden!
+    {
+                       //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+        return UpdateDeviceList_Private();
+    }
+
+       virtual eCABS_Method GetBufferSizeMethod()
+    { 
+                       //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+        return GetBufferSizeMethod_Private();
+    }
+       
+       virtual WTErr DoIdle();
+       
+private:
+    WTErr UpdateDeviceList_Private();
+    eCABS_Method GetBufferSizeMethod_Private() { return m_eCABS_Method; }
+
+protected:
+
+       int m_UpdateDeviceListRequested; ///< Number of times device list change has been detected.
+       int m_UpdateDeviceListProcessed; ///< Number of times device list change has been processed.
+       bool m_UseMultithreading; ///< Flag indicates whether to use multi-threading for audio processing.
+    bool m_bNoCopyAudioBuffer;
+       eCABS_Method m_eCABS_Method; // Type of core audio buffer size list method
+
+       static OSStatus StaticPropertyChangeProc (AudioHardwarePropertyID inPropertyID, void* inClientData);
+       OSStatus PropertyChangeProc (AudioHardwarePropertyID inPropertyID);
+
+       void remove_pattern(const std::string& original_str, const std::string& pattern_str, std::string& return_str);
+};
+
+#endif //#ifndef __WCMRCoreAudioDeviceManager_h_
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.cpp b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.cpp
new file mode 100644 (file)
index 0000000..0cba7ee
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+//----------------------------------------------------------------------------------
+//
+//
+//! \file      WCMRNativeAudio.cpp
+//!
+//! WCMRNativeAudioConnection and related class defienitions
+//!
+//---------------------------------------------------------------------------------*/
+#if defined(__MACOS__)
+#include <CoreAudio/CoreAudio.h>
+#endif
+
+#include "WCMRNativeAudio.h"
+#include "MiscUtils/safe_delete.h"
+#include <sstream>
+#include <boost/assign/list_of.hpp>
+
+#define NONE_DEVICE_NAME "None"
+#define NONE_DEVICE_INPUT_NAMES "Input "
+#define NONE_DEVICE_OUTPUT_NAMES "Output "
+
+//**********************************************************************************************
+// WCMRNativeAudioNoneDevice::WCMRNativeAudioNoneDevice
+//
+//! Constructor for the dummy "None" device. This constructor simply adds supported SRs,
+//!            buffer sizes, and channels, so that it may look like a real native device to
+//!            the applications.
+//!
+//! \param pManager : The managing device manager - simply passed on to the base class.
+//! 
+//! 
+//**********************************************************************************************
+WCMRNativeAudioNoneDevice::WCMRNativeAudioNoneDevice (WCMRAudioDeviceManager *pManager)
+       : WCMRNativeAudioDevice (pManager, false /*useMultiThreading*/)
+       , m_SilenceThread(0)
+#if defined (_WINDOWS)
+    , _waitableTimerForUsleep (CreateWaitableTimer(NULL, TRUE, NULL))
+#endif
+{
+       m_DeviceName = NONE_DEVICE_NAME;
+
+       m_SamplingRates = boost::assign::list_of (m_CurrentSamplingRate=44100)(48000)(88200)(96000);
+
+       m_BufferSizes = boost::assign::list_of (32)(64)(128)(m_CurrentBufferSize=256)(512)(1024);
+
+       for (int channel = 0; channel < __m_NumInputChannels; channel++)
+       {
+        std::stringstream name;
+        name << NONE_DEVICE_INPUT_NAMES;
+               name << (channel + 1);
+               m_InputChannels.push_back(name.str());
+       }
+
+       for (int channel = 0; channel < __m_NumOutputChannels; channel++)
+       {
+        std::stringstream name;
+        name << NONE_DEVICE_INPUT_NAMES;
+               name << (channel + 1);
+               m_OutputChannels.push_back(name.str());
+       }
+       _m_inputBuffer = new float[__m_NumInputChannels * m_BufferSizes.back()];
+       _m_outputBuffer = new float[__m_NumOutputChannels * m_BufferSizes.back()];
+}
+
+
+WCMRNativeAudioNoneDevice::~WCMRNativeAudioNoneDevice ()
+{
+#if defined (_WINDOWS)
+    if(_waitableTimerForUsleep) {
+        CloseHandle(_waitableTimerForUsleep);
+    }
+#endif
+}
+
+WTErr WCMRNativeAudioNoneDevice::SetActive (bool newState)
+{
+       //This will most likely be overridden, the base class simply
+       //changes the member.
+       if (Active() == newState)
+       {
+               return (eNoErr);
+       }
+
+       if (Active() && Streaming())
+       {
+               SetStreaming(false);
+       }
+       return WCMRAudioDevice::SetActive(newState);
+}
+
+WTErr WCMRNativeAudioNoneDevice::SetCurrentBufferSize (int newSize)
+{
+
+       //changes the status.
+       int oldSize = CurrentBufferSize();
+       bool oldActive = Active();
+
+       //same size, nothing to do.
+       if (oldSize == newSize)
+               return eNoErr;
+       
+       //see if this is one of our supported rates...
+       std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize);
+       if (intIter == m_BufferSizes.end())
+       {
+               //Can't change, perhaps use an "invalid param" type of error
+               return eCommandLineParameter;
+       }
+       
+       if (Streaming())
+       {
+               //Can't change, perhaps use an "in use" type of error
+               return eGenericErr;
+       }
+
+       
+       return WCMRAudioDevice::SetCurrentBufferSize(newSize);
+}
+
+
+WTErr WCMRNativeAudioNoneDevice::SetStreaming (bool newState)
+{
+       if (Streaming() == newState)
+       {
+               return (eNoErr);
+       }
+
+       WCMRAudioDevice::SetStreaming(newState);
+       if(Streaming())
+       {
+               if (m_SilenceThread)
+                       std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the inactive NONE-DEVICE was streaming!" << std::endl;
+
+               pthread_attr_t attributes;
+               size_t stack_size = 100000;
+#ifdef __MACOS__
+           stack_size = (((stack_size - 1) / PTHREAD_STACK_MIN) + 1) * PTHREAD_STACK_MIN;
+#endif
+               if (pthread_attr_init (&attributes)) {
+                       std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_attr_init () failed!" << std::endl;
+                       return eGenericErr;
+               }
+   
+               if (pthread_attr_setstacksize (&attributes, stack_size)) {
+                       std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_attr_setstacksize () failed!" << std::endl;
+                       return eGenericErr;
+               }
+
+               if (pthread_create (&m_SilenceThread, &attributes, __SilenceThread, this)) {
+                       m_SilenceThread = 0;
+                       std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_create () failed!" << std::endl;
+                       return eGenericErr;
+               }
+       }
+       else
+       {
+               if (!m_SilenceThread)
+               {
+                       std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the active NONE-DEVICE was NOT streaming!" << std::endl;
+               }
+
+               while (m_SilenceThread)
+               {
+                       _usleep(1); //now wait for ended  thread;
+               }
+       }
+
+       return eNoErr;
+}
+
+void WCMRNativeAudioNoneDevice::_SilenceThread()
+{
+#if defined(_WINDOWS)
+       float* theInpBuffers[__m_NumInputChannels];
+       for(int i = 0; i < __m_NumInputChannels; ++i)
+       {
+               theInpBuffers[i] = _m_inputBuffer + m_BufferSizes.back() * i;
+       }
+#else
+       float* theInpBuffers = _m_inputBuffer;
+#endif
+
+    uint32_t currentSampleTime = 0;    
+       const size_t buffer_size = CurrentBufferSize();
+    const uint64_t cyclePeriodNanos = (1000000000.0 * buffer_size) / CurrentSamplingRate();
+
+       struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData =
+       {
+               (const float*)theInpBuffers,
+               _m_outputBuffer,
+               buffer_size,
+               0, 
+               0
+       };
+
+       audioCallbackData.acdCycleStartTimeNanos =__get_time_nanos();
+
+    // VERY ROUGH IMPLEMENTATION: 
+    while(Streaming()) {
+       
+        uint64_t cycleEndTimeNanos = audioCallbackData.acdCycleStartTimeNanos + cyclePeriodNanos;
+
+               m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData);
+               
+        currentSampleTime += buffer_size;
+               
+               int64_t timeToSleepUsecs = ((int64_t)cycleEndTimeNanos - (int64_t)__get_time_nanos())/1000;
+               
+        if (timeToSleepUsecs > 0) {
+            _usleep (timeToSleepUsecs);
+        }
+               audioCallbackData.acdCycleStartTimeNanos = cycleEndTimeNanos+1;
+    }
+       m_SilenceThread = 0;
+}
+
+void* WCMRNativeAudioNoneDevice::__SilenceThread(void *This)
+{
+       ((WCMRNativeAudioNoneDevice*)This)->_SilenceThread();
+       return 0;
+}
+
+#if defined(_WINDOWS)
+void WCMRNativeAudioNoneDevice::_usleep(uint64_t duration_usec)
+{ 
+    LARGE_INTEGER ft; 
+
+    ft.QuadPart = -(10*duration_usec); // Convert to 100 nanosecond interval, negative value indicates relative time
+
+    SetWaitableTimer(_waitableTimerForUsleep, &ft, 0, NULL, NULL, 0);
+    WaitForSingleObject(_waitableTimerForUsleep, INFINITE); 
+}
+#endif
+
+uint64_t
+WCMRNativeAudioNoneDevice::__get_time_nanos ()
+{
+#ifdef __MACOS__
+    // here we exploit the time counting API which is used by the WCMRCoreAudioDeviceManager. However,
+    // the API should be a part of WCMRCoreAudioDeviceManager to give a chance of being tied to the
+    // audio device transport time�.
+    return AudioConvertHostTimeToNanos (AudioGetCurrentHostTime ());
+    
+#elif _WINDOWS
+    
+    LARGE_INTEGER Frequency, Count ;
+
+    QueryPerformanceFrequency (&Frequency) ;
+    QueryPerformanceCounter (&Count);
+    return uint64_t ((Count.QuadPart * 1000000000.0 / Frequency.QuadPart));
+#endif
+}
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.h b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.h
new file mode 100644 (file)
index 0000000..dc350ff
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+//----------------------------------------------------------------------------------
+//
+//
+//! \file      WCMRNativeAudio.h
+//!
+//! WCMRNativeAudio and related class declarations
+//!
+//---------------------------------------------------------------------------------*/
+#ifndef __WCMRNativeAudio_h_
+       #define __WCMRNativeAudio_h_
+
+#if defined(_WINDOWS)
+#include "windows.h"
+#endif
+#include "pthread.h"
+#include "WCRefManager.h"
+#include "WCMRAudioDeviceManager.h"
+
+class WCMRNativeAudioDevice; //forward
+
+
+
+class WCMRNativeAudioDevice : public WCMRAudioDevice
+{
+public:
+
+       WCMRNativeAudioDevice (WCMRAudioDeviceManager *pManager, bool useMultithreading = true, bool bNoCopy = false) : WCMRAudioDevice (pManager), 
+               m_UseMultithreading (useMultithreading),
+        m_bNoCopyAudioBuffer(bNoCopy)
+               {}
+       virtual ~WCMRNativeAudioDevice () {}
+
+protected:
+       bool m_UseMultithreading;
+    bool m_bNoCopyAudioBuffer; ///< This flag determines whether the audio callback performs a copy of audio, or the source/sink perform the copy. It should be true to let source/sink do the copies.
+
+
+};
+
+
+//! A dummy device to allow apps to choose "None" in case no real device connection is required.
+class WCMRNativeAudioNoneDevice : public WCMRNativeAudioDevice
+{
+public:
+    WCMRNativeAudioNoneDevice (WCMRAudioDeviceManager *pManager);
+    virtual ~WCMRNativeAudioNoneDevice ();
+       virtual WTErr SetActive (bool newState);///<Prepare/Activate device.
+       virtual WTErr SetStreaming (bool newState);///<Start/Stop Streaming - should reconnect connections when streaming starts!
+       virtual WTErr SetCurrentBufferSize (int newSize);///<Change Current Buffer Size : This is a requset, might not be successful at run time!
+
+private:
+
+       static void* __SilenceThread(void *This);
+       void _SilenceThread();
+#if defined(_WINDOWS)
+       void _usleep(uint64_t usec);
+#else
+       inline void _usleep(uint64_t usec) { ::usleep(usec); }
+#endif
+    static const size_t __m_NumInputChannels = 32;
+    static const size_t __m_NumOutputChannels = 32;
+       pthread_t m_SilenceThread;
+    float *_m_inputBuffer;\r
+    float *_m_outputBuffer;\r
+    static uint64_t __get_time_nanos ();
+#if defined (_WINDOWS)
+       HANDLE _waitableTimerForUsleep;
+#endif
+};
+
+
+#endif //#ifndef __WCMRNativeAudio_h_
diff --git a/libs/backends/wavesaudio/wavesapi/miscutils/MinMaxUtilities.h b/libs/backends/wavesaudio/wavesapi/miscutils/MinMaxUtilities.h
new file mode 100644 (file)
index 0000000..cd48169
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __MinMaxUtilities_h__
+#define __MinMaxUtilities_h__
+
+/* copy to include
+#include "MiscUtils/MinMaxUtilities.h"
+*/
+
+#include "BasicTypes/WUDefines.h"
+#include "BasicTypes/WUMathConsts.h"
+#include "WavesPublicAPI/wstdint.h"
+
+// New accelerated templates
+#if defined ( __cplusplus ) && !defined (__WUMinMax)
+#define __WUMinMax   // Also defined in Nativepr.h
+
+
+template<class T> inline T WUMin(const T &a, const T &b) {return (a < b) ? a : b;} // requires only < to be defined for T
+template<class T> inline T WUMax(const T &a,const T &b) {return (a < b) ? b : a;} // requires only < to be defined for T
+template<class T> inline T WUMinMax(const T &Smallest, const T &Biggest, const T &Val)  // requires only < to be defined for T
+{      
+       return ((Val < Smallest) ? Smallest : ((Biggest < Val) ? Biggest : Val));
+}
+/*     
+// Min and Max
+       template<class T> inline T WUMin(T a,T b) {return (a < b) ? a : b;} // requires only < to be defined for T
+       template<class T> inline T WUMax(T a,T b) {return (a < b) ? b : a;} // requires only < to be defined for T
+       template<class T> inline T WUMinMax(T SMALLEST, T BIGGEST, T X)  // requires only < to be defined for T
+       {
+               return ((X < SMALLEST) ? SMALLEST : ((BIGGEST < X) ? BIGGEST : X));
+       }
+ */    
+// Absolute value
+#ifdef _WINDOWS
+       #include <math.h>
+#define __abs(x)       abs(x) 
+#define __labs(x)      labs(x)
+#define __fabs(x)      fabs(x)
+#endif
+#ifdef __GNUC__
+       #include <iostream> // why don't know makes it work need to check
+       #include <cstdlib>
+       #include <cmath>
+
+#define __abs(x)       std::abs(x)
+#define __labs(x)      std::labs(x)
+#define __fabs(x)      std::fabs(x)
+#endif
+       #ifdef __MACOS__
+        #ifdef __GNUC__
+            #include <iostream> // why don't know makes it work need to check
+            #include <cmath>
+#define __abs(x)       std::abs(x)
+#define __labs(x)      std::labs(x)
+#define __fabs(x)      std::fabs(x)
+        #endif
+       #endif
+
+// log2: on Windows there's no proper definition for log2, whereas on other platform there is.
+       #ifndef WUlog2
+    #if defined(_WINDOWS)
+        #define WUlog2(x)  (kdOneOverLog2 * log10((x))) 
+    #else    
+        #define WUlog2(x) log2(x)
+    #endif
+    #endif
+
+template <class T> inline T WUAbs(const T &xA)
+{
+       return (xA > T(0))? xA: -xA;
+}
+
+template <> inline int WUAbs(const int &xA)
+{
+       return __abs(xA);
+}
+
+//template <> inline int32_t WUAbs(const int32_t &xA)// 64BitConversion
+//{
+//     return __labs(xA);
+//}
+
+template <> inline float WUAbs(const float &xA)
+{
+       return (float) __fabs(xA);
+}
+
+template <> inline double WUAbs(const double &xA)
+{
+       return __fabs(xA);
+}
+
+#endif
+
+int32_t DllExport WURand(intptr_t in_Seed);
+int32_t DllExport WURand();
+int32_t DllExport rand_gen_formula(int32_t rndSeed);
+
+template <class T> inline bool WUIsEqualWithTolerance(const T &xA, const T &xB, const T &xTolerance)
+{
+       return (WUAbs(xA - xB) < xTolerance) ? true : false;
+}
+
+
+#endif
diff --git a/libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.cpp b/libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.cpp
new file mode 100644 (file)
index 0000000..e3de715
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifdef _WINDOWS\r
+    #include "IncludeWindows.h"\r
+#endif\r
+#if defined(__linux__) || defined(__MACOS__)\r
+       #include <sys/time.h>\r
+#endif\r
+\r
+#include "UMicroseconds.h"\r
+\r
+namespace wvNS { \r
+UMicroseconds& UMicroseconds::ReadTime()\r
+{\r
+#ifdef _WINDOWS\r
+       LARGE_INTEGER Frequency, Count ;\r
+\r
+       QueryPerformanceFrequency(&Frequency) ;\r
+       QueryPerformanceCounter(&Count);\r
+       theTime = uint64_t((Count.QuadPart * 1000000.0 / Frequency.QuadPart));\r
+#endif\r
+\r
+#if defined(__linux__) || defined(__MACOS__)\r
+//     Mac code replaced by posix calls, to reduce Carbon dependency. \r
+       timeval buf;\r
+\r
+       gettimeofday(&buf,NULL);\r
+\r
+       // micro sec\r
+       theTime = uint64_t(buf.tv_sec) * 1000*1000 + buf.tv_usec;\r
+#endif\r
+\r
+       return *this;\r
+}\r
+/*\r
+ Removed in favor of the posix implementation. \r
+#ifdef __MACOS__\r
+       uint32_t UMicroseconds::hi() {return reinterpret_cast<UnsignedWide*>(&theTime)->hi;}\r
+       uint32_t UMicroseconds::lo() {return reinterpret_cast<UnsignedWide*>(&theTime)->lo;}\r
+#endif\r
+*/\r
+void UMicrosecondsAccumulator::Start()\r
+{\r
+       m_start_time.ReadTime();\r
+}\r
+\r
+void UMicrosecondsAccumulator::Stop()\r
+{\r
+       UMicroseconds stop_time;\r
+       \r
+       m_accumulator += stop_time.GetNativeTime() - m_start_time.GetNativeTime();\r
+}\r
+\r
+void UMicrosecondsAccumulator::Clear()\r
+{\r
+       m_start_time = 0;\r
+       m_accumulator = 0;\r
+}\r
+\r
+UMicroseconds UMicrosecondsAccumulator::GetAccumulatedTime() const\r
+{\r
+       return m_accumulator;\r
+}\r
+\r
+UMicrosecondsAccumulator& UMicrosecondsAccumulator::operator+=(const UMicrosecondsAccumulator& inaccum_to_add)\r
+{\r
+       m_accumulator += inaccum_to_add.GetAccumulatedTime();\r
+       return *this;\r
+}\r
+       \r
+} // namespace wvNS { \r
diff --git a/libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.h b/libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.h
new file mode 100644 (file)
index 0000000..64d1f88
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __UMicroseconds_h__\r
+       #define __UMicroseconds_h__\r
+       \r
+/* Copy to include\r
+#include "UMicroseconds.h"\r
+*/\r
+\r
+\r
+\r
+#include "BasicTypes/WUDefines.h"\r
+#include "BasicTypes/WUTypes.h"\r
+\r
+namespace wvNS { \r
+// a wraper for Microseconds function from Timer.h\r
+class DllExport UMicroseconds\r
+{\r
+public:\r
+\r
+#ifdef _WINDOWS\r
+       typedef int64_t TimeKeeper;\r
+#endif\r
+#ifdef __MACOS__\r
+       typedef uint64_t TimeKeeper;\r
+#endif\r
+#ifdef __linux__\r
+       typedef uint64_t TimeKeeper;\r
+#endif\r
+\r
+private:\r
+       TimeKeeper theTime;\r
+\r
+public:\r
+\r
+       UMicroseconds()\r
+       {\r
+               ReadTime();\r
+       }\r
+\r
+       UMicroseconds(const TimeKeeper in_initVal) : theTime(in_initVal) {}\r
+\r
+       UMicroseconds(const UMicroseconds& inUM) : theTime(inUM.theTime) {}\r
+       UMicroseconds& operator=(const UMicroseconds& inUM) {theTime = inUM.theTime;  return *this;}\r
+       UMicroseconds& operator+=(const TimeKeeper in_timeToAdd)  {theTime += in_timeToAdd;  return *this;}\r
+\r
+       UMicroseconds& ReadTime();\r
+  \r
+       TimeKeeper GetNativeTime() const {return theTime;}\r
+       operator uint64_t () {return static_cast<uint64_t>(theTime);}\r
+       operator double () const {return static_cast<const double>(theTime);}\r
+\r
+       double Seconds() const {return static_cast<double>(theTime) / double(1000000);}\r
+       double MilliSeconds() const {return static_cast<double>(theTime) / double(1000);}\r
+       double MicroSeconds() const {return static_cast<double>(theTime);}\r
+\r
+#ifdef __MACOS__\r
+       uint32_t hi();\r
+       uint32_t lo();\r
+#endif\r
+};\r
+\r
+inline UMicroseconds operator-(const UMicroseconds& in_one, const UMicroseconds& in_two)\r
+{\r
+       UMicroseconds retVal(in_one.GetNativeTime() - in_two.GetNativeTime());\r
+       return retVal;\r
+}\r
+\r
+class UMicrosecondsAccumulator\r
+{\r
+public:\r
+       UMicrosecondsAccumulator() : m_start_time(0), m_accumulator(0) {}\r
+       \r
+       void Start();\r
+       void Stop();\r
+       void Clear();\r
+       \r
+       UMicroseconds GetAccumulatedTime() const;\r
+       \r
+       UMicrosecondsAccumulator& operator+=(const UMicrosecondsAccumulator&);\r
+       \r
+protected:\r
+       UMicroseconds m_start_time;\r
+       UMicroseconds m_accumulator;\r
+};\r
+\r
+inline UMicroseconds operator-(const UMicrosecondsAccumulator& in_one, const UMicrosecondsAccumulator& in_two)\r
+{\r
+       UMicroseconds retVal(in_one.GetAccumulatedTime() - in_two.GetAccumulatedTime());\r
+       return retVal;\r
+}\r
+\r
+//=========================================================================================//\r
+inline void MicrosecondDelay(double amt)\r
+//=========================================================================================//\r
+{\r
+       UMicroseconds than;\r
+       UMicroseconds now;\r
+\r
+       do\r
+       {\r
+               now.ReadTime();\r
+       }       while ((now.MicroSeconds() - than.MicroSeconds()) < amt);\r
+}\r
+       \r
+} // namespace wvNS { \r
+#endif //#ifndef __UMicroseconds_h__\r
diff --git a/libs/backends/wavesaudio/wavesapi/miscutils/WCFixedString.h b/libs/backends/wavesaudio/wavesapi/miscutils/WCFixedString.h
new file mode 100644 (file)
index 0000000..4c7264b
--- /dev/null
@@ -0,0 +1,903 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __WCFixedString_h__
+       #define __WCFixedString_h__
+
+/* Copy to include.
+#include "WCFixedString.h"
+*/
+// do not #include anything else here but standard C++ library files, this file should be free from any and all depandencies
+// do not put any DEBUG_s or TRACE_s in this file, since it is used in BgkConsole functions
+
+#include <algorithm>
+#include <cctype>
+#include <cstring>
+#include <cstdio>
+
+#ifdef __MACOS__
+#include <strings.h>
+#endif
+
+#include "BasicTypes/WUDefines.h"
+#include "BasicTypes/WTByteOrder.h"
+#include "WavesPublicAPI/wstdint.h"
+#include "MiscUtils/MinMaxUtilities.h"
+
+// use this macro instead of std :: string to mark the that use of std :: string could not be replaced
+// by WFixedString.
+#define std_string_approved std::string
+
+#ifdef __POSIX__
+const char* const kStrNewLine = "\n";
+#endif
+#ifdef _WINDOWS
+const char* const kStrNewLine = "\r\n";
+#endif
+
+class DllExport WCFixedStringBase
+{
+public:
+    typedef size_t pos_t;
+    typedef intptr_t spos_t; // signed position, defined to intptr_t because Windows does not have ssize_t
+       static const pos_t npos = UINTPTR_MAX; // Same as size_max
+
+       WCFixedStringBase(char* const in_begin, const size_t in_MaxFixedStringLength) : 
+               m_begin(in_begin),
+               m_MaxFixedStringLength(in_MaxFixedStringLength),
+               m_end(in_begin)
+       {
+               *m_end = '\0';
+       }
+
+       inline WCFixedStringBase& operator=(const WCFixedStringBase& in_fixedStrToAssign)
+       {
+               if (this != &in_fixedStrToAssign)
+               {
+                       clear();
+                       operator<<(in_fixedStrToAssign);
+               }
+
+               return *this;
+       }
+
+       inline WCFixedStringBase& operator=(const char* in_CStrToAssign)
+       {
+               clear();
+               operator<<(in_CStrToAssign);
+
+               return *this;
+       }
+
+       inline WCFixedStringBase& operator=(const char in_charToAssign)
+       {
+               clear();
+               operator<<(in_charToAssign);
+
+               return *this;
+       }
+
+       char operator[](const pos_t in_index) const
+       {
+               if (in_index < m_MaxFixedStringLength)
+                       return m_begin[in_index];
+               else
+                       return m_begin[m_MaxFixedStringLength]; // in_index was too big 
+       }
+
+       char& operator[](const pos_t in_index)
+       {
+               if (in_index < m_MaxFixedStringLength)
+                       return m_begin[in_index];
+               else
+                       return m_begin[m_MaxFixedStringLength]; // in_index was too big 
+       }
+
+       inline size_t resize(const size_t in_newSize)
+       {
+               m_end = m_begin + WUMin<size_t>(in_newSize, m_MaxFixedStringLength);
+               *m_end = '\0';
+               return size();
+       }
+
+       size_t max_size()
+       {
+               return m_MaxFixedStringLength;
+       }
+
+       size_t capacity()
+       {
+               return m_MaxFixedStringLength;
+       }
+
+
+       inline char * peek()
+       {
+               return m_begin;
+       }
+
+       inline const char * c_str() const
+       {
+               *m_end = '\0';
+               return m_begin;
+       }
+
+       inline void clear()
+       {
+               m_end = m_begin;
+               *m_end = '\0';
+       }
+
+       inline size_t size() const
+       {
+               return m_end - m_begin;
+       }
+
+    inline char* begin() const
+    {
+        return m_begin;
+    }
+
+    inline char* end() const
+    {
+        return m_end;
+    }
+
+       inline size_t length() const
+       {
+               return size();
+       }
+
+       inline bool empty() const
+       {
+               return m_begin == m_end;
+       }
+
+       inline void reverse(char* in_left, char* in_right)
+       {
+               char* left = in_left;
+               char* right = in_right;
+               while (left < right)
+               {
+                       char temp = *--right;
+                       *right = *left;
+                       *left++ = temp;
+               }
+       }
+
+       inline void reverse()
+       {
+               reverse(m_begin, m_end);
+       }
+
+       inline void to_lower()
+       {
+               char* pToDo = m_begin;
+
+               while (pToDo < m_end)
+               {
+                       *pToDo = static_cast<char>(std::tolower(*pToDo));
+                       ++pToDo;
+               }
+       }
+
+       inline void to_upper()
+       {
+               char* pToDo = m_begin;
+
+               while (pToDo < m_end)
+               {
+                       *pToDo = static_cast<char>(std::toupper(*pToDo));
+                       ++pToDo;
+               }
+       }
+
+       // append a single char in_count times
+       inline void append(const char in_charToAppend, const size_t in_count)
+       {
+               size_t counter = 0;
+               while ((m_end < m_begin+m_MaxFixedStringLength) && counter++ < in_count)
+                       *m_end++ = in_charToAppend;
+#if kEnableDebug == 1
+               if (counter < in_count)    // if there wasn't enough room for some appended chars
+               {
+                       m_begin[0] = '@';       // mark the string as overflowed
+               }
+#endif
+               *m_end = '\0';
+       }
+
+       inline void append(const char* in_chars)
+       {
+               operator<<(in_chars);
+       }
+
+       // append "iterator style"
+       inline void append(const char* in_chars_begin, const char* in_chars_end)
+       {
+               const char* curr_char = in_chars_begin;
+               while ((m_end < m_begin+m_MaxFixedStringLength) && curr_char < in_chars_end && *curr_char != '\0')
+                       *m_end++ = *curr_char++;
+
+#if kEnableDebug == 1
+               if (curr_char < in_chars_end)   // if there wasn't enough room for some appended chars  
+               {
+                       m_begin[0] = '@';           // mark the string as overflowed
+               }
+#endif
+               *m_end = '\0';
+       }
+
+       // append from a char* in_count chars, (no \0 is required to terminate the input string) 
+       inline void append(const char* in_chars_begin, const size_t in_count)
+       {
+               append(in_chars_begin, in_chars_begin + in_count);
+       }
+
+       // assign from a char* in_count chars, (no \0 is required to terminate the input string) 
+       inline void assign(const char* in_chars_begin, const size_t in_count)
+       {
+               clear();
+               append(in_chars_begin, in_chars_begin + in_count);
+       }
+
+       // assign from a char* , (a \0 is required to terminate the input string) 
+       inline void assign(const char* in_chars_ptr)
+       {
+               clear();
+               operator<<(in_chars_ptr);
+       }
+
+    // assign from a char* to a char*
+    inline void assign(const char* in_begin, const char* in_end)
+    {
+        assign(in_begin, size_t(in_end - in_begin));
+    }
+
+       inline void append_double_with_precision(const double in_double, const int in_precision)
+       {
+               const unsigned int tempBufSize = 32;
+               char buf[tempBufSize];
+
+       #ifdef _WINDOWS
+               _snprintf_s(buf, tempBufSize, tempBufSize - 1, "%.*f", in_precision, in_double);
+       #endif
+       #ifdef __MACOS__
+               std::snprintf(buf, tempBufSize, "%.*f", in_precision, in_double);
+       #endif          
+       #ifdef __linux__        
+               snprintf(buf, tempBufSize, "%.*f", in_precision, in_double);
+       #endif          
+
+               operator<<(buf);
+       }
+
+       inline void append_uint(const uint64_t in_uint, const int_fast16_t in_base = 10)
+       {
+               uint_fast64_t num = in_uint;
+
+               char* lasr_char_before = m_end;
+
+               do {
+                       char  remainder(static_cast<char>(num % in_base));
+
+                       if ( remainder < 10 )
+                               operator<<(char(remainder + '0'));
+                       else
+                               operator<<(char(remainder - 10 + 'A'));
+
+                       num /= in_base;
+               } while (num != 0);
+
+               reverse(lasr_char_before, m_end);
+       }
+
+       inline void append_hex_binary(const uint8_t* in_binary, const size_t in_size)
+       {
+               static const char hexdigits[] = "0123456789ABCDEF";
+
+#if _BYTEORDER_BIG_ENDIAN==1
+               for (size_t ibyte = 0; ibyte < in_size; ++ibyte)
+#elif _BYTEORDER_BIG_ENDIAN==0
+                       for (size_t ibyte = in_size; ibyte > 0; --ibyte)
+#endif
+                       {
+                               operator<<(hexdigits[in_binary[ibyte - 1] >> 4]);
+                               operator<<(hexdigits[in_binary[ibyte - 1] & 0x0F]);
+                       }
+       }
+
+       inline WCFixedStringBase& operator<<(const char in_charToAppend)
+       {
+               if (m_end < m_begin+m_MaxFixedStringLength)
+                       *m_end++ = in_charToAppend;
+#if kEnableDebug == 1
+               else                    // if there wasn't enough room for the appended char
+               {
+                       m_begin[0] = '@'; // mark the string as overflowed
+               }
+#endif
+
+               *m_end = '\0';
+
+               return *this;
+       }
+
+       inline WCFixedStringBase& operator<<(const char* const in_strToAppend)
+       {
+               if (0 != in_strToAppend)
+               {
+                       const char* pSource = in_strToAppend;
+
+                       while (*pSource != '\0' && m_end < m_begin+m_MaxFixedStringLength)
+                               *m_end++ = *pSource++;
+
+#if kEnableDebug == 1
+                       if (*pSource != '\0')   // if there wasn't enough room for some appended chars  
+                       {
+                               m_begin[0] = '@';  // mark the string as overflowed
+                       }
+#endif
+                       *m_end = '\0';
+               }
+
+               return *this;
+       }
+
+       WCFixedStringBase& operator<<(const uint64_t in_uint)
+       {
+               append_uint(in_uint, 10);
+
+               return *this;
+       }
+
+
+       // Warning prevention: the operator<< function overload for unsigneds used to create lots
+    // of warnings once size_t usage was becoming widespread. So for each OS we define only
+    // those overloads that are actually needed. On Windows 32 bit we still get
+       // 'warning C4267: 'argument' : conversion from 'size_t' to 'const unsigned int', possible loss of data'
+       // warning which we do not know how to solve yet. The function DummyFunctionsForWarningTest
+    // in file WCFixedStringStream.cpp calls all combinations of operator<<(unsigned something)
+    // And should produce no warnings - (except the C4267 on windows).
+#if defined(__MACOS__) // both 32 & 64 bit
+       WCFixedStringBase& operator<<(const size_t in_uint) {
+               return operator<<(static_cast<unsigned long long>(in_uint));
+       }
+#endif   
+//     WCFixedStringBase& operator<<(const unsigned char in_uint) {
+//             return operator<<(static_cast<const unsigned long long>(in_uint));
+//             }
+//             
+//     WCFixedStringBase& operator<<(const size_t in_uint) {
+//             return operator<<(static_cast<const uint64_t>(in_uint));
+//             }
+//             
+#if defined(__MACOS__) || defined(_WINDOWS) || defined(__linux__) // both 32 & 64 bit
+       WCFixedStringBase& operator<<(const unsigned int in_uint) {
+               return operator<<(static_cast<uint64_t>(in_uint));
+       }
+#endif   
+//             
+#if defined(_WINDOWS) || defined(__linux__) // both 32 & 64 bit
+       WCFixedStringBase& operator<<(const unsigned long in_uint) {
+               return operator<<(static_cast<uint64_t>(in_uint));
+       }
+#endif   
+
+       WCFixedStringBase& operator<<(const long long in_int)
+       {
+               if (in_int < 0)
+                       operator<<('-');
+#ifdef _WINDOWS
+//        uintmax_t unsigned_in_num = _abs64(in_int);
+               uintmax_t unsigned_in_num = in_int < 0 ? static_cast<uintmax_t>(-in_int) : static_cast<uintmax_t>(in_int);
+#else
+               uintmax_t unsigned_in_num = std::abs(in_int);
+#endif
+               append_uint(unsigned_in_num, 10);
+
+               return *this;
+       }
+
+       WCFixedStringBase& operator<<(const short in_int) {
+               return operator<<(static_cast<int64_t>(in_int));
+       }
+
+       WCFixedStringBase& operator<<(const int in_int) {
+               return operator<<(static_cast<int64_t>(in_int));
+       }
+
+       WCFixedStringBase& operator<<(const long in_int) {
+               return operator<<(static_cast<int64_t>(in_int));
+       }
+
+       WCFixedStringBase& operator<<(const double in_doubleToWrite)
+       {
+               append_double_with_precision(in_doubleToWrite, 10);
+
+               return *this;
+       }
+
+       WCFixedStringBase& operator<<(const float in_floatToWrite)
+       {
+               append_double_with_precision(double(in_floatToWrite), 5);
+
+               return *this;
+       }
+
+       inline WCFixedStringBase& operator<<(const WCFixedStringBase& in_fixedStrToAppend)
+       {
+               operator<<(in_fixedStrToAppend.c_str());
+
+               return *this;
+       }
+
+       WCFixedStringBase& operator<< (bool abool)
+       {
+               return abool ? operator<<("true") : operator<<("false");
+       }
+
+       template<typename T> WCFixedStringBase& operator+=(T in_type)
+       {
+               return operator<<(in_type);
+       }
+
+       ptrdiff_t compare(const char* in_to_compare) const
+       {
+               ptrdiff_t retVal = 1;
+
+               if (0 != in_to_compare)
+               {
+                       retVal =  strcmp(c_str(), in_to_compare);
+               }
+
+               return retVal;
+       }
+
+
+       ptrdiff_t compare(const WCFixedStringBase& in_to_compare) const
+       {
+               ptrdiff_t retVal = compare(in_to_compare.c_str());              
+               return retVal;
+       }
+
+       ptrdiff_t case_insensitive_compare(const char* in_to_compare) const
+       {
+               ptrdiff_t retVal = 1;
+
+               if (0 != in_to_compare)
+               {
+#ifdef _WINDOWS
+                       retVal = _stricmp(c_str(), in_to_compare);
+#endif
+#if defined(__linux__) || defined(__MACOS__)
+                       retVal =  strcasecmp(c_str(), in_to_compare);
+#endif
+               }
+
+               return retVal;
+       }
+
+       ptrdiff_t case_insensitive_compare(const WCFixedStringBase& in_to_compare) const
+       {
+               ptrdiff_t retVal = case_insensitive_compare(in_to_compare.c_str());             
+               return retVal;
+       }
+
+       pos_t find(const char in_char_to_find) const
+       {
+               const char* pCurrChar = m_begin;
+               while (pCurrChar < m_end && *pCurrChar != in_char_to_find)
+                       ++pCurrChar;
+
+               return (pCurrChar < m_end) ? (pCurrChar - m_begin) : npos;
+       }
+
+    pos_t rfind(const char in_char_to_find) const
+    {
+        pos_t retVal = npos;
+        const char* pCurrChar = m_end;
+
+        while (pCurrChar != m_begin) 
+        {
+            --pCurrChar;
+            if (*pCurrChar == in_char_to_find)
+            {
+                retVal = pCurrChar - m_begin;
+                break;
+            }
+        }
+        
+        return retVal;
+    }
+    
+       pos_t find(const char* in_chars_to_find, const pos_t in_start_from = 0) const
+       {
+               pos_t retVal = npos;
+               size_t to_find_size = ::strlen(in_chars_to_find);
+        
+               if (to_find_size > 0 && to_find_size <= size() && in_start_from < size())
+               {
+                       const char* pCurrChar = m_begin + in_start_from;
+                       while ((m_end - pCurrChar) >= (ptrdiff_t)to_find_size)
+                       {
+                               int found = ::memcmp(pCurrChar, in_chars_to_find, to_find_size);
+                               if (0 == found)
+                               {
+                                       retVal = (pCurrChar - m_begin);
+                                       break;
+                               }
+                
+                               ++pCurrChar;
+                       }
+               }
+        
+               return retVal;
+       }
+    
+       pos_t rfind(const char* in_chars_to_find) const
+       {
+               pos_t retVal = npos;
+               size_t to_find_size = ::strlen(in_chars_to_find);
+        
+               if (to_find_size > 0 && to_find_size <= size())
+               {
+                       const char* pCurrChar = m_end - to_find_size;
+                       while (m_begin <= pCurrChar)
+                       {
+                               int found = ::memcmp(pCurrChar, in_chars_to_find, to_find_size);
+                               if (0 == found)
+                               {
+                                       retVal = (pCurrChar - m_begin);
+                                       break;
+                               }
+                
+                               --pCurrChar;
+                       }
+               }
+        
+               return retVal;
+       }
+    
+       pos_t find_case_insensitive(const char* in_chars_to_find, const pos_t in_start_from = 0) const
+       {
+               pos_t retVal = npos;
+               size_t to_find_size = ::strlen(in_chars_to_find);
+        
+               if (to_find_size > 0 && to_find_size <= size() && in_start_from < size())
+               {
+                       const char* pCurrChar = m_begin + in_start_from;
+                       while ((m_end - pCurrChar) >= (ptrdiff_t)to_find_size)
+                       {
+               size_t i;
+               for (i = 0; i < to_find_size; ++i)
+                {
+                       if (tolower(*(pCurrChar+i)) != tolower(in_chars_to_find[i]))
+                       break;
+                }
+                
+                               if (i == to_find_size)
+                               {
+                                       retVal = (pCurrChar - m_begin);
+                                       break;
+                               }
+                
+                               ++pCurrChar;
+                       }
+               }
+        
+               return retVal;
+       }
+    
+       pos_t find_first_of(const char* in_possibe_chars_to_find, const pos_t in_start_from = 0) const
+       {
+               pos_t retVal = npos;
+
+               if (in_start_from < size())
+               {
+                       const char* pFoundChar = strpbrk(m_begin + in_start_from, in_possibe_chars_to_find);
+                       if (0 != pFoundChar)
+                       {
+                               retVal = (pFoundChar - m_begin);
+                       }
+               }
+
+               return retVal;
+       }
+
+       pos_t find_last_of(const char* in_possibe_chars_to_find, const pos_t in_start_from = 0) const
+       {
+               pos_t retVal = npos;
+
+               pos_t curr_location = in_start_from;
+
+               while (size() > curr_location)
+               {
+                       pos_t found = find_first_of(in_possibe_chars_to_find, curr_location);
+                       if (npos != found)
+                       {
+                               retVal = found;
+                               curr_location = found + 1;
+                       }
+                       else
+                               break;
+               }
+
+               return retVal;
+       }
+
+       pos_t find_first_not_of(const char* in_acceptable_chars, const pos_t in_start_from = 0) const
+       {
+               pos_t retVal = npos;
+
+               if (in_start_from < size())
+               {
+                       retVal = (strspn(m_begin + in_start_from, in_acceptable_chars));
+                       if (size() <= retVal + in_start_from)
+                       {
+                               retVal = npos;
+                       }
+                       else
+                       {
+                               retVal += in_start_from;
+                       }
+               }
+
+               return retVal;
+       }
+
+       pos_t find_last_not_of(const char* in_acceptable_chars, const pos_t in_start_from = 0) const
+       {
+               pos_t retVal = npos;
+
+               pos_t curr_location = in_start_from;
+
+               while (size() > curr_location)
+               {
+                       pos_t found = find_first_not_of(in_acceptable_chars, curr_location);
+                       if (npos != found)
+                       {
+                               retVal = found;
+                               curr_location = found + 1;
+                       }
+                       else
+                               break;
+               }
+
+               return retVal;
+       }
+
+       // return true if in_begin_text is found at position 0 OR if in_begin_text is empty
+       bool begins_with(const char* in_begin_text) const
+    {
+        pos_t where = find(in_begin_text, 0);
+        bool retVal = (0 == where) || (0 == ::strlen(in_begin_text));
+        return retVal;
+    }
+       
+    // return true if in_end_text is found at th end OR if in_end_text is empty
+       bool ends_with(const char* in_end_text) const
+    {
+        pos_t where = rfind(in_end_text);
+        bool retVal = ((size() - strlen(in_end_text)) == where) || (0 == ::strlen(in_end_text));
+        return retVal;
+    }
+    
+       size_t replace(const char in_look_for, const char in_replace_with)
+       {
+               size_t retVal = 0;
+
+               char* pCurrChar = m_begin;
+               while (pCurrChar < m_end)
+               {
+                       if (*pCurrChar == in_look_for)
+                       {
+                               *pCurrChar = in_replace_with;
+                               ++retVal;
+                       }
+            ++pCurrChar;
+               }
+
+               return retVal;
+       }
+
+    // erase in_size chars starting from in_location
+       void erase(const pos_t in_location, const size_t in_num_chars = 1)
+       {
+               if (size() > in_location && in_num_chars > 0)
+               {
+                       size_t actual_num_chars = WUMin(in_num_chars, size_t(size() - in_location));
+                       char* pTo = m_begin + in_location;
+                       char* pFrom = pTo + actual_num_chars;
+
+                       while (pFrom < m_end)
+                               *pTo++ = *pFrom++;
+
+                       resize(size() - actual_num_chars);
+               }
+       }
+
+    // erase any char that appear in in_forbidden_chars
+       void erase_all_of(const char* in_forbidden_chars)
+       {
+               pos_t curr_location = 0;
+
+               while (npos != curr_location)
+               {
+                       curr_location = find_first_of(in_forbidden_chars, curr_location);
+                       if (npos != curr_location)
+                               erase(curr_location);
+               }
+       }
+
+    // erase any char that do not appear in in_allowed_chars
+       void erase_all_not_of(const char* in_allowed_chars)
+       {
+               pos_t curr_location = 0;
+
+               while (npos != curr_location)
+               {
+                       curr_location = find_first_not_of(in_allowed_chars, curr_location);
+                       if (npos != curr_location)
+                               erase(curr_location);
+               }
+       }
+
+       //! Copy the content of fixed string to a buffer appending a '\0' at the end.
+    //! If in_buffer_size is more than the allocated buffer size memory over write will happen!
+       void copy_to_buffer(const size_t in_buffer_size, char* out_buffer)
+    {
+       if (in_buffer_size > 0 && 0 != out_buffer)
+        {
+            char* cur_buffer = out_buffer;
+            const char* cur_fixed = m_begin;
+            const char* end_buffer = out_buffer + (WUMin<size_t>(in_buffer_size - 1, m_end - m_begin));
+            while (cur_buffer < end_buffer)
+                *cur_buffer++ = *cur_fixed++;
+            
+            *cur_buffer = '\0';
+        }
+    }
+    
+protected:     
+       ~WCFixedStringBase() {}
+
+       char* const m_begin;
+       const size_t m_MaxFixedStringLength;
+       char* m_end;
+
+private:
+       WCFixedStringBase();
+       WCFixedStringBase(const WCFixedStringBase& in_fixedStrToCopy);
+#if 0
+       :
+       m_begin(in_fixedStrToCopy.m_begin),
+       m_MaxFixedStringLength(in_fixedStrToCopy.m_MaxFixedStringLength),
+       m_end(in_fixedStrToCopy.m_end)
+       {
+       }
+#endif
+};
+
+template<size_t kMaxFixedStringLength> class DllExport WCFixedString : public WCFixedStringBase
+{
+public:
+
+       inline WCFixedString() : 
+               WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
+       {
+       }
+
+       inline  WCFixedString(const char* const in_strToAssign) :
+               WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
+       {
+               operator<<(in_strToAssign);
+       }
+
+       inline  WCFixedString(const WCFixedStringBase& in_fixedStrToAssign) :
+               WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
+       {
+               operator<<(in_fixedStrToAssign);
+       }
+
+       inline  WCFixedString(const WCFixedString& in_fixedStrToAssign) :
+               WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
+       {
+               operator<<(in_fixedStrToAssign);
+       }
+
+       inline  WCFixedString(const char in_char, const size_t in_count = 1) :
+               WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
+       {
+               append(in_char, in_count);
+       }
+
+       inline  WCFixedString(const char* in_chars, const size_t in_count) :
+               WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
+       {
+               append(in_chars, in_count);
+       }
+
+    // substr now supports negative in_length, which means "from the end" so
+    // "abcdefg".substr(1, -1) == "bcdef"
+       inline const WCFixedString substr(const pos_t in_pos = 0, const spos_t in_length = kMaxFixedStringLength) const
+       {
+               pos_t adjusted_pos = WUMin<size_t>(in_pos, size());
+       size_t adjusted_length = 0;
+        if (in_length < 0)
+        {
+               adjusted_length = size_t(WUMax<spos_t>(0, spos_t(size() - adjusted_pos) + in_length));
+        }
+        else
+               adjusted_length = WUMin<size_t>(in_length, size() - adjusted_pos);
+
+               WCFixedString retVal;
+               retVal.append(m_begin + adjusted_pos, adjusted_length);
+
+               return retVal;
+       }
+
+protected:     
+
+       char m_fixedString[kMaxFixedStringLength + 1]; // the "+ 1" is so that *m_end is always valid, and we can put the '\0' there};
+};
+
+inline bool operator==(const WCFixedStringBase& in_left, const WCFixedStringBase& in_right)    
+{
+       return 0 == in_left.compare(in_right.c_str());
+}
+
+inline bool operator==(const WCFixedStringBase& in_left, const char* const in_right)
+{
+       return 0 == in_left.compare(in_right);
+}
+
+inline bool operator!=(const WCFixedStringBase& in_left, const WCFixedStringBase& in_right)    
+{
+       return 0 != in_left.compare(in_right.c_str());
+}
+
+inline bool operator!=(const WCFixedStringBase& in_left, const char* const in_right)
+{
+       return 0 != in_left.compare(in_right);
+}
+
+// class WCFixedStringBase
+typedef WCFixedString<4>       WCFixedString4;
+typedef WCFixedString<15>      WCFixedString15;
+typedef WCFixedString<31>      WCFixedString31;
+typedef WCFixedString<63>      WCFixedString63;
+typedef WCFixedString<127>     WCFixedString127;
+typedef WCFixedString<255>     WCFixedString255;
+typedef WCFixedString<511>     WCFixedString511;
+typedef WCFixedString<1023>    WCFixedString1023;
+typedef WCFixedString<2047>    WCFixedString2047;
+
+template<size_t kSizeOfFirst, size_t kSizeOfSecond> 
+       class WCFixedStringPair : public std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >
+{
+public:
+       WCFixedStringPair(const char* const in_firstStr = 0, const char* const in_secondStr = 0) :      
+       std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
+       WCFixedStringPair(const WCFixedStringBase& in_firstStr, const char* const in_secondStr = 0) :   
+       std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
+       WCFixedStringPair(const WCFixedStringBase& in_firstStr, const WCFixedStringBase& in_secondStr) :        
+       std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
+};
+
+#endif  //  #ifndef __WCFixedString_h__
diff --git a/libs/backends/wavesaudio/wavesapi/miscutils/WUErrors.h b/libs/backends/wavesaudio/wavesapi/miscutils/WUErrors.h
new file mode 100644 (file)
index 0000000..11bca17
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __WUErrors_h__
+    #define __WUErrors_h__
+
+/* Copy to include:
+#include "WUErrors.h"
+*/
+
+#include "BasicTypes/WUTypes.h"
+
+// General errors
+//const WTErr eNoErr =  0; // moved to #include "WavesPublicAPI/WTErr.h"
+const WTErr eGenericErr                                                = -1;
+const WTErr eUserCanceled                      = -2;
+const WTErr eUnknownErr                                                = -3;
+const WTErr eExceptionErr                                      = -4;
+const WTErr eEndianError                                       = -5;
+const WTErr eThreadSafeError                           = -6;
+const WTErr eSomeThingNotInitailzed                    = -7;
+const WTErr eWrongObjectState                          = -8; //!< object was not in an acceptable state
+const WTErr eUninitalized                                      = -9;
+const WTErr eDeprecated                                                = -10;
+const WTErr eCommandLineParameter                      = -11;
+const WTErr eNotANumber                                                = -12; //!< expected a number but none was found
+const WTErr eNotJustANumber                                    = -13; //!< expected a number and found one but also other stuff (e.g. "123XYZ")
+const WTErr eNegativeNumber                                    = -14; //!< expected a positive number and found a negative
+const WTErr eTimeOut                        = -15; //!< something timed out
+const WTErr eCoreAudioFailed                           = -16; //!< Error in a core audio call
+const WTErr eSomeThingInitailzedTwice          = -17; 
+const WTErr eGenerateHelpInfo                          = -18; 
+const WTErr eOutOfRangeNumber                          = -19; 
+const WTErr eMacOnlyCode                               = -20; 
+const WTErr eWinOnlyCode                                   = -21; 
+const WTErr eAppLaunchFailed                       = -22; //!< failed to launch an application
+const WTErr eAppTerminateFailed                    = -23; //!< failed to terminate an application
+const WTErr eAppReturnedError               = -24; //!< Non zero exit code from application
+const WTErr eNotImplemented                 = -25; //!< Function is not implmemented
+const WTErr eNotEmpty                          = -26; //!< Something was expected to be empty but is not
+
+// File Manager errors
+const WTErr eFMNoSuchVolume                                    = -1001; 
+const WTErr eFMFileNotFound                                    = -1002;
+const WTErr eFMFileAllreadyExists                      = -1003;
+const WTErr eFMAllreadyOpenWithWritePerm       = -1004;
+const WTErr eFMEndOfFile                                       = -1005;
+const WTErr eFMPermissionErr                           = -1006;
+const WTErr eFMBusyErr                                         = -1007;
+const WTErr eFMOpenFailed                                      = -1008;
+const WTErr eFMTranslateFileNameFailed         = -1009;
+const WTErr eFMWTPathRefCreationFailed         = -1010;
+const WTErr eFMReadFailed                                      = -1011;
+const WTErr eFMIllegalPathRef                          = -1012;
+const WTErr eFMFileNotOpened                           = -1013;
+const WTErr eFMFileSizeTooBig                          = -1014;
+const WTErr eFMNoSuchDomain                                    = -1015; 
+const WTErr eFMNoSuchSystemFolder                      = -1016; 
+const WTErr eFMWrongParameters                         = -1017;
+const WTErr eFMIsNotAFolder                                    = -1018;
+const WTErr eFMIsAFolder                                       = -1019;
+const WTErr eFMIsNotAFile                                      = -1020;
+const WTErr eFMIsAFile                                         = -1021;
+const WTErr eFMDeleteFailed                                    = -1022;
+const WTErr eFMCreateFailed                                    = -1023;
+const WTErr eFMPathTooLong                                     = -1024;
+const WTErr eFMIOError                                         = -1025;
+const WTErr eFMIllegalOpenFileRef                      = -1026;
+const WTErr eFMDiskFull                                                = -1027;
+const WTErr eFMFileNotEmpty                                    = -1028;
+const WTErr eFMEndOfFolder                                     = -1029;
+const WTErr eFMSamePath                                                = -1030;
+const WTErr eFMPathTooShort                                    = -1031;
+const WTErr eFMIncompletePath                          = -1032;
+const WTErr eFMIsNoAFileSystemLink                     = -1033;
+const WTErr eFMSymlinkBroken                           = -1034;
+const WTErr eFMMoveFailed                                      = -1035;
+const WTErr eFMWriteFailed                  = -1036;
+const WTErr eFMTooManyOpenFiles                                = -1037;
+const WTErr eFMTooManySymlinks                         = -1038;
+
+// System errors
+const WTErr    eGenericSystemError                             = -2000;
+const WTErr eSysNoEnvironmentVariable      = -2001;
+const WTErr eDLLLoadingFailed                          = -2002;
+const WTErr eFuncPoinerNotFound                                = -2003;
+const WTErr eDLLNotFound                                       = -2004;
+const WTErr eBundleNotLoaded                           = -2005;
+const WTErr eBundleCreateFailed                        = -2006;
+const WTErr eBundleExecutableNotFound          = -2007;
+const WTErr    eNotABundle                                             = -2008;
+const WTErr    eInvalideDate                                   = -2009;
+const WTErr eNoNetDevice                    = -2010;
+const WTErr eCacheCreatedFromResource       = -2011;
+const WTErr eNotAValidApplication           = -2012;
+
+// Resource Manager errors
+const WTErr eRMResNotFound             = -3000;
+const WTErr eRMResExists               = -3001; //!< a resource exist even though it's not expected to 
+const WTErr eRMContainerNotFound       = -3002; //!< The container was not found in the list of containers
+const WTErr eRMResRefNotFound          = -3003; //!< The resRef was not found in container's resource list
+const WTErr eRMInvalidResRef                   = -3004;
+const WTErr eRMInvalidResContainer  = -3005;
+const WTErr eRMInvalidNativeResContainer  = -3006;
+const WTErr eRMAttachResContainerFailed   = -3007;
+const WTErr eRMInvalidResID                    = -3008;
+const WTErr eRMResUpdateFailed         = -3009;
+
+// Graphic Manager & GUI errors
+const WTErr eGMIsNotInitailzed         = -3500;
+const WTErr eGMInvalidImage                    = -3501;
+const WTErr eGMGenericErr                      = -3502;
+const WTErr eGMNoCurrentContext                = -3503;
+const WTErr eGUISkinNotFound           = -3504;
+const WTErr eGMNoVertices           = -3505;
+const WTErr eGMNoColors             = -3506;
+const WTErr eGMNoTexture            = -3507;
+const WTErr eGMIncompatibleOGLVersion  = -3508;
+const WTErr eGMNoDeviceContext         = -3509;
+const WTErr eGMNoPixelFormat           = -3510;
+const WTErr eGMNoOGLContext            = -3511;
+const WTErr eGMNoOGLContextSharing     = -3512;
+const WTErr eGMUnsupportedImageFormat          = -3513;
+const WTErr eGMUninitializedContext    = -3514;
+const WTErr eControlOutOfRange                 = -3515;
+const WTErr eGMUninitializedFont       = -3516;
+const WTErr eGMInvalidFontDrawMethod    = -3517;
+const WTErr eGMUnreleasedTextures       = -3518;
+const WTErr eGMWrongThread                     = -3519;
+const WTErr eGMDontCommitDraw                  = -3520;
+// Errors in the -5000 -> -5999 are defined in Waves-incs.h
+
+// Memory errors
+const WTErr eMemNewFailed           = -4001; //!< Something = new CSomething, returned null
+const WTErr eMemNewTPtrFailed       = -4002; //!< NewTPtr or NewTPtrClear failed
+const WTErr eMemNullPointer         = -4003; //!< a null pointer was encountered where it should not
+const WTErr eMemObjNotInitialized   = -4004;
+const WTErr eMemBuffTooShort        = -4005; //!< the buffer in question did not have enough space for the operation
+const WTErr eInstanciationFailed    = -4006;
+const WTErr eMemAddressSpaceError   = -4007; //!< memory falls outside the legal address space
+const WTErr eMemBadPointer          = -4008; 
+const WTErr eMemOutOfMemory         = -4009; 
+
+// XML Errors
+const WTErr eXMLParserFailed        = -6001;
+const WTErr eXMLTreeNotValid        = -6002;
+const WTErr eXMLTreeEmpty          = -6003;
+const WTErr eXMLElementMissing      = -6004;
+const WTErr eXMLElementUninitalized  = -6005; //!< element was default constructed it has not element name, etc..
+const WTErr eXMLElementIncomplete  = -6006;            //!< XML parser did not complete building the element
+const WTErr eXMLAttribMissing      = -6007;
+
+// Preset errors
+const WTErr ePresetFileProblem                 = -7860; 
+const WTErr eInvalidFileFormatProblem          = -7861; 
+const WTErr ePresetLockedProblem               = -7862; 
+const WTErr ePresetInfoNotFound                = -7863; 
+const WTErr eDuplicatePluginSpecificTag     = -7959; 
+const WTErr ePluginSpecifcNotExisting       = -7960; 
+const WTErr eBuffSizeToSmall                = -7961; 
+const WTErr eCreatingPopupWhereAnItemExists = -7962; 
+const WTErr eDeletePluginSpecifcFailed      = -7963; 
+const WTErr eFactoryPresetNumOutOfRange     = -7964; 
+const WTErr eNoFactoryPresets               = -7965; 
+const WTErr eLoadPresetToPlugin_vec_empty   = -7966; 
+const WTErr eFactoryPresetNotFound          = -7967; 
+const WTErr eCantCreateUserPrefFile         = -7968; 
+const WTErr eDataFormatNotSupported         = -7969; 
+const WTErr eCantLoadProcessFunction        = -7970; 
+const WTErr eIllegalChunkIndex                         = -7971; 
+const WTErr eIllegalChunkID                                    = -7972; 
+const WTErr    eIllegalChunkVersion            = -7973;
+
+
+// Shell errors
+const WTErr eNotAPluginFile                 = -8001;
+const WTErr eFaildToLoadPluginDLL                      = -8002;
+const WTErr eNoPluginManager                = -8003;
+const WTErr eGetAvailablePluginsFailed      = -8004;
+const WTErr eNoPluginsAvailable             = -8005;
+const WTErr ePluginSubComponentNotFound     = -8006;
+const WTErr ePluginOpenFailed               = -8007;
+const WTErr eSubComponentRejected              = -8009; //!< user did not want this sub-component - probably through preferences
+const WTErr eIncompatibleNumOfIOs           = -8010; //!< e.g. surround sub-component in stereo only shell
+const WTErr eStemProblem                                       = -8011; //!< Some problem with stems
+const WTErr    eComponentTypeNotSupported              = -8012;
+const WTErr    ePluginNotLoaded                                = -8013;
+const WTErr    ePluginInstanceNotCreate                = -8014;
+const WTErr    ePluginAlgNotCreate                             = -8015;
+const WTErr    ePluginGUINotCreate                             = -8016;
+const WTErr    eMissmatchChannelCount                  = -8017;
+const WTErr eIncompatibleVersion            = -8018;
+const WTErr eIncompatibleAffiliation        = -8019;
+const WTErr eNoSubComponentsFound           = -8020;
+
+// Net-shell errors
+const WTErr eNetShellInitFailed             = -9001;
+
+// Protection errors
+const WTErr eWLSLicenseFileNotFound  = -10001;
+const WTErr eWLSPluginNotAuthorized  = -10002;
+const WTErr eWLSNoLicenseForPlugin   = -10003;
+const WTErr eWLSInvalidLicenseFileName   = -10004;
+const WTErr eWLSInvalidLicenseFileContents   = -10005;
+const WTErr eWLSInvalidDeviceID     = -10006;
+const WTErr eWLSInvalidClientID     = -10007;
+const WTErr eWLSLicenseFileDownloadFailed     = -10008;
+const WTErr eWLSNoLicensesForClientOrDevice   = -10009;
+const WTErr eWLSNoLicensesForSomePlugins   = -10010;
+
+// Communication errors
+const WTErr eCommEndOfRecievedMessage          = -11001;
+const WTErr eCommSocketDisconnected                    = -11002;
+
+// Window Manager Errors
+const WTErr eWMEventNotHandled                         = -12001;
+const WTErr eWMDisposeViewFailed                       = -12002;
+
+// Plugin View Manager Errors
+const WTErr ePVMPlatformNotSupported            = -13001;
+const WTErr ePVMAlreadyInitialized              = -13002;
+const WTErr ePVMIllegalParent                   = -13003;
+const WTErr ePVMCannotCreateView                = -13004;
+const WTErr ePVMNothingSelected                 = -13005;
+const WTErr ePVMDisabledItemChosen              = -13006;
+const WTErr ePVMMenuItemNotFound                = -13007;
+const WTErr ePVMMenuItemNotASubMenu             = -13008;
+const WTErr ePVMUnknownMenu                     = -13009;
+const WTErr ePVMEmptyNativeViewRef              = -13010;
+const WTErr ePVMGenericError                    = -13011;
+const WTErr ePVMFunctionNotImplemented          = -13012;
+
+// Plugin View Manager  - Menu Errors
+const WTErr ePVMCannotCreateMenu                = -13501;
+const WTErr ePVMCannotSetMenuFont               = -13502;
+const WTErr ePVMCannotSetMenu                   = -13503;
+const WTErr ePVMItemParentNotExists             = -13504;
+
+// Plugin View Manager  - TextField Errors
+const WTErr ePVMCannotCreateTextField           = -13553;
+const WTErr ePVMCannotEmbedTextField            = -13554;
+const WTErr ePVMNoTextToValidate                = -13555;
+const WTErr ePVMTextTooLong                     = -13556;
+const WTErr ePVMIllegalCharacter                = -13557;
+
+
+// Meter Manager Errors
+const WTErr eMM_MeterGetMeterValueForParameterNotConnected     = -14000 ;
+
+
+//Surface Driver Manager Errors
+const WTErr eSDM_SurfaceDriverAPIFailed = -14101;
+
+// IPC Errors
+const WTErr eIPC_CreateNamedPipeFailed         = -14200;
+const WTErr eIPC_OpenPipeTimeout               = -14201;
+const WTErr eIPC_DeleteNamedPipeFailed         = -14202;
+const WTErr eIPC_SelectOnNamedPipeFailed       = -14203;
+const WTErr eIPC_ReadFromNamedPipeFailed       = -14204;
+const WTErr eIPC_ReadEndOfFileFromNamedPipe    = -14205;
+const WTErr eIPC_CloseNamedPipeFailed          = -14206;
+const WTErr eIPC_ParseArgsFailed               = -14207;
+const WTErr eIPC_OpenPipeFailed                = -14208;
+const WTErr eIPC_SendMsgFailed                 = -14209;
+const WTErr eIPC_SendCommandInvalid            = -14210;
+const WTErr eIPC_QtTestMode                                   = -14211;        
+const WTErr eIPC_ChangePermissionOnPipe           = -14212;    
+const WTErr eIPC_ConnectionLost                   = -14213;    
+
+const WTErr eIPC_InvalidRole                      = -14213;    
+const WTErr eIPC_CreateNamedPipeM2SFailed      = -14214;
+const WTErr eIPC_CreateNamedPipeS2MFailed      = -14215;
+const WTErr eIPC_ChangePermissionOnPipeM2S     = -14216;       
+const WTErr eIPC_ChangePermissionOnPipeS2M     = -14217;       
+const WTErr eIPC_OpenReadPipeFailed            = -14218;       
+const WTErr eIPC_OpenReadPipeDIsableSigPipe    = -14219;       
+const WTErr eIPC_OpenWritePipeFailed           = -14220;       
+const WTErr eIPC_WritePipeFailed               = -14221;       
+const WTErr eIPC_WritePipeNotOpen              = -14222;       
+const WTErr eIPC_WriteBufferResizeFailed       = -14223;       
+const WTErr eIPC_NotConnectedSendMsgFailed     = -14224;       
+const WTErr eIPC_OpenWritePipeWorkerStoping    = -14225;       
+const WTErr eIPC_SoketSendFailed               = -14226;       
+const WTErr eIPC_PtonFailed                    = -14227;       
+const WTErr eIPC_SocketFailed                  = -14228;       
+const WTErr eIPC_BindFailed                    = -14229;       
+const WTErr eIPC_ListenFailed                  = -14230;       
+const WTErr eIPC_ConnectFailed                 = -14231;       
+const WTErr eIPC_WsaStartupFailed              = -14232;
+const WTErr eIPC_UdpSocketCreateFailed         = -14233;
+const WTErr eIPC_UdpSocketConnectFailed        = -14234;
+const WTErr eIPC_UdpSocketBinFailed            = -14235;
+const WTErr eIPC_SetBufferPreambleFailed       = -14226;       
+
+// Database errors
+const WTErr eDB_BatchRollback = -15501;
+
+// inventory related errors
+const WTErr eUnknown_Device = -16001;
+const WTErr eInvNoDevice    = -16002;
+
+// SG protocol service errors
+const WTErr eSGProtocolService_Not_Running      = -17001;
+const WTErr eSGProtocolService_Version_MisMatch = -17002;
+
+// Error code related to Param
+const WTErr eInvalidParam  = -18001;
+
+#define WUIsError(theErrorCode) (eNoErr != (theErrorCode))
+#define WUNoError(theErrorCode) (eNoErr == (theErrorCode))
+#define WUThrowError(theErrorCode) {if(WUIsError(theErrorCode))throw (theErrorCode);}
+#define WUThrowErrorIfNil(thePtr , theErrorCode) {if (0 == thePtr )throw (theErrorCode);}
+#define WUThrowErrorIfFalse(theBool , theErrorCode) {if (!(theBool))throw (theErrorCode);}
+#define WUThrowErrorCodeIfError(err,theErrorCode) {if(WUIsError(err))throw (theErrorCode);}
+
+// Get the error string that match the error code.
+DllExport const char* WTErrName(WTErr wtErr);
+
+#endif //__WUErrors_h__:
diff --git a/libs/backends/wavesaudio/wavesapi/miscutils/safe_delete.h b/libs/backends/wavesaudio/wavesapi/miscutils/safe_delete.h
new file mode 100644 (file)
index 0000000..72de338
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __safe_delete_h__
+       #define __safe_delete_h__
+       
+
+/* Copy to include:
+#include "safe_delete.h"
+*/
+
+#define        safe_delete(__pObject__) {if((__pObject__) != 0) {delete (__pObject__); (__pObject__) = 0;}}
+
+#define        safe_delete_array(__pArray__) {if((__pArray__) != 0) {delete [] (__pArray__); (__pArray__) = 0;}}
+
+template <class T> void safe_delete_from_iterator(T* pToDelete)
+{
+       safe_delete(pToDelete);
+}
+
+#endif // __safe_delete_h__
diff --git a/libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.cpp b/libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.cpp
new file mode 100644 (file)
index 0000000..34c4a41
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#include "WCRefManager.h"
+
+/// Construcotr.
+WCRefManager::WCRefManager()
+{
+       m_RefCount = 1;
+}
+
+/// Destructor.
+WCRefManager::~WCRefManager()
+{
+}
+
+/// Adds a reference to class.
+void WCRefManager::AddRef()
+{
+       m_RefCount++;
+}
+
+/// Decrements reference count and deletes the object if reference count becomes zero.
+void WCRefManager::Release()
+{
+       m_RefCount--;
+       if( m_RefCount <= 0 )
+               delete this;
+}
\ No newline at end of file
diff --git a/libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.h b/libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.h
new file mode 100644 (file)
index 0000000..7919789
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef WCREFMANAGER_H
+#define WCREFMANAGER_H
+
+
+#define SAFE_RELEASE(p) if (p) {p->Release(); p = NULL;}
+
+
+//In order to use this interface, derive the Interface class
+//from WCRefManager_Interface and derive the implementation class
+//from WCRefManager_Impl. Further, in the implementation class
+//declaration, place the macro WCREFMANAGER_IMPL.
+class WCRefManager_Interface
+{
+public:
+       /// Constructor.
+       WCRefManager_Interface() {};
+       /// Destructor.
+       virtual ~WCRefManager_Interface() {};
+       /// Adds a reference to class.
+       virtual void AddRef() = 0;
+       /// Decrements reference count and deletes the object if reference count becomes zero.
+       virtual void Release() = 0;
+};
+
+///! See details at WCRefManager_Interface for how to use this.
+class WCRefManager_Impl
+{
+public:
+    WCRefManager_Impl () : m_RefCount(1) {}
+    virtual ~WCRefManager_Impl() {}
+protected:
+       /// Variable to store reference count.
+       unsigned int m_RefCount;
+
+/// Helper to put implementation in an interface derived class, don't forget to
+/// derive the impl from WCRefManager_Impl
+#define WCREFMAN_IMPL \
+    public: \
+        virtual void AddRef() {m_RefCount++;} \
+        virtual void Release() {m_RefCount--; if (m_RefCount<=0) delete this;}
+
+};
+
+
+class WCRefManager
+{
+public:
+       /// Construcotr.
+       WCRefManager();
+       /// Destructor.
+       virtual ~WCRefManager();
+       /// Adds a reference to class.
+       void AddRef();
+       /// Decrements reference count and deletes the object if reference count becomes zero.
+       void Release();
+
+private:
+       /// Variable to store reference count.
+       unsigned int m_RefCount;
+};
+
+#endif // WCREFMANAGER_H
diff --git a/libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.cpp b/libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.cpp
new file mode 100644 (file)
index 0000000..62fc040
--- /dev/null
@@ -0,0 +1,844 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#include "Threads/WCThreadSafe.h"
+    
+#if XPLATFORMTHREADS_WINDOWS
+    #define _WIN32_WINNT 0x0500   // need at least Windows2000 (for TryEnterCriticalSection() and SignalObjectAndWait()
+    #include "IncludeWindows.h"
+    #include <process.h>
+#endif // XPLATFORMTHREADS_WINDOWS
+
+
+#if defined(__MACOS__)
+    #include <CoreServices/CoreServices.h>
+    #include <stdio.h>
+#endif // __MACOS__
+
+#if XPLATFORMTHREADS_POSIX
+    #include </usr/include/unistd.h>   // avoid the framework version and use the /usr/include version
+    #include <pthread.h>
+    #include <sched.h>
+    #include <sys/time.h>
+    #include <errno.h>
+    #include <signal.h>
+// We do this externs because <stdio.h> comes from MSL
+extern "C" FILE *popen(const char *command, const char *type);
+extern "C" int pclose(FILE *stream);
+static int (*BSDfread)( void *, size_t, size_t, FILE * ) = 0;
+
+#include <string.h>
+
+#endif //XPLATFORMTHREADS_POSIX
+
+#include "Akupara/threading/atomic_ops.hpp"
+namespace wvNS {
+static const unsigned int knMicrosecondsPerSecond = 1000*1000;
+static const unsigned int knNanosecondsPerMicrosecond = 1000;
+static const unsigned int knNanosecondsPerSecond = knMicrosecondsPerSecond*knNanosecondsPerMicrosecond;
+
+namespace wvThread
+{
+
+    //--------------------------------------------------------------------------------
+    static inline bool EnsureThreadingInitialized()
+    {
+        bool bRetval = true;
+
+        return bRetval;
+    }
+    //--------------------------------------------------------------------------------
+
+
+
+
+    //--------------------------------------------------------------------------------
+    static uint32_t CalculateTicksPerMicrosecond();
+    static uint32_t CalculateTicksPerMicrosecond()
+    {
+        uint32_t nTicksPerMicrosecond=0;
+#if defined(_WIN32)
+        LARGE_INTEGER TSC;
+        ::QueryPerformanceFrequency(&TSC);
+        nTicksPerMicrosecond = uint32_t (TSC.QuadPart / knMicrosecondsPerSecond);
+#elif defined(__linux__) && defined(__i386__)
+        static const timediff sktd_TSC_MeasurementPeriod = 40*1000; // delay for CalculateTicksPerMicrosecond() to measure the TSC frequency
+        uint64_t Tstart, Tend;
+        timeval tvtmp, tvstart, tvend;
+
+        //--------------------- begin measurement code
+        // poll to align to a tick of gettimeofday
+        ::gettimeofday(&tvtmp,0);
+        do { 
+            ::gettimeofday(&tvstart,0);
+            __asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (Tstart));  // RDTSC
+        } while (tvtmp.tv_usec!=tvstart.tv_usec);
+        // delay some
+        ::usleep(sktd_TSC_MeasurementPeriod);
+        //
+        ::gettimeofday(&tvtmp,0);
+        do { 
+            ::gettimeofday(&tvend,0);
+            __asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (Tend));    // RDTSC
+        } while (tvtmp.tv_usec!=tvend.tv_usec);
+        //--------------------- end measurement code
+
+        suseconds_t elapsed_usec = (tvend.tv_sec-tvstart.tv_sec)*knMicrosecondsPerSecond + (tvend.tv_usec-tvstart.tv_usec);
+        uint64_t elapsed_ticks = Tend-Tstart;
+        nTicksPerMicrosecond = uint32_t (elapsed_ticks/elapsed_usec);
+#endif
+        return nTicksPerMicrosecond;
+    }
+    
+#if defined(__MACOS__) //&& !defined(__MACH__)
+
+    
+    bool FindNetInterfaceByIPAddress(const char *sIP, char *sInterface) // sIP and sInterface are both char[16]
+    {
+        FILE *fProcess , *pSubcall;
+        char sLine[256]="", *pToken, sCommand[150];
+        bool res = false;
+        int iret;
+
+        fProcess = popen("ifconfig -l inet", "r");
+        if (fProcess)
+        {
+            memset(sInterface, '\0', 16);
+            iret = BSDfread(sLine, sizeof(char), sizeof(sLine), fProcess);
+            pToken = strtok(sLine, " ");
+            while (pToken)
+            {
+                sprintf(sCommand, "ifconfig %s | grep \"inet %s \"", pToken, sIP);
+                
+                pSubcall = popen(sCommand, "r");
+                if (pSubcall)
+                {
+                    char sSubline[100]="";
+                    if (BSDfread(sSubline, sizeof(char), sizeof(sSubline), pSubcall))
+                    {
+                        // found
+                        strcpy(sInterface, pToken);
+                        res = true;
+                        pclose(pSubcall);
+                        break;
+                    }
+                }
+                pclose(pSubcall);
+                pToken = strtok(NULL, " ");    
+            }
+            
+        }
+        pclose(fProcess);
+        
+        return res;
+    }
+#endif // MACOS
+
+    timestamp now(void)
+    {
+        EnsureThreadingInitialized();
+        static const uint32_t nTicksPerMicrosecond = CalculateTicksPerMicrosecond();
+#if defined(_WIN32)
+        if (nTicksPerMicrosecond)
+        {
+            LARGE_INTEGER TSC;
+            ::QueryPerformanceCounter(&TSC);
+            return timestamp(uint32_t(TSC.QuadPart/nTicksPerMicrosecond));
+        }
+        else return timestamp(0);
+#elif defined(__MACOS__)
+        if (nTicksPerMicrosecond) {} // prevent 'unused' warnings
+        UnsignedWide usecs;
+        ::Microseconds(&usecs);
+        return timestamp(usecs.lo);
+#elif defined(__linux__) && defined(__i386__) && defined(__gnu_linux__)
+        uint64_t TSC;
+        __asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (TSC));  // RDTSC
+        return timestamp(TSC/nTicksPerMicrosecond);
+#elif defined(__linux__) && defined(__PPC__) && defined(__gnu_linux__)
+    #warning need to implement maybe
+#else
+    #error Dont know how to get microseconds timer !
+#endif // defined(_WIN32)
+    }
+
+
+    void sleep_milliseconds(unsigned int nMillisecs)
+    {
+        EnsureThreadingInitialized();
+#if XPLATFORMTHREADS_WINDOWS
+        ::Sleep(nMillisecs);
+#elif XPLATFORMTHREADS_POSIX
+        ::usleep(nMillisecs*1000);
+#else
+    #error Not implemented for your OS
+#endif
+    }
+
+
+#if XPLATFORMTHREADS_WINDOWS
+    inline DWORD win32_milliseconds(timediff td) { return (td+499)/1000; }
+#endif
+
+    void sleep(timediff _td)
+    {
+        if (_td>0)
+        {
+            EnsureThreadingInitialized();
+#if XPLATFORMTHREADS_WINDOWS
+            ::Sleep(win32_milliseconds(_td));    // This is the best we can do in windows
+#elif XPLATFORMTHREADS_POSIX
+            ::usleep(_td);
+#else
+    #error Not implemented for your OS
+#endif
+        }
+    }
+
+
+#if XPLATFORMTHREADS_WINDOWS
+    void yield()   {  ::Sleep(0);   }
+#elif XPLATFORMTHREADS_POSIX
+    void yield()   {  ::sched_yield();  }
+#endif
+
+
+
+    class  ThreadMutexInited::OSDependentMutex : public noncopyableobject
+    {
+#if defined (XPLATFORMTHREADS_WINDOWS)
+    protected:
+        CRITICAL_SECTION m_critsec;
+    public:
+
+        inline OSDependentMutex()  { EnsureThreadingInitialized(); ::InitializeCriticalSection(&m_critsec); }
+        inline ~OSDependentMutex() { EnsureThreadingInitialized(); ::DeleteCriticalSection    (&m_critsec); }
+        inline void obtain()       { EnsureThreadingInitialized(); ::EnterCriticalSection     (&m_critsec); }
+        inline void release()      { EnsureThreadingInitialized(); ::LeaveCriticalSection     (&m_critsec); }
+        inline bool tryobtain()    { EnsureThreadingInitialized(); return TryEnterCriticalSection(&m_critsec)!=FALSE; }
+        
+#elif defined (XPLATFORMTHREADS_POSIX)
+    protected:
+        pthread_mutex_t  m_ptmutex;
+    public:
+        inline OSDependentMutex()  
+        { 
+            EnsureThreadingInitialized(); 
+            pthread_mutexattr_t attr;
+            pthread_mutexattr_init(&attr);
+            pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+            ::pthread_mutex_init (&m_ptmutex, &attr);
+        }
+        inline ~OSDependentMutex() { EnsureThreadingInitialized(); ::pthread_mutex_destroy(&m_ptmutex); }
+        inline void obtain()       { EnsureThreadingInitialized(); ::pthread_mutex_lock       (&m_ptmutex); }
+        inline void release()      { EnsureThreadingInitialized(); ::pthread_mutex_unlock     (&m_ptmutex); }
+        inline bool tryobtain()    { EnsureThreadingInitialized(); return ::pthread_mutex_trylock(&m_ptmutex)!=EBUSY; }
+
+#endif
+    };
+
+    ThreadMutexInited::ThreadMutexInited() :
+                        m_osdmutex(0) {}
+    
+    void ThreadMutexInited::init()
+    {
+        if (! is_init())
+        {
+            m_osdmutex = new OSDependentMutex;
+        }
+    }
+    
+    void ThreadMutexInited::uninit()
+    {
+        if (is_init())
+        {
+            delete m_osdmutex;
+            m_osdmutex = 0;
+        }
+    }
+    
+    ThreadMutexInited::~ThreadMutexInited()
+    {
+        uninit();
+    }    
+    
+    void ThreadMutexInited::obtain()
+    {
+        if (is_init())
+        {
+            m_osdmutex->obtain(); 
+        }
+    }    
+
+    void ThreadMutexInited::release()
+    {
+        if (is_init())
+        {
+            m_osdmutex->release(); 
+        }
+    }    
+    
+    bool ThreadMutexInited::tryobtain()
+    {
+        bool retVal = true;
+        if (is_init())
+        {
+            retVal = m_osdmutex->tryobtain(); 
+        }
+        return retVal;
+    }    
+    
+    class ThreadConditionSignal::OSDependentObject : public noncopyableobject
+    {
+#if defined (XPLATFORMTHREADS_POSIX)
+
+    protected:
+        pthread_cond_t  m_ptcond;
+        pthread_mutex_t m_ptmutex;
+    public:
+        inline OSDependentObject()      
+        {
+            EnsureThreadingInitialized(); 
+            ::pthread_mutex_init(&m_ptmutex,0);
+            ::pthread_cond_init(&m_ptcond, 0); 
+        }
+        inline ~OSDependentObject()     { ::pthread_cond_destroy(&m_ptcond), ::pthread_mutex_destroy(&m_ptmutex); }
+        inline void signal_unicast()    { ::pthread_cond_signal(&m_ptcond);    }
+        inline void signal_broadcast()  { ::pthread_cond_broadcast(&m_ptcond); }
+        inline void await_signal()      { ::pthread_cond_wait(&m_ptcond, &m_ptmutex); }
+        inline bool await_signal(timediff td) 
+        {
+            timespec tspecDeadline;
+            timeval  tvNow;
+            ::gettimeofday(&tvNow,0);
+            tspecDeadline.tv_nsec = (tvNow.tv_usec + td%knMicrosecondsPerSecond)*knNanosecondsPerMicrosecond;
+            tspecDeadline.tv_sec  = tvNow.tv_sec  + td/knMicrosecondsPerSecond;
+            if (!(tspecDeadline.tv_nsec < suseconds_t(knNanosecondsPerSecond)))
+                ++tspecDeadline.tv_sec, tspecDeadline.tv_nsec-=knNanosecondsPerSecond;
+            return ::pthread_cond_timedwait(&m_ptcond, &m_ptmutex, &tspecDeadline) != ETIMEDOUT;
+        }
+
+        void obtain_mutex()    { ::pthread_mutex_lock(&m_ptmutex); }
+        bool tryobtain_mutex() { return ::pthread_mutex_trylock(&m_ptmutex)!=EBUSY; }
+        void release_mutex()   { ::pthread_mutex_unlock(&m_ptmutex); }
+
+
+#elif XPLATFORMTHREADS_WINDOWS
+    protected:
+        unsigned int     m_nWaiterCount;
+        CRITICAL_SECTION m_csectWaiterCount;
+
+        HANDLE m_hndSemaphoreSignaller;        // We keep this semaphore always at 0 count (non-signalled). We use it to release a controlled number of threads.
+        HANDLE m_hndEventAllWaitersReleased;   // auto-reset
+        HANDLE m_hndMutex;                     // the mutex associated with the condition
+        bool   m_bBroadcastSignalled;          // means that the last waiter must signal m_hndEventAllWaitersReleased when done waiting
+
+    protected:
+        // - - - - - - - - - - - - - - - - - - - - - - - -
+        bool await_signal_win32(DWORD dwTimeout)
+        {
+            ::EnterCriticalSection(&m_csectWaiterCount);
+            ++m_nWaiterCount;
+            ::LeaveCriticalSection(&m_csectWaiterCount);
+            // This is the actual wait for the signal
+            bool bWaitSucceeded = ::SignalObjectAndWait(m_hndMutex, m_hndSemaphoreSignaller, dwTimeout, FALSE) == WAIT_OBJECT_0;
+            //
+            ::EnterCriticalSection(&m_csectWaiterCount);
+            bool bLastWaiter = --m_nWaiterCount==0 && m_bBroadcastSignalled;
+            ::LeaveCriticalSection(&m_csectWaiterCount);
+
+            // re-acquire the mutex
+            if (bLastWaiter)
+                ::SignalObjectAndWait(m_hndEventAllWaitersReleased, m_hndMutex, INFINITE, FALSE);
+            else
+                ::WaitForSingleObject(m_hndMutex, INFINITE);
+            return bWaitSucceeded;
+        }
+
+
+    public:
+
+        inline bool await_signal(timediff td)  { return await_signal_win32((win32_milliseconds(td))); }
+        inline void await_signal()             { await_signal_win32(INFINITE); }
+
+        OSDependentObject() : m_nWaiterCount(0), m_bBroadcastSignalled(false)
+        {
+            EnsureThreadingInitialized();
+            ::InitializeCriticalSection(&m_csectWaiterCount);
+            m_hndEventAllWaitersReleased = ::CreateEvent(
+                    0,      // security
+                    FALSE,  // auto-reset
+                    FALSE,  // initial state non-sognalled
+                    0);     // name
+            m_hndSemaphoreSignaller = ::CreateSemaphore(
+                    0,         // security
+                    0,         // initial count (and will stay this way)
+                    0x100000,  // maximum count (should be as large as the maximum number of waiting threads)
+                    0);        // name
+            m_hndMutex = ::CreateMutex(
+                    0,         // security
+                    FALSE,     // not owned initially
+                    0);        // name
+            //if (m_hndEventAllWaitersReleased==INVALID_HANDLE_VALUE || m_hndSemaphoreSignaller==INVALID_HANDLE_VALUE)
+            //    throw something();
+        }
+
+        ~OSDependentObject()
+        {
+            ::CloseHandle(m_hndMutex);
+            ::CloseHandle(m_hndSemaphoreSignaller);
+            ::CloseHandle(m_hndEventAllWaitersReleased);
+            ::DeleteCriticalSection(&m_csectWaiterCount);
+        }
+
+        inline void signal_unicast()
+        {
+            ::EnterCriticalSection(&m_csectWaiterCount);
+            unsigned int nWaiters = m_nWaiterCount;
+            ::LeaveCriticalSection(&m_csectWaiterCount);
+            if (nWaiters)
+                ::ReleaseSemaphore(m_hndSemaphoreSignaller, 1, 0);  // release 1 semaphore credit to release one waiting thread
+        }
+
+        void signal_broadcast()
+        {
+            ::EnterCriticalSection(&m_csectWaiterCount);
+            unsigned int nWaiters = m_nWaiterCount;
+            if (nWaiters)
+            {
+                m_bBroadcastSignalled = true;
+                ::ReleaseSemaphore(m_hndSemaphoreSignaller, nWaiters, 0);  // release as many credits as there are waiting threads
+                ::LeaveCriticalSection(&m_csectWaiterCount);
+                ::WaitForSingleObject(m_hndEventAllWaitersReleased, INFINITE);
+                // at this point all threads are waiting on m_hndMutex, which would be released outside this function call
+                m_bBroadcastSignalled = false;
+            }
+            else
+                // no one is waiting
+                ::LeaveCriticalSection(&m_csectWaiterCount);
+        }
+        //------------------------------------------------
+        inline void obtain_mutex()    { ::WaitForSingleObject(m_hndMutex, INFINITE); }
+        inline bool tryobtain_mutex() { return ::WaitForSingleObject(m_hndMutex,0) == WAIT_OBJECT_0; }
+        inline void release_mutex()   { ::ReleaseMutex(m_hndMutex); }
+        //------------------------------------------------
+#endif // OS switch
+    };
+
+    void ThreadConditionSignal::obtain_mutex()    
+    { 
+        m_osdepobj.obtain_mutex();    
+    }
+    bool ThreadConditionSignal::tryobtain_mutex() { return m_osdepobj.tryobtain_mutex(); }
+    void ThreadConditionSignal::release_mutex()   
+    { 
+        m_osdepobj.release_mutex();   
+    }
+
+    void ThreadConditionSignal::await_condition()                   { m_osdepobj.await_signal();  }
+    bool ThreadConditionSignal::await_condition(timediff tdTimeout) { return m_osdepobj.await_signal(tdTimeout);  }
+    void ThreadConditionSignal::signal_condition_single()           { m_osdepobj.signal_unicast();    }
+    void ThreadConditionSignal::signal_condition_broadcast()        { m_osdepobj.signal_broadcast();  }
+
+    ThreadConditionSignal::ThreadConditionSignal() : m_osdepobj(*new OSDependentObject) {}
+    ThreadConditionSignal::~ThreadConditionSignal() { delete &m_osdepobj; }
+
+
+
+
+
+
+
+
+#if XPLATFORMTHREADS_POSIX
+    namespace // anon
+    {
+        inline int max_FIFO_schedparam()
+        {
+            static const int max_priority = ::sched_get_priority_max(SCHED_FIFO);
+            return max_priority;
+        }
+        inline int schedparam_by_percentage(unsigned short percentage)
+        {
+            return (max_FIFO_schedparam()*10*percentage+500)/1000;
+        }
+        class POSIXThreadPriority
+        {
+        public:
+            int m_SchedPolicy;
+            int m_SchedPriority;
+            POSIXThreadPriority(ThreadPriority pri)
+            {
+                switch (pri)
+                {
+                case ThreadPriority::TimeCritical: m_SchedPolicy=SCHED_FIFO, m_SchedPriority=schedparam_by_percentage(80); break;
+                case ThreadPriority::AboveNormal:  m_SchedPolicy=SCHED_FIFO, m_SchedPriority=schedparam_by_percentage(20); break;
+                case ThreadPriority::BelowNormal:  // fall through to normal; nothing is below normal in POSIX
+                case ThreadPriority::Normal: // fall through to default
+                default: m_SchedPolicy=SCHED_OTHER, m_SchedPriority=0; break;
+                }
+            }
+        };
+
+    } // namespace anonymous
+#endif // XPLATFORMTHREADS_POSIX
+
+#if XPLATFORMTHREADS_WINDOWS
+    namespace // anon
+    {
+        inline int WinThreadPriority(ThreadPriority pri)
+        {
+            switch (pri)
+            {
+            case ThreadPriority::BelowNormal:  return THREAD_PRIORITY_BELOW_NORMAL;
+            case ThreadPriority::AboveNormal:  return THREAD_PRIORITY_ABOVE_NORMAL;
+            case ThreadPriority::TimeCritical: return THREAD_PRIORITY_TIME_CRITICAL;
+            case ThreadPriority::Normal: // fall through to default
+            default: return THREAD_PRIORITY_NORMAL;
+            }
+        }
+    } // namespace anon
+#endif // XPLATFORMTHREADS_WINDOWS
+
+
+
+    void SetMyThreadPriority(ThreadPriority pri)
+    {
+#if XPLATFORMTHREADS_WINDOWS
+        ::SetThreadPriority(::GetCurrentThread(), WinThreadPriority(pri));
+#endif // XPLATFORMTHREADS_WINDOWS
+#if XPLATFORMTHREADS_POSIX
+        const POSIXThreadPriority posixpri(pri);
+        sched_param sparam;
+        ::memset(&sparam, 0, sizeof(sparam));
+        sparam.sched_priority = posixpri.m_SchedPriority;
+#if defined(__linux__)
+        ::sched_setscheduler(0, posixpri.m_SchedPolicy, &sparam);  // linux uses this function instead of pthread_
+#else
+        pthread_setschedparam(pthread_self(), posixpri.m_SchedPolicy, &sparam);
+#endif
+#endif // XPLATFORMTHREADS_POSIX
+    }
+
+
+    struct ThreadWrapperData
+    {
+        ThreadFunction *func;
+        ThreadFunctionArgument arg;
+    };
+
+#if XPLATFORMTHREADS_WINDOWS
+    static unsigned int __stdcall ThreadWrapper(void * arg)
+    {
+        register ThreadWrapperData *twd = reinterpret_cast<ThreadWrapperData*>(arg);
+        ThreadFunction        *func=twd->func;
+        ThreadFunctionArgument farg=twd->arg;
+        delete twd;
+        return DWORD(func(farg));
+    }
+#elif XPLATFORMTHREADS_POSIX
+    static void * ThreadWrapper(void *arg)
+    {
+        register ThreadWrapperData *twd = reinterpret_cast<ThreadWrapperData*>(arg);
+        ThreadFunction        *func=twd->func;
+        ThreadFunctionArgument farg=twd->arg;
+        delete twd;
+        return reinterpret_cast<void*>(func(farg));
+    }
+    typedef void*(ThreadWrapperFunction)(void*);
+
+    static ThreadWrapperFunction *ThunkedThreadWrapper = ThreadWrapper;
+
+#endif // OS switch
+
+
+
+
+
+    class ThreadHandle::OSDependent
+    {
+    public:
+        static void StartThread(ThreadWrapperData *, ThreadHandle &, ThreadPriority);
+        static bool KillThread(ThreadHandle);
+        static bool JoinThread(ThreadHandle, ThreadFunctionReturnType*);
+        static void Close(ThreadHandle);
+#if XPLATFORMTHREADS_WINDOWS
+        static inline uintptr_t from_oshandle(HANDLE h) { return reinterpret_cast<uintptr_t>(h); }
+        static inline HANDLE to_oshandle(uintptr_t h) { return reinterpret_cast<HANDLE>(h); }
+#elif XPLATFORMTHREADS_POSIX
+        static inline uintptr_t from_oshandle(pthread_t pt) { return uintptr_t(pt); }
+        static inline pthread_t to_oshandle(uintptr_t h) { return pthread_t(h); }
+#endif // OS switch
+    };
+
+#if XPLATFORMTHREADS_WINDOWS
+    const ThreadHandle ThreadHandle::Invalid(OSDependent::from_oshandle(INVALID_HANDLE_VALUE));
+#elif XPLATFORMTHREADS_POSIX
+    const ThreadHandle ThreadHandle::Invalid(OSDependent::from_oshandle(0));
+#endif // OS switch
+
+    inline void ThreadHandle::OSDependent::StartThread(ThreadWrapperData *ptwdata, ThreadHandle &th, ThreadPriority pri)
+    {
+#if XPLATFORMTHREADS_WINDOWS
+        uintptr_t h = ::_beginthreadex(
+                0,                 // no security attributes, not inheritable
+                0,                 // default stack size
+                ThreadWrapper,     // function to call
+                (void*)(ptwdata),   // argument for function
+                0,                 // creation flags
+                0                  // where to store thread ID
+            );
+
+        if (h) 
+        {
+            th.m_oshandle = h;
+            if (pri!=ThreadPriority::Normal)
+                ::SetThreadPriority(to_oshandle(h), WinThreadPriority(pri));
+        }
+        else
+            th=Invalid;
+#elif XPLATFORMTHREADS_POSIX
+        pthread_attr_t my_thread_attr, *pmy_thread_attr = 0;
+        sched_param my_schedparam;
+
+        if (pri!=ThreadPriority::Normal)
+        {
+            pmy_thread_attr = &my_thread_attr;
+
+            const POSIXThreadPriority posixpriority(pri);
+            int result;
+            result = pthread_attr_init          (pmy_thread_attr);
+            result = pthread_attr_setschedpolicy(pmy_thread_attr, posixpriority.m_SchedPolicy);
+
+            memset(&my_schedparam, 0, sizeof(my_schedparam));
+            my_schedparam.sched_priority = posixpriority.m_SchedPriority;
+            result = pthread_attr_setschedparam(pmy_thread_attr, &my_schedparam);
+        }
+
+        pthread_t pt;
+        int anyerr = pthread_create(
+                &pt,   // variable for thread handle
+                pmy_thread_attr,     // default attributes
+                ThunkedThreadWrapper,
+                ptwdata
+            );
+            
+        if (anyerr) 
+            th=Invalid;
+        else
+            th.m_oshandle = OSDependent::from_oshandle(pt);
+#endif
+    }
+
+    inline bool ThreadHandle::OSDependent::KillThread(ThreadHandle h)
+    {
+#if XPLATFORMTHREADS_WINDOWS
+        return ::TerminateThread(to_oshandle(h.m_oshandle), (DWORD)-1) != 0;
+#elif XPLATFORMTHREADS_POSIX
+        return pthread_cancel(to_oshandle(h.m_oshandle)) == 0;
+#endif
+    }
+
+    bool ThreadHandle::OSDependent::JoinThread(ThreadHandle h, ThreadFunctionReturnType *pretval)
+    {
+#if XPLATFORMTHREADS_WINDOWS
+        const bool kbReturnedOk = (WAIT_OBJECT_0 == ::WaitForSingleObject(OSDependent::to_oshandle(h.m_oshandle), INFINITE));
+        if (kbReturnedOk && pretval)
+        {
+            DWORD dwExitCode;
+            ::GetExitCodeThread(to_oshandle(h.m_oshandle), &dwExitCode);
+            *pretval = (ThreadFunctionReturnType)(dwExitCode);
+        }
+        return kbReturnedOk;
+#endif
+#if XPLATFORMTHREADS_POSIX
+        ThreadFunctionReturnType ptrExitCode = 0;
+        int join_return_code = pthread_join(to_oshandle(h.m_oshandle), (void**)ptrExitCode);
+        const bool kbReturnedOk = (0 == join_return_code);
+        if (0 != pretval)
+        {
+            *pretval = ptrExitCode;
+        }
+        return kbReturnedOk;
+#endif
+    }
+
+#if XPLATFORMTHREADS_WINDOWS
+    inline void ThreadHandle::OSDependent::Close(ThreadHandle h)
+    {
+        ::CloseHandle(OSDependent::to_oshandle(h.m_oshandle));
+    }
+#endif // XPLATFORMTHREADS_WINDOWS
+#if XPLATFORMTHREADS_POSIX
+    inline void ThreadHandle::OSDependent::Close(ThreadHandle) {}
+#endif // XPLATFORMTHREADS_POSIX
+
+    //**********************************************************************************************
+
+    class WCThreadRef::OSDependent
+    {
+    public:
+        static void GetCurrentThreadRef(WCThreadRef& tid); 
+#if XPLATFORMTHREADS_WINDOWS
+        static inline uintptr_t from_os(DWORD thread_id) { return (uintptr_t)(thread_id); }
+        static inline DWORD to_os(uintptr_t thread_id)   { return (DWORD)(thread_id); }
+#elif XPLATFORMTHREADS_POSIX
+    static inline uintptr_t from_os(pthread_t thread_id) { return (uintptr_t)(thread_id); }
+    static inline pthread_t to_os(uintptr_t thread_id)   { return pthread_t(thread_id); }
+#endif // OS switch
+    };
+
+    //**********************************************************************************************
+    inline void WCThreadRef::OSDependent::GetCurrentThreadRef(WCThreadRef& tid)
+    {
+#if XPLATFORMTHREADS_WINDOWS
+        DWORD thread_id = ::GetCurrentThreadId();
+        tid.m_osThreadRef = OSDependent::from_os(thread_id);
+
+#elif XPLATFORMTHREADS_POSIX
+        pthread_t thread_id = ::pthread_self();
+        tid.m_osThreadRef = OSDependent::from_os(thread_id);
+
+#endif // OS switch
+    }
+
+    //**********************************************************************************************
+
+    ThreadHandle StartThread(ThreadFunction func, ThreadFunctionArgument arg, ThreadPriority thpri)
+    {
+        EnsureThreadingInitialized();
+        ThreadWrapperData *ptwdata = new ThreadWrapperData;
+        ptwdata->func = func;
+        ptwdata->arg  = arg;
+        ThreadHandle thToReturn;
+        ThreadHandle::OSDependent::StartThread(ptwdata, thToReturn, thpri);
+        return thToReturn;
+    }
+
+    bool KillThread(ThreadHandle h)
+    {
+        EnsureThreadingInitialized();
+        return ThreadHandle::OSDependent::KillThread(h);
+    }
+
+    bool JoinThread(ThreadHandle h, ThreadFunctionReturnType *pretval)
+    {
+        EnsureThreadingInitialized();
+        return ThreadHandle::OSDependent::JoinThread(h, pretval);
+    }
+
+    void Close(ThreadHandle h)
+    {
+        EnsureThreadingInitialized();
+        return ThreadHandle::OSDependent::Close(h);
+    }
+
+    //*******************************************************************************************
+
+    WCThreadRef GetCurrentThreadRef()
+    {
+        EnsureThreadingInitialized(); // Is it necessary?  
+        WCThreadRef tRefToReturn;
+        WCThreadRef::OSDependent::GetCurrentThreadRef(tRefToReturn);
+        return tRefToReturn;
+    }
+
+    //*******************************************************************************************
+
+    bool IsThreadExists(const WCThreadRef& threadRef)
+    {
+#if XPLATFORMTHREADS_WINDOWS
+        DWORD dwThreadId = WCThreadRef::OSDependent::to_os((uintptr_t)threadRef);
+        HANDLE handle = ::OpenThread(SYNCHRONIZE, // dwDesiredAccess - use of the thread handle in any of the wait functions
+                                     FALSE,          // bInheritHandle  - processes do not inherit this handle
+                                     dwThreadId);
+
+        // Now we have the handle, check if the associated thread exists:
+        DWORD retVal = WaitForSingleObject(handle, 0);
+        if (retVal == WAIT_FAILED)
+            return false;    // the thread does not exists
+        else
+            return true;    // the thread exists
+
+#elif XPLATFORMTHREADS_POSIX
+        pthread_t pthreadRef = WCThreadRef::OSDependent::to_os((uintptr_t)threadRef);
+        int retVal = pthread_kill(pthreadRef, 0);    // send a signal to the thread, but do nothing
+        if (retVal == ESRCH)
+            return false;    // the thread does not exists
+        else
+            return true;    // the thread exists
+
+#endif // OS switch
+    }
+
+    //*******************************************************************************************
+
+    bool operator==(const WCThreadRef& first, const WCThreadRef& second)
+    {
+        return (first.m_osThreadRef == second.m_osThreadRef);
+    }
+
+    bool operator!=(const WCThreadRef& first, const WCThreadRef& second)
+    {
+        return (first.m_osThreadRef != second.m_osThreadRef);
+    }
+
+    bool operator<(const WCThreadRef& first, const WCThreadRef& second)
+    {
+        return (first.m_osThreadRef < second.m_osThreadRef);
+    }
+
+    bool operator>(const WCThreadRef& first, const WCThreadRef& second)
+    {
+        return (first.m_osThreadRef > second.m_osThreadRef);
+    }
+
+    bool WCAtomicLock::obtain(const uint32_t in_num_trys)
+    {
+        bool retVal = false;
+        
+        uint32_t timeOut = in_num_trys;
+        while (true)
+        {
+            retVal = Akupara::threading::atomic::compare_and_store<int32_t>(&m_the_lock, int32_t(0), int32_t(1));
+            if (retVal)
+            {
+                break;
+            }
+            else
+            {
+                if (--timeOut == 0)
+                {
+                    break;
+                }
+                sleep_milliseconds(1000);
+            }
+        }
+        
+        return retVal;
+    }
+
+    void WCAtomicLock::release()
+    {
+        m_the_lock = 0;
+    }
+
+} //    namespace wvThread
+} // namespace wvNS {
+
diff --git a/libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.h b/libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.h
new file mode 100644 (file)
index 0000000..c97808b
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __WCThreadSafe_h_
+       #define __WCThreadSafe_h_
+
+/* Copy to include
+#include "Threads/WCThreadSafe.h"
+*/
+
+//
+// * WCThreadSafe.h (used to be called XPlatformOSServices.hpp)
+// *
+// * Consistent C++ interfaces to common Operating System services.
+// *
+// *
+// *
+// *
+// * Created 2004-December-13 by Udi Barzilai as XPlatformOSServices.hpp
+// * Moved to WCThreadSafe.h by Shai 26/10/2005
+// * 26/10/2005:       ThreadMutex now inhetites from ThreadMutexInited
+// *                           namespace changed to wvThread
+
+#include "WavesPublicAPI/wstdint.h"
+#include <string>
+
+#include "BasicTypes/WUDefines.h"
+
+#if defined(__linux__) || defined(__MACOS__)
+       #define XPLATFORMOSSERVICES_UNIX  1
+#endif
+
+#if defined(_WIN32)
+       #define XPLATFORMOSSERVICES_WIN32 1
+#endif
+
+#if XPLATFORMOSSERVICES_WIN32
+       #define XPLATFORMTHREADS_WINDOWS 1
+#elif XPLATFORMOSSERVICES_UNIX
+       #define XPLATFORMTHREADS_POSIX   1
+#endif
+namespace wvNS {
+typedef uint32_t WTThreadSafetyType;
+const WTThreadSafetyType kNoThreadSafetyNeeded = 0;
+const WTThreadSafetyType kpthreadsmutexThreadSafety = 1;
+
+
+namespace wvThread
+{
+    //#include "BasicTypes/WavesAPISetAligment.h"
+    //Packing affects the layout of classes, and commonly, if packing changes across header files, there can be problems. 
+#ifdef _WINDOWS
+#pragma pack(push)
+#pragma pack(8)
+#endif
+
+#ifdef __MACOS__
+#ifdef __GNUC__
+#pragma pack(push, 8)
+#endif
+#endif
+
+       //--------------------------------------------------------
+       typedef  int32_t timediff;    // in microseconds
+       static const timediff ktdOneSecond = 1000*1000;
+       //--------------------------------------------------------
+       class timestamp
+       {
+       protected:
+               typedef uint32_t tickcount;
+               tickcount m_nMicroseconds;  // may wrap around
+               static const tickcount ms_knWraparoundThreshold = ~tickcount(0) ^ (~tickcount(0)>>1);  // half the range
+
+       public:
+       timestamp() : m_nMicroseconds(0) { /* uninitialized */ }
+       timestamp(const timestamp &_ts) : m_nMicroseconds(_ts.m_nMicroseconds) {}
+       timestamp &operator=(const timestamp &_rhs) { m_nMicroseconds = _rhs.m_nMicroseconds; return *this; }
+       explicit timestamp(tickcount _i) : m_nMicroseconds(_i) {}
+       uint32_t ticks() const { return m_nMicroseconds; }
+               timediff operator-(timestamp _rhs) const { return timediff(m_nMicroseconds-_rhs.m_nMicroseconds); }
+               timestamp & operator+=(timediff _t) { m_nMicroseconds+=_t; return *this; }
+               timestamp & operator-=(timediff _t) { m_nMicroseconds-=_t; return *this; }
+               timestamp operator+(timediff _t) const { return timestamp(m_nMicroseconds+_t); }
+               timestamp operator-(timediff _t) const { return timestamp(m_nMicroseconds-_t); }
+               bool operator==(timestamp _rhs) const { return m_nMicroseconds==_rhs.m_nMicroseconds; }
+               bool operator!=(timestamp _rhs) const { return m_nMicroseconds!=_rhs.m_nMicroseconds; }
+               bool operator< (timestamp _rhs) const { return m_nMicroseconds-_rhs.m_nMicroseconds >= ms_knWraparoundThreshold; }
+        static timestamp null() { return timestamp(0); }
+        bool is_null() const { return m_nMicroseconds==0; }
+       };
+       //--------------------------------------------------------
+#ifdef __MACOS__
+       bool FindNetInterfaceByIPAddress(const char *sIP, char *sInterface);
+#endif // MACOS
+       //--------------------------------------------------------
+       timestamp now();
+       //--------------------------------------------------------
+       DllExport void sleep(timediff);
+       DllExport void sleep_milliseconds(unsigned int nMillisecs);
+       //--------------------------------------------------------
+    void yield();
+    //--------------------------------------------------------
+
+
+
+       typedef uintptr_t os_dependent_handle_type;
+
+       //--------------------------------------------------------
+       typedef int    ThreadFunctionReturnType;
+       typedef void * ThreadFunctionArgument;
+       //--------------------------------------------------------
+       typedef ThreadFunctionReturnType (ThreadFunction)(ThreadFunctionArgument);
+       //--------------------------------------------------------
+       class ThreadHandle
+       {
+       public:
+               class OSDependent;
+       protected:
+               uintptr_t m_oshandle;                                                                   // hopefully this is good enough for all systems
+       public:
+               static const ThreadHandle Invalid;
+       protected:
+               ThreadHandle(uintptr_t n) : m_oshandle(n) {} 
+       public:
+               ThreadHandle() : m_oshandle(Invalid.m_oshandle) {}
+               bool is_invalid() const { return !m_oshandle || m_oshandle==Invalid.m_oshandle; }
+       };
+       //--------------------------------------------------------
+       class ThreadPriority
+       {
+       public: enum value { BelowNormal=1, Normal=2, AboveNormal=3, TimeCritical=4 };
+       protected: value m_value;
+       public: ThreadPriority(value v) : m_value(v) {}
+       public: operator value() const { return m_value; }
+       };
+       //--------------------------------------------------------
+       void SetMyThreadPriority(ThreadPriority);
+       //--------------------------------------------------------
+       ThreadHandle StartThread(ThreadFunction, ThreadFunctionArgument, ThreadPriority=ThreadPriority::Normal);
+       bool JoinThread(ThreadHandle, ThreadFunctionReturnType * = 0);
+       bool KillThread(ThreadHandle);  // use only for abnormal termination
+       void Close(ThreadHandle); // should be called once for every handle obtained from StartThread.
+       //--------------------------------------------------------
+
+
+
+    
+       //--------------------------------------------------------
+    class DllExport noncopyableobject
+       {
+       protected:
+               noncopyableobject() {}
+       private:
+               noncopyableobject(const noncopyableobject &);
+               noncopyableobject & operator=(const noncopyableobject &);
+       };
+       //--------------------------------------------------------
+
+
+       //--------------------------------------------------------
+       // Thread Mutex class that needs to be explicitly initialized
+       class DllExport ThreadMutexInited : public noncopyableobject
+       {
+       protected:
+               class OSDependentMutex;
+               OSDependentMutex* m_osdmutex;
+
+       public:
+               ThreadMutexInited();
+               ~ThreadMutexInited();
+
+               void init();
+               void uninit();
+               inline bool is_init() { return 0 != m_osdmutex; }
+               void obtain();
+               bool tryobtain();
+               void release();
+       
+       private:
+               ThreadMutexInited(const ThreadMutexInited&);            // cannot be copied
+               ThreadMutexInited& operator=(const ThreadMutexInited&); // cannot be copied
+
+       public:
+               class lock : public noncopyableobject
+               {
+               protected:
+                       ThreadMutexInited &m_mutex;
+               public:
+                       inline lock(ThreadMutexInited &mtx) : m_mutex(mtx) { m_mutex.obtain(); }
+                       inline ~lock() { m_mutex.release(); }
+               };
+               class trylock : public noncopyableobject
+               {
+               protected:
+                       ThreadMutexInited &m_mutex;
+                       bool         m_bObtained;
+               public:
+                       inline trylock(ThreadMutexInited &mtx) : m_mutex(mtx), m_bObtained(false) { m_bObtained = m_mutex.tryobtain(); }
+                       inline ~trylock() { if (m_bObtained) m_mutex.release(); }
+                       inline operator bool() const { return m_bObtained; }
+               };
+       };
+       //--------------------------------------------------------
+
+       // Thread Mutex class that is automatically initialized
+       class ThreadMutex : public ThreadMutexInited 
+       {
+       public:
+               ThreadMutex() {init();}
+       };
+       
+       //--------------------------------------------------------
+       class DllExport ThreadConditionSignal : public noncopyableobject
+       {
+       protected:
+               class OSDependentObject;
+               OSDependentObject &m_osdepobj;
+
+       protected:
+               void obtain_mutex();
+               bool tryobtain_mutex();
+               void release_mutex();
+
+       public:
+               class lock : public noncopyableobject
+               {
+               protected:
+                       ThreadConditionSignal &m_tcs;
+               public:
+                       lock(ThreadConditionSignal &tcs) : m_tcs(tcs) { m_tcs.obtain_mutex(); }
+                       ~lock() { m_tcs.release_mutex(); }
+               };
+               class trylock : public noncopyableobject
+               {
+               protected:
+                       ThreadConditionSignal &m_tcs;
+                       bool                   m_bObtained;
+               public:
+                       trylock(ThreadConditionSignal &tcs) : m_tcs(tcs), m_bObtained(false) { m_bObtained = m_tcs.tryobtain_mutex(); }
+                       ~trylock() { if (m_bObtained) m_tcs.release_mutex(); }
+                       operator bool() const { return m_bObtained; }
+               };
+
+       public:
+               ThreadConditionSignal();
+               ~ThreadConditionSignal();
+
+               // IMPORTANT: All of the functions below MUST be called ONLY while holding a lock for this object !!!
+               void await_condition();
+               bool await_condition(timediff tdTimeout);
+               void signal_condition_single();
+               void signal_condition_broadcast();
+       };
+       //--------------------------------------------------------
+
+
+
+
+
+       //--------------------------------------------------------
+       // A doorbell is a simple communication mechanism that allows
+       // one thread two wake another when there is some work to be done.
+       // The signal is 'clear on read'. This class is not intended for
+       // multi-way communication (i.e. more than two threads).
+//#define XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR (!XPLATFORMTHREADS_WINDOWS && !XPLATFORMOSSERVICES_MACOS)
+#ifdef XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
+#undef XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
+#endif
+#define XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR 1
+#if XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
+       class doorbell_type
+       {
+       protected:
+               ThreadConditionSignal m_signal;
+               bool m_rang;
+       protected:
+               template<bool wait_forever> bool wait_for_ring_internal(timediff timeout)
+               {// mutex
+                       ThreadConditionSignal::lock guard(m_signal);
+                       if (!m_rang)
+                       {
+                               if (wait_forever)
+                               {
+                                       m_signal.await_condition();
+                               }
+                               else
+                               {
+                                       m_signal.await_condition(timeout);
+                               }
+                       }
+                       const bool rang = m_rang;
+                       m_rang = false;
+                       return rang;
+               }// mutex
+
+       public:
+               doorbell_type() : m_rang(false) {}
+               inline ~doorbell_type() {}
+               inline void ring()
+               {// mutex
+                       ThreadConditionSignal::lock guard(m_signal);
+                       m_rang = true;
+                       m_signal.signal_condition_single();
+               }// mutex
+               inline bool wait_for_ring() { return wait_for_ring_internal<true>(0); }
+               inline bool wait_for_ring(timediff timeout) { return wait_for_ring_internal<false>(timeout); }
+       };
+#else
+       class doorbell_type : public noncopyableobject
+       {
+       protected:
+               os_dependent_handle_type m_os_dependent_handle;
+       protected:
+               template<bool wait_forever> bool wait_for_ring_internal(timediff);
+       public:
+               doorbell_type();
+               ~doorbell_type();
+               void ring();
+               bool wait_for_ring();
+               bool wait_for_ring(timediff timeout);
+       };
+#endif // XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
+       //--------------------------------------------------------
+
+       //---------------------------------------------------------------
+       class DllExport WCThreadRef     // Class which holds the threadRef, DWORD in Windows and pthread_t in POSIX (Mac, Unix)
+       {
+       public:
+               class OSDependent;  // the class which contains the OS Dependent implementation
+
+               WCThreadRef() : m_osThreadRef(0) {}
+               bool is_invalid() const { return m_osThreadRef == 0;}
+
+               operator uintptr_t() const {return m_osThreadRef;}
+
+       protected:
+               uintptr_t m_osThreadRef;
+               WCThreadRef(uintptr_t n) : m_osThreadRef(n) {} 
+
+               friend DllExport bool operator==(const WCThreadRef& first, const WCThreadRef& second);
+               friend DllExport bool operator!=(const WCThreadRef& first, const WCThreadRef& second);
+               friend DllExport bool operator<(const WCThreadRef& first, const WCThreadRef& second);
+               friend DllExport bool operator>(const WCThreadRef& first, const WCThreadRef& second);
+       };
+
+       DllExport WCThreadRef GetCurrentThreadRef();    // getting the current thread reference - cross-platform implemented
+       bool IsThreadExists(const WCThreadRef& threadRef);      // correct to the very snapshot of time of execution
+
+       //---------------------------------------------------------------
+
+    class DllExport WCAtomicLock
+    {
+    public:    
+        WCAtomicLock() : m_the_lock(0) {}
+               bool obtain(const uint32_t in_num_trys = 1);
+               void release();
+       private:
+           int32_t m_the_lock;
+    };
+
+    //#include "BasicTypes/WavesAPIResetAligment.h"
+#ifdef _WINDOWS
+#pragma pack(pop)
+#endif
+
+#ifdef __MACOS__
+#ifdef __GNUC__
+#pragma pack(pop)
+#endif
+#endif
+
+class WCStThreadMutexLocker
+{
+public:
+    WCStThreadMutexLocker(wvNS::wvThread::ThreadMutexInited& in_mutex) : 
+    m_mutex(in_mutex)
+    {
+        m_mutex.obtain();
+    }
+    
+    ~WCStThreadMutexLocker()
+    {
+        m_mutex.release();
+    }
+protected:
+    wvNS::wvThread::ThreadMutexInited& m_mutex;
+    WCStThreadMutexLocker(const WCStThreadMutexLocker&);
+    WCStThreadMutexLocker& operator=(const WCStThreadMutexLocker&);
+};
+    
+} // namespace wvThread
+
+
+} //namespace wvNS {
+#endif // #ifndef __WCThreadSafe_h_
diff --git a/libs/backends/wavesaudio/wavesapi/wavespublicapi/1.0/WavesPublicAPI_Defines.h b/libs/backends/wavesaudio/wavesapi/wavespublicapi/1.0/WavesPublicAPI_Defines.h
new file mode 100644 (file)
index 0000000..470ce77
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __WavesPublicAPI_Defines_h__
+       #define __WavesPublicAPI_Defines_h__
+
+/*Copy to include
+#include "WavesPublicAPI_Defines.h"
+*/
+
+#ifdef __MACOS__
+
+    #ifdef __GNUC__
+        #define WPAPI_DllExport __attribute__ ((visibility("default")))
+        #define __WPAPI_CDECL
+        #define __WPAPI_STDCALL
+    
+    #else
+    
+        #define WPAPI_DllExport __declspec(export)
+        #define __WPAPI_CDECL
+        #define __WPAPI_STDCALL
+
+    #endif
+
+#endif
+
+
+#ifdef _WINDOWS
+    #define WPAPI_DllExport __declspec(dllexport)
+       #define __WPAPI_CDECL __cdecl
+       #define __WPAPI_STDCALL __stdcall
+#endif 
+
+#ifdef __linux__
+
+    #define WPAPI_DllExport __attribute__ ((visibility("default")))
+
+       #define __WPAPI_CDECL
+       #define __WPAPI_STDCALL
+
+#endif
+
+#endif //__WavesPublicAPI_Defines_h__
diff --git a/libs/backends/wavesaudio/wavesapi/wavespublicapi/WTErr.h b/libs/backends/wavesaudio/wavesapi/wavespublicapi/WTErr.h
new file mode 100644 (file)
index 0000000..6c6a0b9
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+// \file WTErr.h, defines basic error type and "No Error" code
+// All users may use their own error codes with this type, as long as eNoErr remains defined here
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+#ifndef __WTErr_h__
+#define __WTErr_h__
+
+/* Copy to include:
+#include "WavesPublicAPI/WTErr.h"
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "WavesPublicAPI/wstdint.h"
+
+typedef int32_t        WTErr; // Waves Type Error
+const WTErr eNoErr =  0;
+
+
+#ifdef __cplusplus
+} //extern "C" {
+#endif
+
+#endif // __WTErr_h__
+
diff --git a/libs/backends/wavesaudio/wavesapi/wavespublicapi/wstdint.h b/libs/backends/wavesaudio/wavesapi/wavespublicapi/wstdint.h
new file mode 100644 (file)
index 0000000..a933696
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+    Copyright (C) 2013 Waves Audio Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __stdint_h__
+#define __stdint_h__
+
+/* Copy to include
+#include "wstdint.h"
+*/
+
+
+#ifdef __MACOS__
+       #include <stddef.h>
+       #include </usr/include/stdint.h>  // Mac has this file in /usr/includez
+#endif
+#ifdef __linux__
+       #if ! defined(__STDC_LIMIT_MACROS)
+               #define __STDC_LIMIT_MACROS  
+       #endif
+       
+       #include <stddef.h>
+       #include </usr/include/stdint.h>
+#endif
+
+#if (defined (_WINDOWS) || defined(WIN32) || defined(WIN64))
+#if (_MSC_VER > 1600) || defined(__MINGW64__)
+    // Taken from MSDN official page:
+    // In Visual Studio 2010 _MSC_VER  is defined as 1600, In Visual Studio 2012 _MSC_VER  is defined as 1700.
+    #include <stdint.h>
+#else
+#ifndef _STDINT_H
+    #define _STDINT_H // this will prevent Altura's CGBase.h from defining int32_t
+#endif
+/*
+ * ISO C 99 <stdint.h> for platforms that lack it.
+ * <http://www.opengroup.org/onlinepubs/007904975/basedefs/stdint.h.html>
+ */
+
+/* Get wchar_t, WCHAR_MIN, WCHAR_MAX.  */
+#include <stddef.h>
+/* Get CHAR_BIT, LONG_MIN, LONG_MAX, ULONG_MAX.  */
+#include <limits.h>
+
+/* Get those types that are already defined in other system include files.  */
+#if defined(__FreeBSD__)
+# include <sys/inttypes.h>
+#endif
+
+#if defined(__sun) && HAVE_SYS_INTTYPES_H
+# include <sys/inttypes.h>
+  /* Solaris 7 <sys/inttypes.h> has the types except the *_fast*_t types, and
+     the macros except for *_FAST*_*, INTPTR_MIN, PTRDIFF_MIN, PTRDIFF_MAX.
+     But note that <sys/int_types.h> contains only the type definitions!  */
+# define HAVE_SYSTEM_INTTYPES
+#endif
+#if (defined(__hpux) || defined(_AIX)) && HAVE_INTTYPES_H
+# include <inttypes.h>
+  /* HP-UX 10 <inttypes.h> has nearly everything, except UINT_LEAST8_MAX,
+     UINT_FAST8_MAX, PTRDIFF_MIN, PTRDIFF_MAX.  */
+  /* AIX 4 <inttypes.h> has nearly everything, except INTPTR_MIN, INTPTR_MAX,
+     UINTPTR_MAX, PTRDIFF_MIN, PTRDIFF_MAX.  */
+# define HAVE_SYSTEM_INTTYPES
+#endif
+#if !(defined(UNIX_CYGWIN32) && defined(__BIT_TYPES_DEFINED__))
+# define NEED_SIGNED_INT_TYPES
+#endif
+
+#if !defined(HAVE_SYSTEM_INTTYPES)
+
+/* 7.18.1.1. Exact-width integer types */
+#if !defined(__FreeBSD__)
+
+#if defined(_MSC_VER)
+typedef          __int8  int8_t;
+typedef unsigned __int8  uint8_t;
+typedef          __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef          __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef          __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+#else // _MSC_VER
+
+#ifdef NEED_SIGNED_INT_TYPES
+typedef signed char    int8_t;
+#endif
+typedef unsigned char  uint8_t;
+
+#ifdef NEED_SIGNED_INT_TYPES
+typedef short          int16_t;
+#endif
+typedef unsigned short uint16_t;
+
+#ifdef NEED_SIGNED_INT_TYPES
+typedef int            int32_t;
+#endif
+typedef unsigned int   uint32_t;
+
+#if 0
+#ifdef NEED_SIGNED_INT_TYPES
+typedef long           int64_t;
+#endif
+typedef unsigned long  uint64_t;
+#elif 0
+#ifdef NEED_SIGNED_INT_TYPES
+typedef long long          int64_t;
+#endif
+typedef unsigned long long uint64_t;
+#endif
+
+#endif // _MSC_VER
+
+#endif /* !FreeBSD */
+
+/* 7.18.1.2. Minimum-width integer types */
+
+typedef int8_t   int_least8_t;
+typedef uint8_t  uint_least8_t;
+typedef int16_t  int_least16_t;
+typedef uint16_t uint_least16_t;
+#if !defined(kAlturaAlreadyDefinesInt32)
+typedef int32_t  int_least32_t;
+#endif
+typedef uint32_t uint_least32_t;
+typedef int64_t  int_least64_t;
+typedef uint64_t uint_least64_t;
+
+
+/* 7.18.1.3. Fastest minimum-width integer types */
+
+typedef int32_t  int_fast8_t;
+typedef uint32_t uint_fast8_t;
+typedef int32_t  int_fast16_t;
+typedef uint32_t uint_fast16_t;
+typedef int32_t  int_fast32_t;
+typedef uint32_t uint_fast32_t;
+typedef int64_t  int_fast64_t;
+typedef uint64_t uint_fast64_t;
+
+
+/* 7.18.1.4. Integer types capable of holding object pointers */
+
+#if !defined(__FreeBSD__)
+
+/* On some platforms (like IRIX6 MIPS with -n32) sizeof(void*) < sizeof(long),
+   but this doesn't matter here.  */
+#if !defined(_INTPTR_T_DEFINED)
+typedef long          intptr_t;
+#define _INTPTR_T_DEFINED
+#endif
+#if !defined(_UINTPTR_T_DEFINED)
+typedef unsigned long uintptr_t;
+#define _UINTPTR_T_DEFINED
+#endif
+
+#endif /* !FreeBSD */
+
+/* 7.18.1.5. Greatest-width integer types */
+
+
+typedef int64_t  intmax_t;
+typedef uint64_t uintmax_t;
+#if 0 || 0
+typedef int32_t  intmax_t;
+typedef uint32_t uintmax_t;
+#endif
+
+/* 7.18.2. Limits of specified-width integer types */
+
+//#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
+
+/* 7.18.2.1. Limits of exact-width integer types */
+
+#define INT8_MIN  -128
+#define INT8_MAX   127
+#define UINT8_MAX  255U
+#define INT16_MIN  -32768
+#define INT16_MAX   32767
+#define UINT16_MAX  65535U
+#define INT32_MIN   (~INT32_MAX)
+#define INT32_MAX   2147483647
+#define UINT32_MAX  4294967295U
+#if 0
+#define INT64_MIN   (~INT64_MIN)
+#define INT64_MAX   9223372036854775807L
+#define UINT64_MAX 18446744073709551615UL
+#elif 0
+#define INT64_MIN   (~INT64_MIN)
+#define INT64_MAX   9223372036854775807LL
+#define UINT64_MAX 18446744073709551615ULL
+#endif
+
+/* 7.18.2.2. Limits of minimum-width integer types */
+
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#if 0 || 0
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+#endif
+
+/* 7.18.2.3. Limits of fastest minimum-width integer types */
+
+#define INT_FAST8_MIN INT32_MIN
+#define INT_FAST8_MAX INT32_MAX
+#define UINT_FAST8_MAX UINT32_MAX
+#define INT_FAST16_MIN INT32_MIN
+#define INT_FAST16_MAX INT32_MAX
+#define UINT_FAST16_MAX UINT32_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#if 0 || 0
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+#endif
+
+/* 7.18.2.4. Limits of integer types capable of holding object pointers */
+
+#define INTPTR_MIN LONG_MIN
+#define INTPTR_MAX LONG_MAX
+#define UINTPTR_MAX ULONG_MAX
+
+/* 7.18.2.5. Limits of greatest-width integer types */
+
+#if 0 || 0
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+#else
+#define INTMAX_MIN INT32_MIN
+#define INTMAX_MAX INT32_MAX
+#define UINTMAX_MAX UINT32_MAX
+#endif
+
+/* 7.18.3. Limits of other integer types */
+
+#define PTRDIFF_MIN (~(ptrdiff_t)0 << (sizeof(ptrdiff_t)*CHAR_BIT-1))
+#define PTRDIFF_MAX (~PTRDIFF_MIN)
+
+/* This may be wrong...  */
+#define SIG_ATOMIC_MIN 0
+#define SIG_ATOMIC_MAX 127
+
+//#define SIZE_MAX (~(size_t)0)
+
+/* wchar_t limits already defined in <stddef.h>.  */
+/* wint_t limits already defined in <wchar.h>.  */
+
+//#endif
+
+/* 7.18.4. Macros for integer constants */
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
+
+/* 7.18.4.1. Macros for minimum-width integer constants */
+
+#ifdef INT8_C
+#undef INT8_C
+#endif
+#define INT8_C(x) x
+
+#ifdef UINT8_C
+#undef UINT8_C
+#endif
+#define UINT8_C(x) x##U
+
+#ifdef INT16_C
+#undef INT16_C
+#endif
+#define INT16_C(x) x
+
+#ifdef UINT16_C
+#undef UINT16_C
+#endif
+#define UINT16_C(x) x##U
+
+#ifdef INT32_C
+#undef INT32_C
+#endif
+#define INT32_C(x) x
+
+#ifdef UINT32_C
+#undef UINT32_C
+#endif
+#define UINT32_C(x) x##U
+
+// INT64_C and UINT64_C definitions
+#ifdef INT64_C
+#undef INT64_C
+#endif
+#ifdef UINT64_C
+#undef UINT64_C
+#endif
+#if 0
+#define INT64_C(x) x##L
+#define UINT64_C(x) x##UL
+#elif 0
+#define INT64_C(x) x##LL
+#define UINT64_C(x) x##ULL
+#endif // #if 0
+
+/* 7.18.4.2. Macros for greatest-width integer constants */
+
+// INTMAX_C and UINTMAX_C definitions
+#ifdef INTMAX_C
+#undef INTMAX_C
+#endif
+#ifdef UINTMAX_C
+#undef UINTMAX_C
+#endif
+
+#if 0
+#define INTMAX_C(x) x##L
+#define UINTMAX_C(x) x##UL
+#elif 0
+#define INTMAX_C(x) x##LL
+#define UINTMAX_C(x) x##ULL
+#else
+#define INTMAX_C(x) x
+#define UINTMAX_C(x) x##U
+#endif
+
+#endif
+
+#endif  /* !HAVE_SYSTEM_INTTYPES */
+
+#endif /* (_MSC_VER < 1400) */
+
+#endif /* #ifdef _WINDOWS */
+
+#endif /* __stdint_h__ */
diff --git a/libs/backends/wavesaudio/wscript b/libs/backends/wavesaudio/wscript
new file mode 100644 (file)
index 0000000..2d4ee0a
--- /dev/null
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+from waflib.extras import autowaf as autowaf
+import os
+import sys
+import re
+
+# Library version (UNIX style major, minor, micro)
+# major increment <=> incompatible changes
+# minor increment <=> compatible changes (additions)
+# micro increment <=> no interface changes
+WAVESAUDIOBACKEND_VERSION = '0.0.1'
+I18N_PACKAGE = 'wavesaudio-backend'
+
+# Mandatory variables
+top = '.'
+out = 'build'
+
+def options(opt):
+    autowaf.set_options(opt)
+
+def configure(conf):
+    autowaf.configure(conf)
+    
+def build(bld):
+    obj = bld(features = 'cxx cxxshlib')
+    if bld.env['build_target'] == 'mountain_lion':
+        obj.framework = 'CoreMidi'
+    else:
+        obj.framework = 'CoreMIDI'
+    obj.source = [
+            'waves_audiobackend.cc',
+            'waves_audiobackend.latency.cc',
+            'waves_audiobackend.midi.cc',
+            'waves_audiobackend.port_engine.cc',
+            'waves_dataport.cc',
+            'waves_audioport.cc',
+            'waves_midiport.cc',
+            'waves_midi_device_manager.cc',
+            'waves_midi_device.cc',
+            'waves_midi_event.cc',
+            'waves_midi_buffer.cc',
+            'wavesapi/refmanager/WCRefManager.cpp',
+            'wavesapi/devicemanager/WCMRAudioDeviceManager.cpp',
+            'wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp',
+            'wavesapi/devicemanager/WCMRNativeAudio.cpp',
+            'wavesapi/threads/WCThreadSafe.cpp',
+                       'portmidi/src/pm_common/pmutil.c',
+                       'portmidi/src/pm_common/portmidi.c',
+                       'portmidi/src/pm_mac/pmmac.c',
+                       'portmidi/src/pm_mac/pmmacosxcm.c',
+                       'portmidi/src/pm_mac/finddefault.c',
+                       'portmidi/src/pm_mac/readbinaryplist.c',
+                       'portmidi/src/porttime/ptmacosx_mach.c'
+            ]
+    obj.includes = ['.',
+           'wavesapi',
+           'wavesapi/refmanager',
+           'wavesapi/wavespublicapi',
+           'wavesapi/devicemanager',
+           'wavesapi/miscutils',
+           'portmidi',
+           'portmidi/src/pm_common'
+            ]
+    obj.cxxflags = [ '-fPIC' ]
+    obj.name     = 'waves_audiobackend'
+    obj.target   = 'waves_audiobackend'
+    obj.use      = [ 'libardour', 'libpbd' ]
+    obj.vnum     = WAVESAUDIOBACKEND_VERSION
+    obj.install_path  = os.path.join(bld.env['LIBDIR'], 'ardour3', 'backends')
+    obj.defines = ['PACKAGE="' + I18N_PACKAGE + '"',
+            '__MACOS__',
+            'ARDOURBACKEND_DLL_EXPORTS'
+            ]