2nd attempt at updated Waves audio backend, with added -fms-extensions as previously...
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 30 Apr 2014 17:46:41 +0000 (13:46 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Wed, 30 Apr 2014 17:46:41 +0000 (13:46 -0400)
58 files changed:
libs/backends/wavesaudio/portmidi/pmutil.h
libs/backends/wavesaudio/portmidi/src/pm_common/pminternal.h
libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.c
libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.h
libs/backends/wavesaudio/portmidi/src/pm_mac/pmmacosxcm.h
libs/backends/wavesaudio/portmidi/src/pm_mac/readbinaryplist.c
libs/backends/wavesaudio/portmidi/src/pm_win/pmwin.c
libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.c
libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.h
libs/backends/wavesaudio/portmidi/src/porttime/ptmacosx_mach.c
libs/backends/wavesaudio/waves_audiobackend.cc
libs/backends/wavesaudio/waves_audiobackend.h
libs/backends/wavesaudio/waves_audiobackend.latency.cc
libs/backends/wavesaudio/waves_audiobackend.midi.cc
libs/backends/wavesaudio/waves_audiobackend.port_engine.cc
libs/backends/wavesaudio/waves_audioport.cc
libs/backends/wavesaudio/waves_audioport.h
libs/backends/wavesaudio/waves_dataport.cc
libs/backends/wavesaudio/waves_dataport.h
libs/backends/wavesaudio/waves_midi_buffer.cc
libs/backends/wavesaudio/waves_midi_buffer.h
libs/backends/wavesaudio/waves_midi_device.cc
libs/backends/wavesaudio/waves_midi_device.h
libs/backends/wavesaudio/waves_midi_device_manager.cc
libs/backends/wavesaudio/waves_midi_device_manager.h
libs/backends/wavesaudio/waves_midi_event.cc
libs/backends/wavesaudio/waves_midi_event.h
libs/backends/wavesaudio/waves_midiport.cc
libs/backends/wavesaudio/waves_midiport.h
libs/backends/wavesaudio/wavesapi/BasicTypes/WCFourCC.h
libs/backends/wavesaudio/wavesapi/BasicTypes/WTByteOrder.h
libs/backends/wavesaudio/wavesapi/BasicTypes/WUComPtr.h
libs/backends/wavesaudio/wavesapi/BasicTypes/WUDefines.h
libs/backends/wavesaudio/wavesapi/BasicTypes/WUMathConsts.h
libs/backends/wavesaudio/wavesapi/BasicTypes/WUTypes.h
libs/backends/wavesaudio/wavesapi/devicemanager/IncludeWindows.h
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.cpp
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.h
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.cpp
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.h
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.cpp [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.h [new file with mode: 0644]
libs/backends/wavesaudio/wavesapi/miscutils/MinMaxUtilities.h
libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.cpp
libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.h
libs/backends/wavesaudio/wavesapi/miscutils/WCFixedString.h
libs/backends/wavesaudio/wavesapi/miscutils/WUErrors.h
libs/backends/wavesaudio/wavesapi/miscutils/safe_delete.h
libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.cpp
libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.h
libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.cpp
libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.h
libs/backends/wavesaudio/wavesapi/wavespublicapi/1.0/WavesPublicAPI_Defines.h
libs/backends/wavesaudio/wavesapi/wavespublicapi/WTErr.h
libs/backends/wavesaudio/wavesapi/wavespublicapi/wstdint.h
libs/backends/wavesaudio/wscript [changed mode: 0644->0755]

index 40dabbff0e769a13e47e145aa6449394d59802ec..ef5ee4bf84aefa3cb9758664876603a2f6b15377 100644 (file)
-/* 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
+/* pmutil.h -- some helpful utilities for building midi 
+               applications that use PortMidi 
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef void PmQueue;
+
+/*
+    A single-reader, single-writer queue is created by
+    Pm_QueueCreate(), which takes the number of messages and
+    the message size as parameters. The queue only accepts
+    fixed sized messages. Returns NULL if memory cannot be allocated.
+
+    This queue implementation uses the "light pipe" algorithm which
+    operates correctly even with multi-processors and out-of-order
+    memory writes. (see Alexander Dokumentov, "Lock-free Interprocess
+    Communication," Dr. Dobbs Portal, http://www.ddj.com/, 
+    articleID=189401457, June 15, 2006. This algorithm requires
+    that messages be translated to a form where no words contain
+    zeros. Each word becomes its own "data valid" tag. Because of
+    this translation, we cannot return a pointer to data still in 
+    the queue when the "peek" method is called. Instead, a buffer 
+    is preallocated so that data can be copied there. Pm_QueuePeek() 
+    dequeues a message into this buffer and returns a pointer to 
+    it. A subsequent Pm_Dequeue() will copy from this buffer.
+
+    This implementation does not try to keep reader/writer data in
+    separate cache lines or prevent thrashing on cache lines. 
+    However, this algorithm differs by doing inserts/removals in
+    units of messages rather than units of machine words. Some
+    performance improvement might be obtained by not clearing data
+    immediately after a read, but instead by waiting for the end
+    of the cache line, especially if messages are smaller than
+    cache lines. See the Dokumentov article for explanation.
+
+    The algorithm is extended to handle "overflow" reporting. To report
+    an overflow, the sender writes the current tail position to a field.
+    The receiver must acknowlege receipt by zeroing the field. The sender
+    will not send more until the field is zeroed.
+    
+    Pm_QueueDestroy() destroys the queue and frees its storage.
+ */
+
+PMEXPORT PmQueue *Pm_QueueCreate(long num_msgs, int32_t bytes_per_msg);
+PMEXPORT PmError Pm_QueueDestroy(PmQueue *queue);
+
+/* 
+    Pm_Dequeue() removes one item from the queue, copying it into msg.
+    Returns 1 if successful, and 0 if the queue is empty.
+    Returns pmBufferOverflow if what would have been the next thing
+    in the queue was dropped due to overflow. (So when overflow occurs,
+    the receiver can receive a queue full of messages before getting the
+    overflow report. This protocol ensures that the reader will be 
+    notified when data is lost due to overflow.
+ */
+PMEXPORT PmError Pm_Dequeue(PmQueue *queue, void *msg);
+
+
+/*
+    Pm_Enqueue() inserts one item into the queue, copying it from msg.
+    Returns pmNoError if successful and pmBufferOverflow if the queue was 
+    already full. If pmBufferOverflow is returned, the overflow flag is set.
+ */
+PMEXPORT PmError Pm_Enqueue(PmQueue *queue, void *msg);
+
+
+/*
+    Pm_QueueFull() returns non-zero if the queue is full
+    Pm_QueueEmpty() returns non-zero if the queue is empty
+
+    Either condition may change immediately because a parallel
+    enqueue or dequeue operation could be in progress. Furthermore,
+    Pm_QueueEmpty() is optimistic: it may say false, when due to 
+    out-of-order writes, the full message has not arrived. Therefore,
+    Pm_Dequeue() could still return 0 after Pm_QueueEmpty() returns
+    false. On the other hand, Pm_QueueFull() is pessimistic: if it
+    returns false, then Pm_Enqueue() is guaranteed to succeed. 
+
+    Error conditions: Pm_QueueFull() returns pmBadPtr if queue is NULL.
+    Pm_QueueEmpty() returns FALSE if queue is NULL.
+ */
+PMEXPORT int Pm_QueueFull(PmQueue *queue);
+PMEXPORT int Pm_QueueEmpty(PmQueue *queue);
+
+
+/*
+    Pm_QueuePeek() returns a pointer to the item at the head of the queue,
+    or NULL if the queue is empty. The item is not removed from the queue.
+    Pm_QueuePeek() will not indicate when an overflow occurs. If you want
+    to get and check pmBufferOverflow messages, use the return value of
+    Pm_QueuePeek() *only* as an indication that you should call 
+    Pm_Dequeue(). At the point where a direct call to Pm_Dequeue() would
+    return pmBufferOverflow, Pm_QueuePeek() will return NULL but internally
+    clear the pmBufferOverflow flag, enabling Pm_Enqueue() to resume
+    enqueuing messages. A subsequent call to Pm_QueuePeek()
+    will return a pointer to the first message *after* the overflow. 
+    Using this as an indication to call Pm_Dequeue(), the first call
+    to Pm_Dequeue() will return pmBufferOverflow. The second call will
+    return success, copying the same message pointed to by the previous
+    Pm_QueuePeek().
+
+    When to use Pm_QueuePeek(): (1) when you need to look at the message
+    data to decide who should be called to receive it. (2) when you need
+    to know a message is ready but cannot accept the message.
+
+    Note that Pm_QueuePeek() is not a fast check, so if possible, you 
+    might as well just call Pm_Dequeue() and accept the data if it is there.
+ */
+PMEXPORT void *Pm_QueuePeek(PmQueue *queue);
+
+/*
+    Pm_SetOverflow() allows the writer (enqueuer) to signal an overflow
+    condition to the reader (dequeuer). E.g. when transfering data from 
+    the OS to an application, if the OS indicates a buffer overrun,
+    Pm_SetOverflow() can be used to insure that the reader receives a
+    pmBufferOverflow result from Pm_Dequeue(). Returns pmBadPtr if queue
+    is NULL, returns pmBufferOverflow if buffer is already in an overflow
+    state, returns pmNoError if successfully set overflow state.
+ */
+PMEXPORT PmError Pm_SetOverflow(PmQueue *queue);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
index f7c62705b70b6c64582c51af3d0df407323a573d..6b6242026ddcc349d0f6fca90e6ad4c3e54d988a 100644 (file)
-/* 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
+/* pminternal.h -- header for interface implementations */
+
+/* this file is included by files that implement library internals */
+/* Here is a guide to implementers:
+     provide an initialization function similar to pm_winmm_init()
+     add your initialization function to pm_init()
+     Note that your init function should never require not-standard
+         libraries or fail in any way. If the interface is not available,
+         simply do not call pm_add_device. This means that non-standard
+         libraries should try to do dynamic linking at runtime using a DLL
+         and return without error if the DLL cannot be found or if there
+         is any other failure.
+     implement functions as indicated in pm_fns_type to open, read, write,
+         close, etc.
+     call pm_add_device() for each input and output device, passing it a
+         pm_fns_type structure.
+     assumptions about pm_fns_type functions are given below.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int pm_initialized; /* see note in portmidi.c */
+
+/* these are defined in system-specific file */
+void *pm_alloc(size_t s);
+void pm_free(void *ptr);
+
+/* if an error occurs while opening or closing a midi stream, set these: */
+extern int pm_hosterror;
+extern char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];
+struct pm_internal_struct;
+
+/* these do not use PmInternal because it is not defined yet... */
+typedef PmError (*pm_write_short_fn)(struct pm_internal_struct *midi, 
+                                     PmEvent *buffer);
+typedef PmError (*pm_begin_sysex_fn)(struct pm_internal_struct *midi,
+                                     PmTimestamp timestamp);
+typedef PmError (*pm_end_sysex_fn)(struct pm_internal_struct *midi,
+                                   PmTimestamp timestamp);
+typedef PmError (*pm_write_byte_fn)(struct pm_internal_struct *midi,
+                                    unsigned char byte, PmTimestamp timestamp);
+typedef PmError (*pm_write_realtime_fn)(struct pm_internal_struct *midi,
+                                        PmEvent *buffer);
+typedef PmError (*pm_write_flush_fn)(struct pm_internal_struct *midi,
+                                     PmTimestamp timestamp);
+typedef PmTimestamp (*pm_synchronize_fn)(struct pm_internal_struct *midi);
+/* pm_open_fn should clean up all memory and close the device if any part
+   of the open fails */
+typedef PmError (*pm_open_fn)(struct pm_internal_struct *midi,
+                              void *driverInfo);
+typedef PmError (*pm_abort_fn)(struct pm_internal_struct *midi);
+/* pm_close_fn should clean up all memory and close the device if any
+   part of the close fails. */
+typedef PmError (*pm_close_fn)(struct pm_internal_struct *midi);
+typedef PmError (*pm_poll_fn)(struct pm_internal_struct *midi);
+typedef void (*pm_host_error_fn)(struct pm_internal_struct *midi, char * msg,
+                                 unsigned int len);
+typedef unsigned int (*pm_has_host_error_fn)(struct pm_internal_struct *midi);
+
+typedef struct {
+    pm_write_short_fn write_short; /* output short MIDI msg */
+    pm_begin_sysex_fn begin_sysex; /* prepare to send a sysex message */
+    pm_end_sysex_fn end_sysex; /* marks end of sysex message */
+    pm_write_byte_fn write_byte; /* accumulate one more sysex byte */
+    pm_write_realtime_fn write_realtime; /* send real-time message within sysex */
+    pm_write_flush_fn write_flush; /* send any accumulated but unsent data */
+    pm_synchronize_fn synchronize; /* synchronize portmidi time to stream time */
+    pm_open_fn open;   /* open MIDI device */
+    pm_abort_fn abort; /* abort */
+    pm_close_fn close; /* close device */
+    pm_poll_fn poll;   /* read pending midi events into portmidi buffer */
+    pm_has_host_error_fn has_host_error; /* true when device has had host 
+                                            error message */
+    pm_host_error_fn host_error; /* provide text readable host error message
+                                    for device (clears and resets) */
+} pm_fns_node, *pm_fns_type;
+
+
+/* when open fails, the dictionary gets this set of functions: */
+extern pm_fns_node pm_none_dictionary;
+
+typedef struct {
+    PmDeviceInfo pub; /* some portmidi state also saved in here (for autmatic
+                         device closing (see PmDeviceInfo struct) */
+    void *descriptor; /* ID number passed to win32 multimedia API open */
+    void *internalDescriptor; /* points to PmInternal device, allows automatic 
+                                 device closing */
+    pm_fns_type dictionary;
+} descriptor_node, *descriptor_type;
+
+extern int pm_descriptor_max;
+extern descriptor_type descriptors;
+extern int pm_descriptor_index;
+
+typedef uint32_t (*time_get_proc_type)(void *time_info);
+
+typedef struct pm_internal_struct {
+    int device_id; /* which device is open (index to descriptors) */
+    short write_flag; /* MIDI_IN, or MIDI_OUT */
+    
+    PmTimeProcPtr time_proc; /* where to get the time */
+    void *time_info; /* pass this to get_time() */
+    int32_t buffer_len; /* how big is the buffer or queue? */
+    PmQueue *queue;
+
+    int32_t latency; /* time delay in ms between timestamps and actual output */
+                  /* set to zero to get immediate, simple blocking output */
+                  /* if latency is zero, timestamps will be ignored; */
+                  /* if midi input device, this field ignored */
+    
+    int sysex_in_progress; /* when sysex status is seen, this flag becomes
+        * true until EOX is seen. When true, new data is appended to the
+        * stream of outgoing bytes. When overflow occurs, sysex data is 
+        * dropped (until an EOX or non-real-timei status byte is seen) so
+        * that, if the overflow condition is cleared, we don't start 
+        * sending data from the middle of a sysex message. If a sysex
+        * message is filtered, sysex_in_progress is false, causing the
+        * message to be dropped. */
+    PmMessage sysex_message; /* buffer for 4 bytes of sysex data */
+    int sysex_message_count; /* how many bytes in sysex_message so far */
+
+    int32_t filters; /* flags that filter incoming message classes */
+    int32_t channel_mask; /* filter incoming messages based on channel */
+    PmTimestamp last_msg_time; /* timestamp of last message */
+    PmTimestamp sync_time; /* time of last synchronization */
+    PmTimestamp now; /* set by PmWrite to current time */
+    int first_message; /* initially true, used to run first synchronization */
+    pm_fns_type dictionary; /* implementation functions */
+    void *descriptor; /* system-dependent state */
+    /* the following are used to expedite sysex data */
+    /* on windows, in debug mode, based on some profiling, these optimizations
+     * cut the time to process sysex bytes from about 7.5 to 0.26 usec/byte,
+     * but this does not count time in the driver, so I don't know if it is
+     * important
+     */
+    unsigned char *fill_base; /* addr of ptr to sysex data */
+    uint32_t *fill_offset_ptr; /* offset of next sysex byte */
+    int32_t fill_length; /* how many sysex bytes to write */
+} PmInternal;
+
+
+/* defined by system specific implementation, e.g. pmwinmm, used by PortMidi */
+void pm_init(void); 
+void pm_term(void); 
+
+/* defined by portMidi, used by pmwinmm */
+PmError none_write_short(PmInternal *midi, PmEvent *buffer);
+PmError none_write_byte(PmInternal *midi, unsigned char byte, 
+                        PmTimestamp timestamp);
+PmTimestamp none_synchronize(PmInternal *midi);
+
+PmError pm_fail_fn(PmInternal *midi);
+PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp);
+PmError pm_success_fn(PmInternal *midi);
+PmError pm_add_device(char *interf, char *name, int input, void *descriptor,
+                      pm_fns_type dictionary);
+uint32_t pm_read_bytes(PmInternal *midi, const unsigned char *data, int len,
+                           PmTimestamp timestamp);
+void pm_read_short(PmInternal *midi, PmEvent *event);
+
+#define none_write_flush pm_fail_timestamp_fn
+#define none_sysex pm_fail_timestamp_fn
+#define none_poll pm_fail_fn
+#define success_poll pm_success_fn
+
+#define MIDI_REALTIME_MASK 0xf8
+#define is_real_time(msg) \
+    ((Pm_MessageStatus(msg) & MIDI_REALTIME_MASK) == MIDI_REALTIME_MASK)
+
+int pm_find_default_device(char *pattern, int is_input);
+
+#ifdef __cplusplus
+}
+#endif
+
index 13ac68300441e582ac52e08c37c555a054b46260..bcef0d1f1c14b6d6c1083983659dfd4587c8f605 100644 (file)
@@ -1,59 +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
+/* pmmac.c -- PortMidi os-dependent code */
+
+/* This file only needs to implement:
+pm_init(), which calls various routines to register the 
+available midi devices,
+Pm_GetDefaultInputDeviceID(), and
+Pm_GetDefaultOutputDeviceID().
+It is seperate from pmmacosxcm because we might want to register
+non-CoreMIDI devices.
+*/
+
+#include "stdlib.h"
+#include "portmidi.h"
+#include "pmutil.h"
+#include "pminternal.h"
+#include "pmmacosxcm.h"
+
+PmDeviceID pm_default_input_device_id = -1;
+PmDeviceID pm_default_output_device_id = -1;
+
+void pm_init()
+{
+    PmError err = pm_macosxcm_init();
+    // this is set when we return to Pm_Initialize, but we need it
+    // now in order to (successfully) call Pm_CountDevices()
+    pm_initialized = TRUE;
+    if (!err) {
+        pm_default_input_device_id = find_default_device(
+                "/PortMidi/PM_RECOMMENDED_INPUT_DEVICE", TRUE, 
+                pm_default_input_device_id);
+        pm_default_output_device_id = find_default_device(
+                "/PortMidi/PM_RECOMMENDED_OUTPUT_DEVICE", FALSE, 
+                pm_default_output_device_id);
+    }
+}
+
+
+void pm_term(void)
+{
+    pm_macosxcm_term();
+}
+
+
+PmDeviceID Pm_GetDefaultInputDeviceID()
+{
+    Pm_Initialize();
+    return pm_default_input_device_id;
+}
+
+PmDeviceID Pm_GetDefaultOutputDeviceID() {
+    Pm_Initialize();
+    return pm_default_output_device_id;
+}
+
+void *pm_alloc(size_t s) { return malloc(s); }
+
+void pm_free(void *ptr) { free(ptr); }
+
+
index 2d714254ea71512d76d23af158fcac9c059750cc..6cc0392c3f454d705b8e670994a71951329dd57b 100644 (file)
@@ -1,4 +1,4 @@
-/* pmmac.h */\r
-\r
-extern PmDeviceID pm_default_input_device_id;\r
+/* pmmac.h */
+
+extern PmDeviceID pm_default_input_device_id;
 extern PmDeviceID pm_default_output_device_id;
\ No newline at end of file
index 97235b5dd203ac55c1a1293760d7bc1c4f6af73d..ea79902d40b9c5e4d21e3d032c4226e27c5340fc 100644 (file)
@@ -1,6 +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
+/* system-specific definitions */
+
+PmError pm_macosxcm_init(void);
+void pm_macosxcm_term(void);
+
+PmDeviceID find_default_device(char *path, int input, PmDeviceID id);
index bccd09518310cace8b6fbba688d133639181ef39..d8ed8fbabc8e342deab86c66f09384928e41ced0 100644 (file)
-/*\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
+/*
+
+readbinaryplist.c -- Roger B. Dannenberg, Jun 2008
+Based on ReadBinaryPList.m by Jens Ayton, 2007
+
+Note that this code is intended to read preference files and has an upper
+bound on file size (currently 100MB) and assumes in some places that 32 bit
+offsets are sufficient.
+
+Here are his comments:
+
+Reader for binary property list files (version 00).
+
+This has been found to work on all 566 binary plists in my ~/Library/Preferences/
+and /Library/Preferences/ directories. This probably does not provide full
+test coverage. It has also been found to provide different data to Apple's
+implementation when presented with a key-value archive. This is because Apple's
+implementation produces undocumented CFKeyArchiverUID objects. My implementation
+produces dictionaries instead, matching the in-file representation used in XML
+and OpenStep plists. See extract_uid().
+
+Full disclosure: in implementing this software, I read one comment and one
+struct defintion in CFLite, Apple's implementation, which is under the APSL
+license. I also deduced the information about CFKeyArchiverUID from that code.
+However, none of the implementation was copied.
+
+Copyright (C) 2007 Jens Ayton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+*/
+
+/* A note about memory management:
+Strings and possibly other values are unique and because the values
+associated with IDs are cached, you end up with a directed graph rather
+than a tree. It is tricky to free the data because if you do a simple
+depth-first search to free nodes, you will free nodes twice. I decided
+to allocate memory from blocks of 1024 bytes and keep the blocks in a
+list associated with but private to this module. So the user should
+access this module by calling:
+    bplist_read_file() or bplist_read_user_pref() or 
+    bplist_read_system_pref()
+which returns a value. When you are done with the value, call
+    bplist_free_data()
+This will of course free the value_ptr returned by bplist_read_*()
+
+To deal with memory exhaustion (what happens when malloc returns
+NULL?), use setjmp/longjmp -- a single setjmp protects the whole
+parser, and allocate uses longjmp to abort. After abort, memory
+is freed and NULL is returned to caller. There is not much here
+in the way of error reporting.
+
+Memory is obtained by calling allocate which either returns the
+memory requested or calls longjmp, so callers don't have to check.
+
+*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include "readbinaryplist.h"
+#include <Carbon/Carbon.h>
+
+#define NO 0
+#define YES 1
+#define BOOL int
+
+#define MAXPATHLEN 256
+
+/* there are 2 levels of error logging/printing:
+ *   BPLIST_LOG and BPLIST_LOG_VERBOSE
+ * either or both can be set to non-zero to turn on
+ * If BPLIST_LOG_VERBOSE is true, then BPLIST_LOG 
+ * is also true.
+ * 
+ * In the code, logging is done by calling either
+ * bplist_log() or bplist_log_verbose(), which take
+ * parameters like printf but might be a no-op.
+ */
+/* #define BPLIST_LOG_VERBOSE 1 */
+
+#if BPLIST_LOG_VERBOSE
+    #ifndef BPLIST_LOG
+        #define BPLIST_LOG 1
+    #endif
+#endif
+
+#if BPLIST_LOG
+    #define bplist_log printf
+#else
+    #define bplist_log(...)
+#endif
+
+#if BPLIST_LOG_VERBOSE
+    #define bplist_log_verbose bplist_log
+#else
+    #define bplist_log_verbose(...)
+#endif
+
+
+/********* MEMORY MANAGEMENT ********/
+#define BLOCK_SIZE 1024
+// memory is aligned to multiples of this; assume malloc automatically
+// aligns to this number and assume this number is > sizeof(void *)
+#define ALIGNMENT 8
+static void *block_list = NULL;
+static char *free_ptr = NULL;
+static char *end_ptr = NULL;
+static jmp_buf abort_parsing;
+
+static void *allocate(size_t size)
+{
+    void *result;
+    if (free_ptr + size > end_ptr) {
+        size_t how_much = BLOCK_SIZE;
+        // align everything to 8 bytes
+        if (size > BLOCK_SIZE - ALIGNMENT) {
+            how_much = size + ALIGNMENT;
+        }
+        result = malloc(how_much);
+        if (result == NULL) {
+            /* serious problem */
+            longjmp(abort_parsing, 1);
+        }
+        *((void **)result) = block_list;
+        block_list = result;
+        free_ptr = ((char *) result) + ALIGNMENT;
+        end_ptr = ((char *) result) + how_much;
+    }
+    // now, there is enough rooom at free_ptr
+    result = free_ptr;
+    free_ptr += size;
+    return result;
+}
+
+void bplist_free_data()
+{
+    while (block_list) {
+        void *next = *(void **)block_list;
+        free(block_list);
+        block_list = next;
+    }
+    free_ptr = NULL;
+    end_ptr = NULL;
+}
+
+// layout of trailer -- last 32 bytes in plist data
+    uint8_t unused[6];
+    uint8_t offset_int_size;
+    uint8_t object_ref_size;
+    uint64_t object_count;
+    uint64_t top_level_object;
+    uint64_t offset_table_offset;
+
+
+enum
+{
+    kHEADER_SIZE = 8,
+    kTRAILER_SIZE = 32, //sizeof(bplist_trailer_node),
+    kMINIMUM_SANE_SIZE = kHEADER_SIZE + kTRAILER_SIZE
+};
+
+
+static const char kHEADER_BYTES[kHEADER_SIZE] = "bplist00";
+
+// map from UID key to previously parsed value
+typedef struct cache_struct {
+    uint64_t key;
+    value_ptr value;
+    struct cache_struct *next;
+} cache_node, *cache_ptr;
+
+
+typedef struct bplist_info
+{
+    uint64_t object_count;
+    const uint8_t *data_bytes;
+    uint64_t length;
+    uint64_t offset_table_offset;
+    uint8_t offset_int_size;
+    uint8_t object_ref_size;
+    cache_ptr cache;
+} bplist_info_node, *bplist_info_ptr;
+
+
+static value_ptr bplist_read_pldata(pldata_ptr data);
+static value_ptr bplist_read_pref(char *filename, OSType folder_type);
+static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset, uint8_t size);
+static uint64_t read_offset(bplist_info_ptr bplist, uint64_t index);
+static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset, uint64_t *outValue, size_t *outSize);
+
+static value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef);
+static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_int(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset);
+
+
+value_ptr value_create()
+{
+    value_ptr value = (value_ptr) allocate(sizeof(value_node));
+    return value;
+}
+
+
+void value_set_integer(value_ptr v, int64_t i) {
+    v->tag = kTAG_INT; v->integer = i;
+}
+
+void value_set_real(value_ptr v, double d) {
+    v->tag = kTAG_REAL; v->real = d;
+}
+
+// d is seconds since 1 January 2001
+void value_set_date(value_ptr v, double d) {
+    v->tag = kTAG_DATE; v->real = d;
+}
+
+void value_set_ascii_string(value_ptr v, const uint8_t *s, size_t len) {
+    v->tag = kTAG_ASCIISTRING;
+    v->string = (char *) allocate(len + 1);
+    memcpy(v->string, s, len);
+    v->string[len] = 0;
+}
+
+void value_set_unicode_string(value_ptr v, const uint8_t *s, size_t len) {
+    v->tag = kTAG_UNICODESTRING;
+    v->string = (char *) allocate(len + 1);
+    memcpy(v->string, s, len);
+    v->string[len] = 0;
+}
+
+void value_set_uid(value_ptr v, uint64_t uid)
+{
+    v->tag = kTAG_UID; v->uinteger = uid;
+}
+
+// v->data points to a pldata that points to the actual bytes
+// the bytes are copied, so caller must free byte source (*data)
+void value_set_data(value_ptr v, const uint8_t *data, size_t len) {
+    v->tag = kTAG_DATA;
+    pldata_ptr pldata = (pldata_ptr) allocate(sizeof(pldata_node));
+    pldata->data = (uint8_t *) allocate(len);
+    memcpy(pldata->data, data, len);
+    pldata->len = len;
+    v->data = pldata;
+    printf("value at %p gets data at %p\n", v, pldata);
+}
+
+// caller releases ownership of array to value_ptr v
+void value_set_array(value_ptr v, value_ptr *array, size_t length) {
+    array_ptr a = (array_ptr) allocate(sizeof(array_node));
+    a->array = array;
+    a->length = length;
+    v->tag = kTAG_ARRAY;
+    v->array = a;
+}
+
+// caller releases ownership of dict to value_ptr v
+void value_set_dict(value_ptr v, dict_ptr dict) {
+    v->tag = kTAG_DICTIONARY;
+    v->dict = dict;
+}
+
+
+// look up an objectref in the cache, a ref->value_ptr mapping
+value_ptr cache_lookup(cache_ptr cache, uint64_t ref)
+{
+    while (cache) {
+        if (cache->key == ref) {
+            return cache->value;
+        }
+        cache = cache->next;
+    }
+    return NULL;
+}
+
+
+// insert an objectref and value in the cache
+void cache_insert(cache_ptr *cache, uint64_t ref, value_ptr value)
+{
+    cache_ptr c = (cache_ptr) allocate(sizeof(cache_node));
+    c->key = ref;
+    c->value = value;
+    c->next = *cache;
+    *cache = c;
+}
+
+
+// insert an objectref and value in a dictionary
+void dict_insert(dict_ptr *dict, value_ptr key, value_ptr value)
+{
+    dict_ptr d = (dict_ptr) allocate(sizeof(dict_node));
+    d->key = key;
+    d->value = value;
+    d->next = *dict;
+    *dict = d;
+}
+
+
+BOOL is_binary_plist(pldata_ptr data)
+{
+    if (data->len < kMINIMUM_SANE_SIZE)  return NO;
+    return memcmp(data->data, kHEADER_BYTES, kHEADER_SIZE) == 0;
+}
+
+
+value_ptr bplist_read_file(char *filename)
+{
+    struct stat stbuf;
+    pldata_node pldata;
+    FILE *file;
+    size_t n;
+    value_ptr value;
+    int rslt = stat(filename, &stbuf);
+    if (rslt) {
+        #if BPLIST_LOG
+            perror("in stat");
+        #endif
+        bplist_log("Could not stat %s, error %d\n", filename, rslt);
+        return NULL;
+    }
+    // if file is >100MB, assume it is not a preferences file and give up
+    if (stbuf.st_size > 100000000) {
+        bplist_log("Large file %s encountered (%llu bytes) -- not read\n",
+                   filename, stbuf.st_size);
+        return NULL;
+    }
+    pldata.len = (size_t) stbuf.st_size;
+    // note: this is supposed to be malloc, not allocate. It is separate
+    // from the graph structure, large, and easy to free right after
+    // parsing.
+    pldata.data = (uint8_t *) malloc(pldata.len);
+    if (!pldata.data) {
+        bplist_log("Could not allocate %lu bytes for %s\n",
+                   (unsigned long) pldata.len, filename);
+        return NULL;
+    }
+    file = fopen(filename, "rb");
+    if (!file) {
+        bplist_log("Could not open %s\n", filename);
+        return NULL;
+    }
+    n = fread(pldata.data, 1, pldata.len, file);
+    if (n != pldata.len) {
+        bplist_log("Error reading from %s\n", filename);
+        return NULL;
+    }
+    value = bplist_read_pldata(&pldata);
+    free(pldata.data);
+    return value;
+}
+
+
+value_ptr bplist_read_pref(char *filename, OSType folder_type)
+{
+    FSRef prefdir;
+    char cstr[MAXPATHLEN];
+
+    OSErr err = FSFindFolder(kOnAppropriateDisk, folder_type,
+                             FALSE, &prefdir);
+    if (err) {
+        bplist_log("Error finding preferences folder: %d\n", err);
+        return NULL;
+    }
+    err = FSRefMakePath(&prefdir, (UInt8 *) cstr, (UInt32) (MAXPATHLEN - 1));
+    if (err) {
+        bplist_log("Error making path name for preferences folder: %d\n", err);
+        return NULL;
+    }
+    strlcat(cstr, "/", MAXPATHLEN);
+    strlcat(cstr, filename, MAXPATHLEN);
+    return bplist_read_file(cstr);
+}
+
+
+value_ptr bplist_read_system_pref(char *filename) {
+    return bplist_read_pref(filename, kSystemPreferencesFolderType);
+}
+
+
+value_ptr bplist_read_user_pref(char *filename) {
+    return bplist_read_pref(filename, kPreferencesFolderType);
+}
+
+
+// data is stored with high-order bytes first.
+// read from plist data in a machine-independent fashion
+//
+uint64_t convert_uint64(uint8_t *ptr)
+{
+    uint64_t rslt = 0;
+    int i;
+    // shift in bytes, high-order first
+    for (i = 0; i < sizeof(uint64_t); i++) {
+        rslt <<= 8;
+        rslt += ptr[i];
+    }
+    return rslt;
+}
+
+
+value_ptr bplist_read_pldata(pldata_ptr data)
+{
+    value_ptr result = NULL;
+    bplist_info_node bplist;
+    uint8_t *ptr;
+    uint64_t top_level_object;
+    int i;
+
+    if (data == NULL)  return NULL;
+    if (!is_binary_plist(data)) {
+        bplist_log("Bad binary plist: too short or invalid header.\n");
+        return NULL;
+    }
+        
+    // read trailer
+    ptr = (uint8_t *) (data->data + data->len - kTRAILER_SIZE);
+    bplist.offset_int_size = ptr[6];
+    bplist.object_ref_size = ptr[7];
+    bplist.object_count = convert_uint64(ptr + 8);
+    top_level_object = convert_uint64(ptr + 16);
+    bplist.offset_table_offset = convert_uint64(ptr + 24);
+        
+    // Basic sanity checks
+    if (bplist.offset_int_size < 1 || bplist.offset_int_size > 8 ||
+        bplist.object_ref_size < 1 || bplist.object_ref_size > 8 ||
+        bplist.offset_table_offset < kHEADER_SIZE) {
+        bplist_log("Bad binary plist: trailer declared insane.\n");
+        return NULL;                
+    }
+        
+    // Ensure offset table is inside file
+    uint64_t offsetTableSize = bplist.offset_int_size * bplist.object_count;
+    if (offsetTableSize + bplist.offset_table_offset + kTRAILER_SIZE > 
+        data->len) {
+        bplist_log("Bad binary plist: offset table overlaps end of container.\n");
+        return NULL;
+    }
+        
+    bplist.data_bytes = data->data;
+    bplist.length = data->len;
+    bplist.cache = NULL; /* dictionary is empty */
+
+    bplist_log_verbose("Got a sane bplist with %llu items, offset_int_size: %u, object_ref_size: %u\n", 
+                      bplist.object_count, bplist.offset_int_size, 
+                      bplist.object_ref_size);
+    /* at this point, we are ready to do some parsing which allocates
+        memory for the result data structure. If memory allocation (using
+        allocate fails, a longjmp will return to here and we simply give up
+     */
+    i = setjmp(abort_parsing);
+    if (i == 0) {
+        result = extract_object(&bplist, top_level_object);
+    } else {
+        bplist_log("allocate() failed to allocate memory. Giving up.\n");
+        result = NULL;
+    }
+    if (!result) {
+        bplist_free_data();
+    }
+    return result;
+}
+
+
+static value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef)
+{
+    uint64_t offset;
+    value_ptr result = NULL;
+    uint8_t objectTag;
+    
+    if (objectRef >= bplist->object_count) {
+        // Out-of-range object reference.
+        bplist_log("Bad binary plist: object index is out of range.\n");
+        return NULL;
+    }
+        
+    // Use cached object if it exists
+    result = cache_lookup(bplist->cache, objectRef);
+    if (result != NULL)  return result;
+        
+    // Otherwise, find object in file.
+    offset = read_offset(bplist, objectRef);
+    if (offset > bplist->length) {
+        // Out-of-range offset.
+        bplist_log("Bad binary plist: object outside container.\n");
+        return NULL;
+    }
+    objectTag = *(bplist->data_bytes + offset);
+    switch (objectTag & 0xF0) {
+    case kTAG_SIMPLE:
+        result = extract_simple(bplist, offset);
+        break;
+                
+    case kTAG_INT:
+        result = extract_int(bplist, offset);
+        break;
+                        
+    case kTAG_REAL:
+        result = extract_real(bplist, offset);
+        break;
+                        
+    case kTAG_DATE:
+        result = extract_date(bplist, offset);
+        break;
+                        
+    case kTAG_DATA:
+        result = extract_data(bplist, offset);
+        break;
+                        
+    case kTAG_ASCIISTRING:
+        result = extract_ascii_string(bplist, offset);
+        break;
+                        
+    case kTAG_UNICODESTRING:
+        result = extract_unicode_string(bplist, offset);
+        break;
+        
+    case kTAG_UID:
+        result = extract_uid(bplist, offset);
+        break;
+        
+    case kTAG_ARRAY:
+        result = extract_array(bplist, offset);
+        break;
+        
+    case kTAG_DICTIONARY:
+        result = extract_dictionary(bplist, offset);
+        break;
+        
+    default:
+        // Unknown tag.
+        bplist_log("Bad binary plist: unknown tag 0x%X.\n", 
+                   (objectTag & 0x0F) >> 4);
+        result = NULL;
+    }
+    
+    // Cache and return result.
+    if (result != NULL)  
+        cache_insert(&bplist->cache, objectRef, result);
+    return result;
+}
+
+
+static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset, 
+                               uint8_t size)
+{
+    assert(bplist->data_bytes != NULL && size >= 1 && size <= 8 && 
+           offset + size <= bplist->length);
+        
+    uint64_t result = 0;
+    const uint8_t *byte = bplist->data_bytes + offset;
+        
+    do {
+        // note that ints seem to be high-order first
+        result = (result << 8) | *byte++;
+    } while (--size);
+        
+    return result;
+}
+
+
+static uint64_t read_offset(bplist_info_ptr bplist, uint64_t index)
+{
+    assert(index < bplist->object_count);
+        
+    return read_sized_int(bplist, 
+            bplist->offset_table_offset + bplist->offset_int_size * index, 
+            bplist->offset_int_size);
+}
+
+
+static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset, 
+                             uint64_t *outValue, size_t *outSize)
+{
+    uint32_t size;
+    int64_t value;
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+    size = 1 << (bplist->data_bytes[offset] & 0x0F);
+    if (size > 8) {
+        // Maximum allowable size in this implementation is 1<<3 = 8 bytes.
+        // This also happens to be the biggest we can handle.
+        return NO;
+    }
+        
+    if (offset + 1 + size > bplist->length) {
+        // Out of range.
+        return NO;
+    }
+        
+    value = read_sized_int(bplist, offset + 1, size);
+    
+    if (outValue != NULL) *outValue = value;
+    if (outSize != NULL) *outSize = size + 1; // +1 for tag byte.
+    return YES;
+}
+
+
+static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset)
+{
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+    value_ptr value = value_create();
+        
+    switch (bplist->data_bytes[offset]) {
+    case kVALUE_NULL:
+        value->tag = kVALUE_NULL;
+        return value;
+        
+    case kVALUE_TRUE:
+        value->tag = kVALUE_TRUE;
+        return value;
+                        
+    case kVALUE_FALSE:
+        value->tag = kVALUE_FALSE;
+        return value;
+    }
+        
+    // Note: kVALUE_FILLER is treated as invalid, because it, er, is.
+    bplist_log("Bad binary plist: invalid atom.\n");
+    free(value);
+    return NULL;
+}
+
+
+static value_ptr extract_int(bplist_info_ptr bplist, uint64_t offset)
+{
+    value_ptr value = value_create();
+    value->tag = kTAG_INT;
+
+    if (!read_self_sized_int(bplist, offset, &value->uinteger, NULL)) {
+        bplist_log("Bad binary plist: invalid integer object.\n");
+    }
+        
+    /* NOTE: originally, I sign-extended here. This was the wrong thing; it
+       turns out that negative ints are always stored as 64-bit, and smaller
+       ints are unsigned.
+    */
+    return value;
+}
+
+
+static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset)
+{
+    value_ptr value = value_create();
+    uint32_t size;
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+    
+    size = 1 << (bplist->data_bytes[offset] & 0x0F);
+        
+    // FIXME: what to do if faced with other sizes for float/double?
+    assert (sizeof (float) == sizeof (uint32_t) && 
+            sizeof (double) == sizeof (uint64_t));
+        
+    if (offset + 1 + size > bplist->length) {
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                  "floating-point number");
+        free(value);
+        return NULL;
+    }
+        
+    if (size == sizeof (float)) {
+        // cast is ok because we know size is 4 bytes
+        uint32_t i = (uint32_t) read_sized_int(bplist, offset + 1, size); 
+        // Note that this handles byte swapping.
+        value_set_real(value, *(float *)&i);
+        return value;
+    } else if (size == sizeof (double)) {
+        uint64_t i = read_sized_int(bplist, offset + 1, size);
+        // Note that this handles byte swapping.
+        value_set_real(value, *(double *)&i);
+        return value;
+    } else {
+        // Can't handle floats of other sizes.
+        bplist_log("Bad binary plist: can't handle %u-byte float.\n", size);
+        free(value);
+        return NULL;
+    }
+}
+
+
+static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset)
+{
+    value_ptr value;
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+    // Data has size code like int and real, but only 3 (meaning 8 bytes) is valid.
+    if (bplist->data_bytes[offset] != kVALUE_FULLDATETAG) {
+        bplist_log("Bad binary plist: invalid size for date object.\n");
+        return NULL;
+    }
+        
+    if (offset + 1 + sizeof (double) > bplist->length) {
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                  "date");
+        return NULL;
+    }
+        
+    // FIXME: what to do if faced with other sizes for double?
+    assert (sizeof (double) == sizeof (uint64_t));
+        
+    uint64_t date = read_sized_int(bplist, offset + 1, sizeof(double));
+    // Note that this handles byte swapping.
+    value = value_create();
+    value_set_date(value, *(double *)&date);
+    return value;
+}
+
+
+uint64_t bplist_get_a_size(bplist_info_ptr bplist, 
+                           uint64_t *offset_ptr, char *msg)
+{
+    uint64_t size = bplist->data_bytes[*offset_ptr] & 0x0F;
+    (*offset_ptr)++;
+    if (size == 0x0F) {
+        // 0x0F means separate int size follows. 
+        // Smaller values are used for short data.
+        size_t extra; // the length of the data size we are about to read
+        if ((bplist->data_bytes[*offset_ptr] & 0xF0) != kTAG_INT) {
+            // Bad data, mistagged size int
+            bplist_log("Bad binary plist: %s object size is not tagged as int.\n",
+                       msg);
+            return UINT64_MAX; // error
+        }
+                
+        // read integer data as size, extra tells how many bytes to skip
+        if (!read_self_sized_int(bplist, *offset_ptr, &size, &extra)) {
+            bplist_log("Bad binary plist: invalid %s object size tag.\n", 
+                      "data");
+            return UINT64_MAX; // error
+        }
+        (*offset_ptr) += extra;
+    }
+
+    if (*offset_ptr + size > bplist->length) {
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                  "data");
+        return UINT64_MAX; // error
+    }
+    return size;
+}
+
+
+static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset)
+{
+    uint64_t size;
+    value_ptr value;
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+    if ((size = bplist_get_a_size(bplist, &offset, "data")) == UINT64_MAX) 
+        return NULL;
+        
+    value = value_create();
+    // cast is ok because we only allow files up to 100MB:
+    value_set_data(value, bplist->data_bytes + (size_t) offset, (size_t) size);
+    return value;
+}
+
+
+static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset)
+{
+    uint64_t size;
+    value_ptr value; // return value
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+    if ((size = bplist_get_a_size(bplist, &offset, "ascii string")) ==
+        UINT64_MAX) 
+        return NULL;
+
+    value = value_create();
+    // cast is ok because we only allow 100MB files
+    value_set_ascii_string(value, bplist->data_bytes + (size_t) offset, 
+                           (size_t) size);
+    return value;
+}
+
+
+static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset)
+{
+    uint64_t size;
+    value_ptr value;
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+    if ((size = bplist_get_a_size(bplist, &offset, "unicode string")) == 
+        UINT64_MAX)
+        return NULL;
+        
+    value = value_create();
+    // cast is ok because we only allow 100MB files
+    value_set_unicode_string(value, bplist->data_bytes + (size_t) offset, 
+                             (size_t) size);
+    return value;
+}
+
+
+static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset)
+{
+    /* UIDs are used by Cocoa's key-value coder.
+       When writing other plist formats, they are expanded to dictionaries of
+       the form <dict><key>CF$UID</key><integer>value</integer></dict>, so we
+       do the same here on reading. This results in plists identical to what
+       running plutil -convert xml1 gives us. However, this is not the same
+       result as [Core]Foundation's plist parser, which extracts them as un-
+       introspectable CF objects. In fact, it even seems to convert the CF$UID
+       dictionaries from XML plists on the fly.
+    */
+        
+    value_ptr value;
+    uint64_t uid;
+        
+    if (!read_self_sized_int(bplist, offset, &uid, NULL)) {
+        bplist_log("Bad binary plist: invalid UID object.\n");
+        return NULL;
+    }
+        
+    // assert(NO); // original code suggests using a string for a key
+    // but our dictionaries all use big ints for keys, so I don't know
+    // what to do here
+    
+    // In practice, I believe this code is never executed by PortMidi.
+    // I changed it to do something and not raise compiler warnings, but
+    // not sure what the code should do.
+
+    value = value_create();
+    value_set_uid(value, uid);
+    // return [NSDictionary dictionaryWithObject:
+    //         [NSNumber numberWithUnsignedLongLong:value] 
+    //         forKey:"CF$UID"];
+    return value;
+}
+
+
+static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset)
+{
+    uint64_t i, count;
+    uint64_t size;
+    uint64_t elementID;
+    value_ptr element = NULL;
+    value_ptr *array = NULL;
+    value_ptr value = NULL;
+    BOOL ok = YES;
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+    if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX)
+        return NULL;
+        
+    if (count > UINT64_MAX / bplist->object_ref_size - offset) {
+        // Offset overflow.
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                   "array");
+        return NULL;
+    }
+        
+    size = bplist->object_ref_size * count;
+    if (size + offset > bplist->length) {
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                   "array");
+        return NULL;
+    }
+        
+    // got count, the number of array elements
+
+    value = value_create();
+    assert(value);
+
+    if (count == 0) {
+        // count must be size_t or smaller because max file size is 100MB
+        value_set_array(value, array, (size_t) count);
+        return value;
+    }
+        
+    array = allocate(sizeof(value_ptr) * (size_t) count);
+        
+    for (i = 0; i != count; ++i) {
+        bplist_log_verbose("[%u]\n", i);
+        elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size, 
+                                 bplist->object_ref_size);
+        element = extract_object(bplist, elementID);
+        if (element != NULL) {
+            array[i] = element;
+        } else {
+            ok = NO;
+            break;
+        }
+    }
+    if (ok) { // count is smaller than size_t max because of 100MB file limit
+        value_set_array(value, array, (size_t) count);
+    }
+
+    return value;
+}
+
+
+static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset)
+{
+    uint64_t i, count;
+    uint64_t size;
+    uint64_t elementID;
+    value_ptr value = NULL;
+    dict_ptr dict = NULL;
+    BOOL ok = YES;
+        
+    assert(bplist->data_bytes != NULL && offset < bplist->length);
+        
+        
+    if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX)
+        return NULL;
+
+    if (count > UINT64_MAX / (bplist->object_ref_size * 2) - offset) {
+        // Offset overflow.
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                   "dictionary");
+        return NULL;
+    }
+    
+    size = bplist->object_ref_size * count * 2;
+    if (size + offset > bplist->length) {
+        bplist_log("Bad binary plist: %s object overlaps end of container.\n", 
+                   "dictionary");
+        return NULL;
+    }
+    
+    value = value_create();
+    if (count == 0) {
+        value_set_dict(value, NULL);
+        return value;
+    }
+
+    for (i = 0; i != count; ++i) {
+        value_ptr key;
+        value_ptr val;
+        elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size, 
+                                 bplist->object_ref_size);
+        key = extract_object(bplist, elementID);
+        if (key != NULL) {
+            bplist_log_verbose("key: %p\n", key);
+        } else {
+            ok = NO;
+            break;
+        }
+                    
+        elementID = read_sized_int(bplist, 
+                            offset + (i + count) * bplist->object_ref_size, 
+                            bplist->object_ref_size);
+        val = extract_object(bplist, elementID);
+        if (val != NULL) {
+            dict_insert(&dict, key, val);
+        } else {
+            ok = NO;
+            break;
+        }
+    }
+    if (ok) {
+        value_set_dict(value, dict);
+    }
+    
+    return value;
+}
+
+/*************** functions for accessing values ****************/
+
+
+char *value_get_asciistring(value_ptr v)
+{
+    if (v->tag != kTAG_ASCIISTRING) return NULL;
+    return v->string;
+}
+
+
+value_ptr value_dict_lookup_using_string(value_ptr v, char *key)
+{
+    dict_ptr dict;
+    if (v->tag != kTAG_DICTIONARY) return NULL; // not a dictionary
+    dict = v->dict;
+    /* search for key */
+    while (dict) {
+        if (dict->key && dict->key->tag == kTAG_ASCIISTRING &&
+            strcmp(key, dict->key->string) == 0) { // found it
+            return dict->value;
+        }
+        dict = dict->next;
+    }
+    return NULL; /* not found */
+}
+
+value_ptr value_dict_lookup_using_path(value_ptr v, char *path)
+{
+    char key[MAX_KEY_SIZE];
+    while (*path) { /* more to the path */
+        int i = 0;
+        while (i < MAX_KEY_SIZE - 1) {
+            key[i] = *path++;
+            if (key[i] == '/') { /* end of entry in path */
+                key[i + 1] = 0;
+                break;
+            }
+            if (!key[i]) {
+                path--; /* back up to end of string char */
+                break;  /* this will cause outer loop to exit */
+            }
+            i++;
+        }
+        if (!v || v->tag != kTAG_DICTIONARY) return NULL;
+        /* now, look up the key to get next value */
+        v = value_dict_lookup_using_string(v, key);
+        if (v == NULL) return NULL;
+    }
+    return v;
+}
+                
+
+/*************** functions for debugging ***************/
+
+void plist_print(value_ptr v)
+{
+    size_t i;
+    int comma_needed;
+    dict_ptr dict;
+    if (!v) {
+        printf("NULL");
+        return;
+    }
+    switch (v->tag & 0xF0) {
+    case kTAG_SIMPLE:
+        switch (v->tag) {
+        case kVALUE_NULL: 
+            printf("NULL@%p", v); break;
+        case kVALUE_FALSE: 
+            printf("FALSE@%p", v); break;
+        case kVALUE_TRUE:
+            printf("TRUE@%p", v); break;
+        default:
+            printf("UNKNOWN tag=%x@%p", v->tag, v); break;
+        }
+        break;
+    case kTAG_INT:
+        printf("%lld@%p", v->integer, v); break;
+    case kTAG_REAL:
+        printf("%g@%p", v->real, v); break;
+    case kTAG_DATE:
+        printf("date:%g@%p", v->real, v); break;
+    case kTAG_DATA:
+        printf("data@%p->%p:[%p:", v, v->data, v->data->data);
+        for (i = 0; i < v->data->len; i++) {
+            printf(" %2x", v->data->data[i]);
+        }
+        printf("]"); break;
+    case kTAG_ASCIISTRING:
+        printf("%p:\"%s\"@%p", v->string, v->string, v); break;
+    case kTAG_UNICODESTRING:
+        printf("unicode:%p:\"%s\"@%p", v->string, v->string, v); break;
+    case kTAG_UID:
+        printf("UID:%llu@%p", v->uinteger, v); break;
+    case kTAG_ARRAY:
+        comma_needed = FALSE;
+        printf("%p->%p:[%p:", v, v->array, v->array->array);
+        for (i = 0; i < v->array->length; i++) {
+            if (comma_needed) printf(", ");
+            plist_print(v->array->array[i]);
+            comma_needed = TRUE;
+        }
+        printf("]"); break;
+    case kTAG_DICTIONARY:
+        comma_needed = FALSE;
+        printf("%p:[", v);
+        dict = v->dict;
+        while (dict) {
+            if (comma_needed) printf(", ");
+            printf("%p:", dict);
+            plist_print(dict->key);
+            printf("->");
+            plist_print(dict->value);
+            comma_needed = TRUE;
+            dict = dict->next;
+        }
+        printf("]"); break;
+    default:
+        printf("UNKNOWN tag=%x", v->tag);
+        break;
+    }
+}
+
+            
index 5b4dec63fce9b3963d3806ac69a8ba4cab5275ae..aeed48554dba4ee6b16d043e7386b2f07d8b3e4a 100644 (file)
-/* 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
+/* pmwin.c -- PortMidi os-dependent code */
+
+/* This file only needs to implement:
+       pm_init(), which calls various routines to register the 
+           available midi devices,
+       Pm_GetDefaultInputDeviceID(), and
+       Pm_GetDefaultOutputDeviceID().
+   This file must
+   be separate from the main portmidi.c file because it is system
+   dependent, and it is separate from, say, pmwinmm.c, because it
+   might need to register devices for winmm, directx, and others.
+
+ */
+
+#include "stdlib.h"
+#include "portmidi.h"
+#include "pmutil.h"
+#include "pminternal.h"
+#include "pmwinmm.h"
+#ifdef DEBUG
+#include "stdio.h"
+#endif
+#include <windows.h>
+
+/* pm_exit is called when the program exits.
+   It calls pm_term to make sure PortMidi is properly closed.
+   If DEBUG is on, we prompt for input to avoid losing error messages.
+ */
+static void pm_exit(void) {
+    pm_term();
+#ifdef DEBUG
+#define STRING_MAX 80
+    {
+        char line[STRING_MAX];
+        printf("Type ENTER...\n");
+        /* note, w/o this prompting, client console application can not see one
+           of its errors before closing. */
+        fgets(line, STRING_MAX, stdin);
+    }
+#endif
+}
+
+
+/* pm_init is the windows-dependent initialization.*/
+void pm_init(void)
+{
+    atexit(pm_exit);
+#ifdef DEBUG
+    printf("registered pm_exit with atexit()\n");
+#endif
+    pm_winmm_init();
+    /* initialize other APIs (DirectX?) here */
+}
+
+
+void pm_term(void) {
+    pm_winmm_term();
+}
+
+
+static PmDeviceID pm_get_default_device_id(int is_input, char *key) {
+    HKEY hkey;
+#define PATTERN_MAX 256
+    char pattern[PATTERN_MAX];
+    long pattern_max = PATTERN_MAX;
+    DWORD dwType;
+    /* Find first input or device -- this is the default. */
+    PmDeviceID id = pmNoDevice;
+    int i, j;
+    Pm_Initialize(); /* make sure descriptors exist! */
+    for (i = 0; i < pm_descriptor_index; i++) {
+        if (descriptors[i].pub.input == is_input) {
+            id = i;
+            break;
+        }
+    }
+    /* Look in registry for a default device name pattern. */
+    if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &hkey) != 
+        ERROR_SUCCESS) {
+        return id;
+    }
+    if (RegOpenKeyEx(hkey, "JavaSoft", 0, KEY_READ, &hkey) !=
+        ERROR_SUCCESS) {
+        return id;
+    }
+    if (RegOpenKeyEx(hkey, "Prefs", 0, KEY_READ, &hkey) !=
+        ERROR_SUCCESS) {
+        return id;
+    }
+    if (RegOpenKeyEx(hkey, "/Port/Midi", 0, KEY_READ, &hkey) !=
+        ERROR_SUCCESS) {
+        return id;
+    }
+    if (RegQueryValueEx(hkey, key, NULL, &dwType, pattern, &pattern_max) != 
+       ERROR_SUCCESS) {
+        return id;
+    }
+
+    /* decode pattern: upper case encoded with "/" prefix */
+    i = j = 0;
+    while (pattern[i]) {
+        if (pattern[i] == '/' && pattern[i + 1]) {
+            pattern[j++] = toupper(pattern[++i]);
+       } else {
+            pattern[j++] = tolower(pattern[i]);
+       }
+        i++;
+    }
+    pattern[j] = 0; /* end of string */
+
+    /* now pattern is the string from the registry; search for match */
+    i = pm_find_default_device(pattern, is_input);
+    if (i != pmNoDevice) {
+        id = i;
+    }
+    return id;
+}
+
+
+PmDeviceID Pm_GetDefaultInputDeviceID() {
+    return pm_get_default_device_id(TRUE, 
+           "/P/M_/R/E/C/O/M/M/E/N/D/E/D_/I/N/P/U/T_/D/E/V/I/C/E");
+}
+
+
+PmDeviceID Pm_GetDefaultOutputDeviceID() {
+  return pm_get_default_device_id(FALSE,
+          "/P/M_/R/E/C/O/M/M/E/N/D/E/D_/O/U/T/P/U/T_/D/E/V/I/C/E");
+}
+
+
+#include "stdio.h" 
+
+void *pm_alloc(size_t s) {
+    return malloc(s); 
+}
+
+
+void pm_free(void *ptr) { 
+    free(ptr); 
+}
+
+
index ab66f80dc1c6b059c015c1aacf1b67058cb6b93c..2de8109a0a142f1a1efd1413618dc7a2848edb76 100644 (file)
-/* 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
+/* pmwinmm.c -- system specific definitions */
+
+#ifdef _MSC_VER
+ #pragma warning(disable: 4133) // stop warnings about implicit typecasts
+#endif
+
+#ifndef _WIN32_WINNT
+    /* without this define, InitializeCriticalSectionAndSpinCount is 
+     * undefined. This version level means "Windows 2000 and higher" 
+     */
+    #define _WIN32_WINNT 0x0500
+#endif
+
+#include "windows.h"
+#include "mmsystem.h"
+#include "portmidi.h"
+#include "pmutil.h"
+#include "pminternal.h"
+#include "pmwinmm.h"
+#include <string.h>
+#include "porttime.h"
+
+/* asserts used to verify portMidi code logic is sound; later may want
+    something more graceful */
+#include <assert.h>
+#ifdef DEBUG
+/* this printf stuff really important for debugging client app w/host errors.
+    probably want to do something else besides read/write from/to console
+    for portability, however */
+#define STRING_MAX 80
+#include "stdio.h"
+#endif
+
+#define streql(x, y) (strcmp(x, y) == 0)
+
+#define MIDI_SYSEX      0xf0
+#define MIDI_EOX        0xf7
+
+/* callback routines */
+static void CALLBACK winmm_in_callback(HMIDIIN hMidiIn,
+                                       WORD wMsg, DWORD dwInstance, 
+                                       DWORD dwParam1, DWORD dwParam2);
+static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg,
+                                              DWORD dwInstance, DWORD dwParam1, 
+                                              DWORD dwParam2);
+#ifdef USE_SYSEX_BUFFERS
+static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg,
+                                        DWORD dwInstance, DWORD dwParam1, 
+                                        DWORD dwParam2);
+#endif
+
+extern pm_fns_node pm_winmm_in_dictionary;
+extern pm_fns_node pm_winmm_out_dictionary;
+
+static void winmm_out_delete(PmInternal *midi); /* forward reference */
+
+/*
+A note about buffers: WinMM seems to hold onto buffers longer than
+one would expect, e.g. when I tried using 2 small buffers to send
+long sysex messages, at some point WinMM held both buffers. This problem
+was fixed by making buffers bigger. Therefore, it seems that there should 
+be enough buffer space to hold a whole sysex message. 
+
+The bufferSize passed into Pm_OpenInput (passed into here as buffer_len)
+will be used to estimate the largest sysex message (= buffer_len * 4 bytes).
+Call that the max_sysex_len = buffer_len * 4.
+
+For simple midi output (latency == 0), allocate 3 buffers, each with half
+the size of max_sysex_len, but each at least 256 bytes.
+
+For stream output, there will already be enough space in very short
+buffers, so use them, but make sure there are at least 16.
+
+For input, use many small buffers rather than 2 large ones so that when 
+there are short sysex messages arriving frequently (as in control surfaces)
+there will be more free buffers to fill. Use max_sysex_len / 64 buffers,
+but at least 16, of size 64 bytes each.
+
+The following constants help to represent these design parameters:
+*/
+#define NUM_SIMPLE_SYSEX_BUFFERS 3
+#define MIN_SIMPLE_SYSEX_LEN 256
+
+#define MIN_STREAM_BUFFERS 16
+#define STREAM_BUFFER_LEN 24
+
+#define INPUT_SYSEX_LEN 64
+#define MIN_INPUT_BUFFERS 16
+
+/* if we run out of space for output (assume this is due to a sysex msg,
+   expand by up to NUM_EXPANSION_BUFFERS in increments of EXPANSION_BUFFER_LEN
+ */
+#define NUM_EXPANSION_BUFFERS 128
+#define EXPANSION_BUFFER_LEN 1024
+
+/* A sysex buffer has 3 DWORDS as a header plus the actual message size */
+#define MIDIHDR_SYSEX_BUFFER_LENGTH(x) ((x) + sizeof(long)*3)
+/* A MIDIHDR with a sysex message is the buffer length plus the header size */
+#define MIDIHDR_SYSEX_SIZE(x) (MIDIHDR_SYSEX_BUFFER_LENGTH(x) + sizeof(MIDIHDR))
+#ifdef USE_SYSEX_BUFFERS
+/* Size of a MIDIHDR with a buffer contaning multiple MIDIEVENT structures */
+#define MIDIHDR_SIZE(x) ((x) + sizeof(MIDIHDR))
+#endif
+
+/*
+==============================================================================
+win32 mmedia system specific structure passed to midi callbacks
+==============================================================================
+*/
+
+/* global winmm device info */
+MIDIINCAPS *midi_in_caps = NULL;
+MIDIINCAPS midi_in_mapper_caps;
+UINT midi_num_inputs = 0;
+MIDIOUTCAPS *midi_out_caps = NULL;
+MIDIOUTCAPS midi_out_mapper_caps;
+UINT midi_num_outputs = 0;
+
+/* per device info */
+typedef struct midiwinmm_struct {
+    union {
+        HMIDISTRM stream;   /* windows handle for stream */
+        HMIDIOUT out;       /* windows handle for out calls */
+        HMIDIIN in;         /* windows handle for in calls */
+    } handle;
+
+    /* midi output messages are sent in these buffers, which are allocated
+     * in a round-robin fashion, using next_buffer as an index
+     */
+    LPMIDIHDR *buffers;     /* pool of buffers for midi in or out data */
+    int max_buffers;        /* length of buffers array */
+    int buffers_expanded;   /* buffers array expanded for extra msgs? */
+    int num_buffers;        /* how many buffers allocated in buffers array */
+    int next_buffer;        /* index of next buffer to send */
+    HANDLE buffer_signal;   /* used to wait for buffer to become free */
+#ifdef USE_SYSEX_BUFFERS
+    /* sysex buffers will be allocated only when
+     * a sysex message is sent. The size of the buffer is fixed.
+     */
+    LPMIDIHDR sysex_buffers[NUM_SYSEX_BUFFERS]; /* pool of buffers for sysex data */
+    int next_sysex_buffer;      /* index of next sysexbuffer to send */
+#endif
+    unsigned long last_time;    /* last output time */
+    int first_message;          /* flag: treat first message differently */
+    int sysex_mode;             /* middle of sending sysex */
+    unsigned long sysex_word;   /* accumulate data when receiving sysex */
+    unsigned int sysex_byte_count; /* count how many received */
+    LPMIDIHDR hdr;              /* the message accumulating sysex to send */
+    unsigned long sync_time;    /* when did we last determine delta? */
+    long delta;                 /* difference between stream time and
+                                       real time */
+    int error;                  /* host error from doing port midi call */
+    CRITICAL_SECTION lock;      /* prevents reentrant callbacks (input only) */
+} midiwinmm_node, *midiwinmm_type;
+
+
+/*
+=============================================================================
+general MIDI device queries
+=============================================================================
+*/
+static void pm_winmm_general_inputs()
+{
+    UINT i;
+    WORD wRtn;
+    midi_num_inputs = midiInGetNumDevs();
+    midi_in_caps = (MIDIINCAPS *) pm_alloc(sizeof(MIDIINCAPS) * 
+                                           midi_num_inputs);
+    if (midi_in_caps == NULL) {
+        /* if you can't open a particular system-level midi interface
+         * (such as winmm), we just consider that system or API to be
+         * unavailable and move on without reporting an error.
+         */
+        return;
+    }
+
+    for (i = 0; i < midi_num_inputs; i++) {
+        wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) & midi_in_caps[i],
+                                sizeof(MIDIINCAPS));
+        if (wRtn == MMSYSERR_NOERROR) {
+            /* ignore errors here -- if pm_descriptor_max is exceeded, some
+               devices will not be accessible. */
+            pm_add_device("MMSystem", midi_in_caps[i].szPname, TRUE,
+                          (void *) i, &pm_winmm_in_dictionary);
+        }
+    }
+}
+
+
+static void pm_winmm_mapper_input()
+{
+    WORD wRtn;
+    /* Note: if MIDIMAPPER opened as input (documentation implies you
+        can, but current system fails to retrieve input mapper
+        capabilities) then you still should retrieve some formof
+        setup info. */
+    wRtn = midiInGetDevCaps((UINT) MIDIMAPPER,
+                            (LPMIDIINCAPS) & midi_in_mapper_caps, 
+                            sizeof(MIDIINCAPS));
+    if (wRtn == MMSYSERR_NOERROR) {
+        pm_add_device("MMSystem", midi_in_mapper_caps.szPname, TRUE,
+                      (void *) MIDIMAPPER, &pm_winmm_in_dictionary);
+    }
+}
+
+
+static void pm_winmm_general_outputs()
+{
+    UINT i;
+    DWORD wRtn;
+    midi_num_outputs = midiOutGetNumDevs();
+    midi_out_caps = pm_alloc( sizeof(MIDIOUTCAPS) * midi_num_outputs );
+
+    if (midi_out_caps == NULL) {
+        /* no error is reported -- see pm_winmm_general_inputs */
+        return ;
+    }
+
+    for (i = 0; i < midi_num_outputs; i++) {
+        wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) & midi_out_caps[i],
+                                 sizeof(MIDIOUTCAPS));
+        if (wRtn == MMSYSERR_NOERROR) {
+            pm_add_device("MMSystem", midi_out_caps[i].szPname, FALSE,
+                          (void *) i, &pm_winmm_out_dictionary);
+        }
+    }
+}
+
+
+static void pm_winmm_mapper_output()
+{
+    WORD wRtn;
+    /* Note: if MIDIMAPPER opened as output (pseudo MIDI device
+        maps device independent messages into device dependant ones,
+        via NT midimapper program) you still should get some setup info */
+    wRtn = midiOutGetDevCaps((UINT) MIDIMAPPER, (LPMIDIOUTCAPS)
+                             & midi_out_mapper_caps, sizeof(MIDIOUTCAPS));
+    if (wRtn == MMSYSERR_NOERROR) {
+        pm_add_device("MMSystem", midi_out_mapper_caps.szPname, FALSE,
+                      (void *) MIDIMAPPER, &pm_winmm_out_dictionary);
+    }
+}
+
+
+/*
+=========================================================================================
+host error handling
+=========================================================================================
+*/
+static unsigned int winmm_has_host_error(PmInternal * midi)
+{
+    midiwinmm_type m = (midiwinmm_type)midi->descriptor;
+    return m->error;
+}
+
+
+/* str_copy_len -- like strcat, but won't overrun the destination string */
+/*
+ * returns length of resulting string
+ */
+static int str_copy_len(char *dst, char *src, int len)
+{
+    strncpy(dst, src, len);
+    /* just in case suffex is greater then len, terminate with zero */
+    dst[len - 1] = 0;
+    return strlen(dst);
+}
+
+
+static void winmm_get_host_error(PmInternal * midi, char * msg, UINT len)
+{
+    /* precondition: midi != NULL */
+    midiwinmm_node * m = (midiwinmm_node *) midi->descriptor;
+    char *hdr1 = "Host error: ";
+    char *hdr2 = "Host callback error: ";
+
+    msg[0] = 0; /* initialize result string to empty */
+
+    if (descriptors[midi->device_id].pub.input) {
+        /* input and output use different winmm API calls */
+        if (m) { /* make sure there is an open device to examine */
+            if (m->error != MMSYSERR_NOERROR) {
+                int n = str_copy_len(msg, hdr1, len);
+                /* read and record host error */
+                int err = midiInGetErrorText(m->error, msg + n, len - n);
+                assert(err == MMSYSERR_NOERROR);
+                m->error = MMSYSERR_NOERROR;
+            }
+        }
+    } else { /* output port */
+        if (m) {
+            if (m->error != MMSYSERR_NOERROR) {
+                int n = str_copy_len(msg, hdr1, len);
+                int err = midiOutGetErrorText(m->error, msg + n, len - n);
+                assert(err == MMSYSERR_NOERROR);
+                m->error = MMSYSERR_NOERROR;
+            }
+        }
+    }
+}
+
+
+/*
+=============================================================================
+buffer handling
+=============================================================================
+*/
+static MIDIHDR *allocate_buffer(long data_size)
+{
+    LPMIDIHDR hdr = (LPMIDIHDR) pm_alloc(MIDIHDR_SYSEX_SIZE(data_size));
+    MIDIEVENT *evt;
+    if (!hdr) return NULL;
+    evt = (MIDIEVENT *) (hdr + 1); /* place MIDIEVENT after header */
+    hdr->lpData = (LPSTR) evt;
+    hdr->dwBufferLength = MIDIHDR_SYSEX_BUFFER_LENGTH(data_size);
+    hdr->dwBytesRecorded = 0;
+    hdr->dwFlags = 0;
+    hdr->dwUser = hdr->dwBufferLength;
+    return hdr;
+}
+
+#ifdef USE_SYSEX_BUFFERS
+static MIDIHDR *allocate_sysex_buffer(long data_size)
+{
+    /* we're actually allocating more than data_size because the buffer 
+     * will include the MIDIEVENT header in addition to the data 
+     */
+    LPMIDIHDR hdr = (LPMIDIHDR) pm_alloc(MIDIHDR_SYSEX_SIZE(data_size));
+    MIDIEVENT *evt;
+    if (!hdr) return NULL;
+    evt = (MIDIEVENT *) (hdr + 1); /* place MIDIEVENT after header */
+    hdr->lpData = (LPSTR) evt;
+    hdr->dwFlags = 0;
+    hdr->dwUser = 0;
+    return hdr;
+}
+#endif
+
+static PmError allocate_buffers(midiwinmm_type m, long data_size, long count)
+{
+    int i;
+    /* buffers is an array of count pointers to MIDIHDR/MIDIEVENT struct */
+    m->num_buffers = 0; /* in case no memory can be allocated */
+    m->buffers = (LPMIDIHDR *) pm_alloc(sizeof(LPMIDIHDR) * count);
+    if (!m->buffers) return pmInsufficientMemory;
+    m->max_buffers = count;
+    for (i = 0; i < count; i++) {
+        LPMIDIHDR hdr = allocate_buffer(data_size);
+        if (!hdr) { /* free everything allocated so far and return */
+            for (i = i - 1; i >= 0; i--) pm_free(m->buffers[i]);
+            pm_free(m->buffers);
+            m->max_buffers = 0;
+            return pmInsufficientMemory;
+        }
+        m->buffers[i] = hdr; /* this may be NULL if allocation fails */
+    }
+    m->num_buffers = count;
+    return pmNoError;
+}
+
+#ifdef USE_SYSEX_BUFFERS
+static PmError allocate_sysex_buffers(midiwinmm_type m, long data_size)
+{
+    PmError rslt = pmNoError;
+    /* sysex_buffers is an array of count pointers to MIDIHDR/MIDIEVENT struct */
+    int i;
+    for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {
+        LPMIDIHDR hdr = allocate_sysex_buffer(data_size);
+
+        if (!hdr) rslt = pmInsufficientMemory;
+        m->sysex_buffers[i] = hdr; /* this may be NULL if allocation fails */
+        hdr->dwFlags = 0; /* mark as free */
+    }
+    return rslt;
+}
+#endif
+
+#ifdef USE_SYSEX_BUFFERS
+static LPMIDIHDR get_free_sysex_buffer(PmInternal *midi)
+{
+    LPMIDIHDR r = NULL;
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    if (!m->sysex_buffers[0]) {
+        if (allocate_sysex_buffers(m, SYSEX_BYTES_PER_BUFFER)) {
+            return NULL;
+        }
+    }
+    /* busy wait until we find a free buffer */
+    while (TRUE) {
+        int i;
+        for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {
+            /* cycle through buffers, modulo NUM_SYSEX_BUFFERS */
+            m->next_sysex_buffer++;
+            if (m->next_sysex_buffer >= NUM_SYSEX_BUFFERS) m->next_sysex_buffer = 0;
+            r = m->sysex_buffers[m->next_sysex_buffer];
+            if ((r->dwFlags & MHDR_PREPARED) == 0) goto found_sysex_buffer;
+        }
+        /* after scanning every buffer and not finding anything, block */
+        if (WaitForSingleObject(m->buffer_signal, 1000) == WAIT_TIMEOUT) {
+#ifdef DEBUG
+            printf("PortMidi warning: get_free_sysex_buffer() wait timed out after 1000ms\n");
+#endif
+        }
+    }
+found_sysex_buffer:
+    r->dwBytesRecorded = 0;
+    r->dwBufferLength = 0; /* changed to correct value later */
+    return r;
+}
+#endif
+
+static LPMIDIHDR get_free_output_buffer(PmInternal *midi)
+{
+    LPMIDIHDR r = NULL;
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    while (TRUE) {
+        int i;
+        for (i = 0; i < m->num_buffers; i++) {
+            /* cycle through buffers, modulo m->num_buffers */
+            m->next_buffer++;
+            if (m->next_buffer >= m->num_buffers) m->next_buffer = 0;
+            r = m->buffers[m->next_buffer];
+            if ((r->dwFlags & MHDR_PREPARED) == 0) goto found_buffer;
+        }
+        /* after scanning every buffer and not finding anything, block */
+        if (WaitForSingleObject(m->buffer_signal, 1000) == WAIT_TIMEOUT) {
+#ifdef DEBUG
+            printf("PortMidi warning: get_free_output_buffer() wait timed out after 1000ms\n");
+#endif
+            /* if we're trying to send a sysex message, maybe the 
+             * message is too big and we need more message buffers.
+             * Expand the buffer pool by 128KB using 1024-byte buffers.
+             */
+            /* first, expand the buffers array if necessary */
+            if (!m->buffers_expanded) {
+                LPMIDIHDR *new_buffers = (LPMIDIHDR *) pm_alloc(
+                        (m->num_buffers + NUM_EXPANSION_BUFFERS) * 
+                        sizeof(LPMIDIHDR));
+                /* if no memory, we could return a no-memory error, but user
+                 * probably will be unprepared to deal with it. Maybe the
+                 * MIDI driver is temporarily hung so we should just wait.
+                 * I don't know the right answer, but waiting is easier.
+                 */
+                if (!new_buffers) continue;
+                /* copy buffers to new_buffers and replace buffers */
+                memcpy(new_buffers, m->buffers, 
+                       m->num_buffers * sizeof(LPMIDIHDR));
+                pm_free(m->buffers);
+                m->buffers = new_buffers;
+                m->max_buffers = m->num_buffers + NUM_EXPANSION_BUFFERS;
+                m->buffers_expanded = TRUE;
+            }
+            /* next, add one buffer and return it */
+            if (m->num_buffers < m->max_buffers) {
+                r = allocate_buffer(EXPANSION_BUFFER_LEN);
+                /* again, if there's no memory, we may not really be 
+                 * dead -- maybe the system is temporarily hung and
+                 * we can just wait longer for a message buffer */
+                if (!r) continue;
+                m->buffers[m->num_buffers++] = r;
+                goto found_buffer; /* break out of 2 loops */
+            }
+            /* else, we've allocated all NUM_EXPANSION_BUFFERS buffers,
+             * and we have no free buffers to send. We'll just keep
+             * polling to see if any buffers show up.
+             */
+        }
+    }
+found_buffer:
+    r->dwBytesRecorded = 0;
+    /* actual buffer length is saved in dwUser field */
+    r->dwBufferLength = (DWORD) r->dwUser;
+    return r;
+}
+
+#ifdef EXPANDING_SYSEX_BUFFERS
+note: this is not working code, but might be useful if you want
+      to grow sysex buffers.
+static PmError resize_sysex_buffer(PmInternal *midi, long old_size, long new_size)
+{
+    LPMIDIHDR big;
+    int i;
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    /* buffer must be smaller than 64k, but be also a multiple of 4 */
+    if (new_size > 65520) {
+        if (old_size >= 65520)
+            return pmBufferMaxSize;
+        else
+            new_size = 65520;
+    }
+    /* allocate a bigger message  */
+    big = allocate_sysex_buffer(new_size);
+    /* printf("expand to %d bytes\n", new_size);*/
+    if (!big) return pmInsufficientMemory;
+    m->error = midiOutPrepareHeader(m->handle.out, big, sizeof(MIDIHDR));
+    if (m->error) {
+        pm_free(big);
+        return pmHostError;
+    }
+    /* make sure we're not going to overwrite any memory */
+    assert(old_size <= new_size);
+    memcpy(big->lpData, m->hdr->lpData, old_size);
+    /* keep track of how many sysex bytes are in message so far */
+    big->dwBytesRecorded = m->hdr->dwBytesRecorded;
+    big->dwBufferLength = new_size;
+    /* find which buffer this was, and replace it */
+    for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {
+        if (m->sysex_buffers[i] == m->hdr) {
+            m->sysex_buffers[i] = big;
+            m->sysex_buffer_size[i] = new_size;
+            pm_free(m->hdr);
+            m->hdr = big;
+            break;
+        }
+    }
+    assert(i != NUM_SYSEX_BUFFERS);
+
+    return pmNoError;
+}
+#endif
+
+/*
+=========================================================================================
+begin midi input implementation
+=========================================================================================
+*/
+
+
+static PmError allocate_input_buffer(HMIDIIN h, long buffer_len)
+{
+    LPMIDIHDR hdr = allocate_buffer(buffer_len);
+    if (!hdr) return pmInsufficientMemory;
+    pm_hosterror = midiInPrepareHeader(h, hdr, sizeof(MIDIHDR));
+    if (pm_hosterror) {
+        pm_free(hdr);
+        return pm_hosterror;
+    }
+    pm_hosterror = midiInAddBuffer(h, hdr, sizeof(MIDIHDR));
+    return pm_hosterror;
+}
+
+
+static PmError winmm_in_open(PmInternal *midi, void *driverInfo)
+{
+    DWORD dwDevice;
+    int i = midi->device_id;
+    int max_sysex_len = midi->buffer_len * 4;
+    int num_input_buffers = max_sysex_len / INPUT_SYSEX_LEN;
+    midiwinmm_type m;
+
+    dwDevice = (DWORD) descriptors[i].descriptor;
+
+    /* create system dependent device data */
+    m = (midiwinmm_type) pm_alloc(sizeof(midiwinmm_node)); /* create */
+    midi->descriptor = m;
+    if (!m) goto no_memory;
+    m->handle.in = NULL;
+    m->buffers = NULL; /* not used for input */
+    m->num_buffers = 0; /* not used for input */
+    m->max_buffers = FALSE; /* not used for input */
+    m->buffers_expanded = 0; /* not used for input */
+    m->next_buffer = 0; /* not used for input */
+    m->buffer_signal = 0; /* not used for input */
+#ifdef USE_SYSEX_BUFFERS
+    for (i = 0; i < NUM_SYSEX_BUFFERS; i++) 
+        m->sysex_buffers[i] = NULL; /* not used for input */
+    m->next_sysex_buffer = 0; /* not used for input */
+#endif
+    m->last_time = 0;
+    m->first_message = TRUE; /* not used for input */
+    m->sysex_mode = FALSE;
+    m->sysex_word = 0;
+    m->sysex_byte_count = 0;
+    m->hdr = NULL; /* not used for input */
+    m->sync_time = 0;
+    m->delta = 0;
+    m->error = MMSYSERR_NOERROR;
+    /* 4000 is based on Windows documentation -- that's the value used in the
+       memory manager. It's small enough that it should not hurt performance even
+       if it's not optimal.
+     */
+    InitializeCriticalSectionAndSpinCount(&m->lock, 4000);
+    /* open device */
+    pm_hosterror = midiInOpen(
+           &(m->handle.in),  /* input device handle */
+           dwDevice,  /* device ID */
+           (DWORD_PTR) winmm_in_callback,  /* callback address */
+           (DWORD_PTR) midi,  /* callback instance data */
+           CALLBACK_FUNCTION); /* callback is a procedure */
+    if (pm_hosterror) goto free_descriptor;
+
+    if (num_input_buffers < MIN_INPUT_BUFFERS)
+        num_input_buffers = MIN_INPUT_BUFFERS;
+    for (i = 0; i < num_input_buffers; i++) {
+        if (allocate_input_buffer(m->handle.in, INPUT_SYSEX_LEN)) {
+            /* either pm_hosterror was set, or the proper return code
+               is pmInsufficientMemory */
+            goto close_device;
+        }
+    }
+    /* start device */
+    pm_hosterror = midiInStart(m->handle.in);
+    if (pm_hosterror) goto reset_device;
+    return pmNoError;
+
+    /* undo steps leading up to the detected error */
+reset_device:
+    /* ignore return code (we already have an error to report) */
+    midiInReset(m->handle.in);
+close_device:
+    midiInClose(m->handle.in); /* ignore return code */
+free_descriptor:
+    midi->descriptor = NULL;
+    pm_free(m);
+no_memory:
+    if (pm_hosterror) {
+        int err = midiInGetErrorText(pm_hosterror, (char *) pm_hosterror_text,
+                                     PM_HOST_ERROR_MSG_LEN);
+        assert(err == MMSYSERR_NOERROR);
+        return pmHostError;
+    }
+    /* if !pm_hosterror, then the error must be pmInsufficientMemory */
+    return pmInsufficientMemory;
+    /* note: if we return an error code, the device will be
+       closed and memory will be freed. It's up to the caller
+       to free the parameter midi */
+}
+
+static PmError winmm_in_poll(PmInternal *midi) {
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    return m->error;
+}
+
+
+
+/* winmm_in_close -- close an open midi input device */
+/*
+ * assume midi is non-null (checked by caller)
+ */
+static PmError winmm_in_close(PmInternal *midi)
+{
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    if (!m) return pmBadPtr;
+    /* device to close */
+    if (pm_hosterror = midiInStop(m->handle.in)) {
+        midiInReset(m->handle.in); /* try to reset and close port */
+        midiInClose(m->handle.in);
+    } else if (pm_hosterror = midiInReset(m->handle.in)) {
+        midiInClose(m->handle.in); /* best effort to close midi port */
+    } else {
+        pm_hosterror = midiInClose(m->handle.in);
+    }
+    midi->descriptor = NULL;
+    DeleteCriticalSection(&m->lock);
+    pm_free(m); /* delete */
+    if (pm_hosterror) {
+        int err = midiInGetErrorText(pm_hosterror, (char *) pm_hosterror_text,
+                                     PM_HOST_ERROR_MSG_LEN);
+        assert(err == MMSYSERR_NOERROR);
+        return pmHostError;
+    }
+    return pmNoError;
+}
+
+
+/* Callback function executed via midiInput SW interrupt (via midiInOpen). */
+static void FAR PASCAL winmm_in_callback(
+    HMIDIIN hMidiIn,    /* midiInput device Handle */
+    WORD wMsg,          /* midi msg */
+    DWORD dwInstance,   /* application data */
+    DWORD dwParam1,     /* MIDI data */
+    DWORD dwParam2)    /* device timestamp (wrt most recent midiInStart) */
+{
+    static int entry = 0;
+    PmInternal *midi = (PmInternal *) dwInstance;
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+
+    /* NOTE: we do not just EnterCriticalSection() here because an
+     * MIM_CLOSE message arrives when the port is closed, but then
+     * the m->lock has been destroyed.
+     */
+
+    switch (wMsg) {
+    case MIM_DATA: {
+        /* if this callback is reentered with data, we're in trouble. 
+         * It's hard to imagine that Microsoft would allow callbacks 
+         * to be reentrant -- isn't the model that this is like a 
+         * hardware interrupt? -- but I've seen reentrant behavior 
+         * using a debugger, so it happens.
+         */
+        long new_driver_time;
+        EnterCriticalSection(&m->lock);
+
+        /* dwParam1 is MIDI data received, packed into DWORD w/ 1st byte of
+                message LOB;
+           dwParam2 is time message received by input device driver, specified
+            in [ms] from when midiInStart called.
+           each message is expanded to include the status byte */
+
+        new_driver_time = dwParam2;
+
+        if ((dwParam1 & 0x80) == 0) {
+            /* not a status byte -- ignore it. This happened running the
+               sysex.c test under Win2K with MidiMan USB 1x1 interface,
+               but I can't reproduce it. -RBD
+             */
+            /* printf("non-status byte found\n"); */
+        } else { /* data to process */
+            PmEvent event;
+            if (midi->time_proc)
+                dwParam2 = (*midi->time_proc)(midi->time_info);
+            event.timestamp = dwParam2;
+            event.message = dwParam1;
+            pm_read_short(midi, &event);
+        }
+        LeaveCriticalSection(&m->lock);
+        break;
+    }
+    case MIM_LONGDATA: {
+        MIDIHDR *lpMidiHdr = (MIDIHDR *) dwParam1;
+        unsigned char *data = (unsigned char *) lpMidiHdr->lpData;
+        unsigned int processed = 0;
+        int remaining = lpMidiHdr->dwBytesRecorded;
+
+        EnterCriticalSection(&m->lock);
+        /* printf("midi_in_callback -- lpMidiHdr %x, %d bytes, %2x...\n", 
+                lpMidiHdr, lpMidiHdr->dwBytesRecorded, *data); */
+        if (midi->time_proc)
+            dwParam2 = (*midi->time_proc)(midi->time_info);
+        /* can there be more than one message in one buffer? */
+        /* assume yes and iterate through them */
+        while (remaining > 0) {
+            unsigned int amt = pm_read_bytes(midi, data + processed, 
+                                             remaining, dwParam2);
+            remaining -= amt;
+            processed += amt;
+        }
+
+        /* when a device is closed, the pending MIM_LONGDATA buffers are
+           returned to this callback with dwBytesRecorded == 0. In this
+           case, we do not want to send them back to the interface (if
+           we do, the interface will not close, and Windows OS may hang). */
+        if (lpMidiHdr->dwBytesRecorded > 0) {
+            MMRESULT rslt;
+            lpMidiHdr->dwBytesRecorded = 0;
+            lpMidiHdr->dwFlags = 0;
+                       
+            /* note: no error checking -- can this actually fail? */
+            rslt = midiInPrepareHeader(hMidiIn, lpMidiHdr, sizeof(MIDIHDR));
+            assert(rslt == MMSYSERR_NOERROR);
+            /* note: I don't think this can fail except possibly for
+             * MMSYSERR_NOMEM, but the pain of reporting this
+             * unlikely but probably catastrophic error does not seem
+             * worth it.
+             */
+            rslt = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR));
+            assert(rslt == MMSYSERR_NOERROR);
+            LeaveCriticalSection(&m->lock);
+        } else {
+            midiInUnprepareHeader(hMidiIn,lpMidiHdr,sizeof(MIDIHDR));
+            LeaveCriticalSection(&m->lock);
+            pm_free(lpMidiHdr);
+        }
+        break;
+    }
+    case MIM_OPEN:
+        break;
+    case MIM_CLOSE:
+        break;
+    case MIM_ERROR:
+        /* printf("MIM_ERROR\n"); */
+        break;
+    case MIM_LONGERROR:
+        /* printf("MIM_LONGERROR\n"); */
+        break;
+    default:
+        break;
+    }
+}
+
+/*
+=========================================================================================
+begin midi output implementation
+=========================================================================================
+*/
+
+/* begin helper routines used by midiOutStream interface */
+
+/* add_to_buffer -- adds timestamped short msg to buffer, returns fullp */
+static int add_to_buffer(midiwinmm_type m, LPMIDIHDR hdr,
+                         unsigned long delta, unsigned long msg)
+{
+    unsigned long *ptr = (unsigned long *)
+                         (hdr->lpData + hdr->dwBytesRecorded);
+    *ptr++ = delta; /* dwDeltaTime */
+    *ptr++ = 0;     /* dwStream */
+    *ptr++ = msg;   /* dwEvent */
+    hdr->dwBytesRecorded += 3 * sizeof(long);
+    /* if the addition of three more words (a message) would extend beyond
+       the buffer length, then return TRUE (full)
+     */
+    return hdr->dwBytesRecorded + 3 * sizeof(long) > hdr->dwBufferLength;
+}
+
+
+static PmTimestamp pm_time_get(midiwinmm_type m)
+{
+    MMTIME mmtime;
+    MMRESULT wRtn;
+    mmtime.wType = TIME_TICKS;
+    mmtime.u.ticks = 0;
+    wRtn = midiStreamPosition(m->handle.stream, &mmtime, sizeof(mmtime));
+    assert(wRtn == MMSYSERR_NOERROR);
+    return mmtime.u.ticks;
+}
+
+
+/* end helper routines used by midiOutStream interface */
+
+
+static PmError winmm_out_open(PmInternal *midi, void *driverInfo)
+{
+    DWORD dwDevice;
+    int i = midi->device_id;
+    midiwinmm_type m;
+    MIDIPROPTEMPO propdata;
+    MIDIPROPTIMEDIV divdata;
+    int max_sysex_len = midi->buffer_len * 4;
+    int output_buffer_len;
+    int num_buffers;
+    dwDevice = (DWORD) descriptors[i].descriptor;
+
+    /* create system dependent device data */
+    m = (midiwinmm_type) pm_alloc(sizeof(midiwinmm_node)); /* create */
+    midi->descriptor = m;
+    if (!m) goto no_memory;
+    m->handle.out = NULL;
+    m->buffers = NULL;
+    m->num_buffers = 0;
+    m->max_buffers = 0;
+    m->buffers_expanded = FALSE;
+    m->next_buffer = 0;
+#ifdef USE_SYSEX_BUFFERS
+    m->sysex_buffers[0] = NULL;
+    m->sysex_buffers[1] = NULL;
+    m->next_sysex_buffer = 0;
+#endif
+    m->last_time = 0;
+    m->first_message = TRUE; /* we treat first message as special case */
+    m->sysex_mode = FALSE;
+    m->sysex_word = 0;
+    m->sysex_byte_count = 0;
+    m->hdr = NULL;
+    m->sync_time = 0;
+    m->delta = 0;
+    m->error = MMSYSERR_NOERROR;
+
+    /* create a signal */
+    m->buffer_signal = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+    /* this should only fail when there are very serious problems */
+    assert(m->buffer_signal);
+
+    /* open device */
+    if (midi->latency == 0) {
+        /* use simple midi out calls */
+        pm_hosterror = midiOutOpen(
+                (LPHMIDIOUT) & m->handle.out,  /* device Handle */
+               dwDevice,  /* device ID  */
+               /* note: same callback fn as for StreamOpen: */
+               (DWORD_PTR) winmm_streamout_callback, /* callback fn */
+               (DWORD_PTR) midi,  /* callback instance data */
+               CALLBACK_FUNCTION); /* callback type */
+    } else {
+        /* use stream-based midi output (schedulable in future) */
+        pm_hosterror = midiStreamOpen(
+               &m->handle.stream,  /* device Handle */
+               (LPUINT) & dwDevice,  /* device ID pointer */
+               1,  /* reserved, must be 1 */
+               (DWORD_PTR) winmm_streamout_callback,
+               (DWORD_PTR) midi,  /* callback instance data */
+               CALLBACK_FUNCTION);
+    }
+    if (pm_hosterror != MMSYSERR_NOERROR) {
+        goto free_descriptor;
+    }
+
+    if (midi->latency == 0) {
+        num_buffers = NUM_SIMPLE_SYSEX_BUFFERS;
+        output_buffer_len = max_sysex_len / num_buffers;
+        if (output_buffer_len < MIN_SIMPLE_SYSEX_LEN)
+            output_buffer_len = MIN_SIMPLE_SYSEX_LEN;
+    } else {
+        long dur = 0;
+        num_buffers = max(midi->buffer_len, midi->latency / 2);
+        if (num_buffers < MIN_STREAM_BUFFERS)
+            num_buffers = MIN_STREAM_BUFFERS;
+        output_buffer_len = STREAM_BUFFER_LEN;
+
+        propdata.cbStruct = sizeof(MIDIPROPTEMPO);
+        propdata.dwTempo = 480000; /* microseconds per quarter */
+        pm_hosterror = midiStreamProperty(m->handle.stream,
+                                          (LPBYTE) & propdata,
+                                          MIDIPROP_SET | MIDIPROP_TEMPO);
+        if (pm_hosterror) goto close_device;
+
+        divdata.cbStruct = sizeof(MIDIPROPTEMPO);
+        divdata.dwTimeDiv = 480;   /* divisions per quarter */
+        pm_hosterror = midiStreamProperty(m->handle.stream,
+                                          (LPBYTE) & divdata,
+                                          MIDIPROP_SET | MIDIPROP_TIMEDIV);
+        if (pm_hosterror) goto close_device;
+    }
+    /* allocate buffers */
+    if (allocate_buffers(m, output_buffer_len, num_buffers)) 
+        goto free_buffers;
+    /* start device */
+    if (midi->latency != 0) {
+        pm_hosterror = midiStreamRestart(m->handle.stream);
+        if (pm_hosterror != MMSYSERR_NOERROR) goto free_buffers;
+    }
+    return pmNoError;
+
+free_buffers:
+    /* buffers are freed below by winmm_out_delete */
+close_device:
+    midiOutClose(m->handle.out);
+free_descriptor:
+    midi->descriptor = NULL;
+    winmm_out_delete(midi); /* frees buffers and m */
+no_memory:
+    if (pm_hosterror) {
+        int err = midiOutGetErrorText(pm_hosterror, (char *) pm_hosterror_text,
+                                      PM_HOST_ERROR_MSG_LEN);
+        assert(err == MMSYSERR_NOERROR);
+        return pmHostError;
+    }
+    return pmInsufficientMemory;
+}
+
+
+/* winmm_out_delete -- carefully free data associated with midi */
+/**/
+static void winmm_out_delete(PmInternal *midi)
+{
+    int i;
+    /* delete system dependent device data */
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    if (m) {
+        if (m->buffer_signal) {
+            /* don't report errors -- better not to stop cleanup */
+            CloseHandle(m->buffer_signal);
+        }
+        /* if using stream output, free buffers */
+        for (i = 0; i < m->num_buffers; i++) {
+            if (m->buffers[i]) pm_free(m->buffers[i]);
+        }
+        m->num_buffers = 0;
+        pm_free(m->buffers);
+        m->max_buffers = 0;
+#ifdef USE_SYSEX_BUFFERS
+        /* free sysex buffers */
+        for (i = 0; i < NUM_SYSEX_BUFFERS; i++) {
+            if (m->sysex_buffers[i]) pm_free(m->sysex_buffers[i]);
+        }
+#endif
+    }
+    midi->descriptor = NULL;
+    pm_free(m); /* delete */
+}
+
+
+/* see comments for winmm_in_close */
+static PmError winmm_out_close(PmInternal *midi)
+{
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    if (m->handle.out) {
+        /* device to close */
+        if (midi->latency == 0) {
+            pm_hosterror = midiOutClose(m->handle.out);
+        } else {
+            pm_hosterror = midiStreamClose(m->handle.stream);
+        }
+        /* regardless of outcome, free memory */
+        winmm_out_delete(midi);
+    }
+    if (pm_hosterror) {
+        int err = midiOutGetErrorText(pm_hosterror,
+                                      (char *) pm_hosterror_text,
+                                      PM_HOST_ERROR_MSG_LEN);
+        assert(err == MMSYSERR_NOERROR);
+        return pmHostError;
+    }
+    return pmNoError;
+}
+
+
+static PmError winmm_out_abort(PmInternal *midi)
+{
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    m->error = MMSYSERR_NOERROR;
+
+    /* only stop output streams */
+    if (midi->latency > 0) {
+        m->error = midiStreamStop(m->handle.stream);
+    }
+    return m->error ? pmHostError : pmNoError;
+}
+
+
+static PmError winmm_write_flush(PmInternal *midi, PmTimestamp timestamp)
+{
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    assert(m);
+    if (m->hdr) {
+        m->error = midiOutPrepareHeader(m->handle.out, m->hdr, 
+                                        sizeof(MIDIHDR));
+        if (m->error) {
+            /* do not send message */
+        } else if (midi->latency == 0) {
+            /* As pointed out by Nigel Brown, 20Sep06, dwBytesRecorded
+             * should be zero. This is set in get_free_sysex_buffer(). 
+             * The msg length goes in dwBufferLength in spite of what
+             * Microsoft documentation says (or doesn't say). */
+            m->hdr->dwBufferLength = m->hdr->dwBytesRecorded;
+            m->hdr->dwBytesRecorded = 0;
+            m->error = midiOutLongMsg(m->handle.out, m->hdr, sizeof(MIDIHDR));
+        } else {
+            m->error = midiStreamOut(m->handle.stream, m->hdr, 
+                                     sizeof(MIDIHDR));
+        }
+        midi->fill_base = NULL;
+        m->hdr = NULL;
+        if (m->error) {
+            m->hdr->dwFlags = 0; /* release the buffer */
+            return pmHostError;
+        }
+    }
+    return pmNoError;
+}
+
+
+
+#ifdef GARBAGE
+static PmError winmm_write_sysex_byte(PmInternal *midi, unsigned char byte)
+{
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    unsigned char *msg_buffer;
+
+    /* at the beginning of sysex, m->hdr is NULL */
+    if (!m->hdr) { /* allocate a buffer if none allocated yet */
+        m->hdr = get_free_output_buffer(midi);
+        if (!m->hdr) return pmInsufficientMemory;
+        m->sysex_byte_count = 0;
+    }
+    /* figure out where to write byte */
+    msg_buffer = (unsigned char *) (m->hdr->lpData);
+    assert(m->hdr->lpData == (char *) (m->hdr + 1));
+
+    /* check for overflow */
+    if (m->sysex_byte_count >= m->hdr->dwBufferLength) {
+        /* allocate a bigger message -- double it every time */
+        LPMIDIHDR big = allocate_buffer(m->sysex_byte_count * 2);
+        /* printf("expand to %d bytes\n", m->sysex_byte_count * 2); */
+        if (!big) return pmInsufficientMemory;
+        m->error = midiOutPrepareHeader(m->handle.out, big,
+                                        sizeof(MIDIHDR));
+        if (m->error) {
+            m->hdr = NULL;
+            return pmHostError;
+        }
+        memcpy(big->lpData, msg_buffer, m->sysex_byte_count);
+        msg_buffer = (unsigned char *) (big->lpData);
+        if (m->buffers[0] == m->hdr) {
+            m->buffers[0] = big;
+            pm_free(m->hdr);
+            /* printf("freed m->hdr\n"); */
+        } else if (m->buffers[1] == m->hdr) {
+            m->buffers[1] = big;
+            pm_free(m->hdr);
+            /* printf("freed m->hdr\n"); */
+        }
+        m->hdr = big;
+    }
+
+    /* append byte to message */
+    msg_buffer[m->sysex_byte_count++] = byte;
+
+    /* see if we have a complete message */
+    if (byte == MIDI_EOX) {
+        m->hdr->dwBytesRecorded = m->sysex_byte_count;
+        /*
+        { int i; int len = m->hdr->dwBytesRecorded;
+          printf("OutLongMsg %d ", len);
+          for (i = 0; i < len; i++) {
+              printf("%2x ", msg_buffer[i]);
+          }
+        }
+        */
+        m->error = midiOutLongMsg(m->handle.out, m->hdr, sizeof(MIDIHDR));
+        m->hdr = NULL; /* stop using this message buffer */
+        if (m->error) return pmHostError;
+    }
+    return pmNoError;
+}
+#endif
+
+
+static PmError winmm_write_short(PmInternal *midi, PmEvent *event)
+{
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    PmError rslt = pmNoError;
+    assert(m);
+
+    if (midi->latency == 0) { /* use midiOut interface, ignore timestamps */
+        m->error = midiOutShortMsg(m->handle.out, event->message);
+        if (m->error) rslt = pmHostError;
+    } else {  /* use midiStream interface -- pass data through buffers */
+        unsigned long when = event->timestamp;
+        unsigned long delta;
+        int full;
+        if (when == 0) when = midi->now;
+        /* when is in real_time; translate to intended stream time */
+        when = when + m->delta + midi->latency;
+        /* make sure we don't go backward in time */
+        if (when < m->last_time) when = m->last_time;
+        delta = when - m->last_time;
+        m->last_time = when;
+        /* before we insert any data, we must have a buffer */
+        if (m->hdr == NULL) {
+            /* stream interface: buffers allocated when stream is opened */
+            m->hdr = get_free_output_buffer(midi);
+        }
+        full = add_to_buffer(m, m->hdr, delta, event->message);
+        if (full) rslt = winmm_write_flush(midi, when);
+    }
+    return rslt;
+}
+
+#define winmm_begin_sysex winmm_write_flush
+#ifndef winmm_begin_sysex
+static PmError winmm_begin_sysex(PmInternal *midi, PmTimestamp timestamp)
+{
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    PmError rslt = pmNoError;
+
+    if (midi->latency == 0) {
+        /* do nothing -- it's handled in winmm_write_byte */
+    } else {
+        /* sysex expects an empty sysex buffer, so send whatever is here */
+        rslt = winmm_write_flush(midi);
+    }
+    return rslt;
+}
+#endif
+
+static PmError winmm_end_sysex(PmInternal *midi, PmTimestamp timestamp)
+{
+    /* could check for callback_error here, but I haven't checked
+     * what happens if we exit early and don't finish the sysex msg
+     * and clean up
+     */
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    PmError rslt = pmNoError;
+    LPMIDIHDR hdr = m->hdr;
+    if (!hdr) return rslt; /* something bad happened earlier,
+            do not report an error because it would have been 
+            reported (at least) once already */
+    /* a(n old) version of MIDI YOKE requires a zero byte after
+     * the sysex message, but do not increment dwBytesRecorded: */
+    hdr->lpData[hdr->dwBytesRecorded] = 0;
+    if (midi->latency == 0) {
+#ifdef DEBUG_PRINT_BEFORE_SENDING_SYSEX
+        /* DEBUG CODE: */
+        { int i; int len = m->hdr->dwBufferLength;
+          printf("OutLongMsg %d ", len);
+          for (i = 0; i < len; i++) {
+              printf("%2x ", (unsigned char) (m->hdr->lpData[i]));
+          }
+        }
+#endif
+    } else {
+        /* Using stream interface. There are accumulated bytes in m->hdr
+           to send using midiStreamOut
+         */
+        /* add bytes recorded to MIDIEVENT length, but don't
+           count the MIDIEVENT data (3 longs) */
+        MIDIEVENT *evt = (MIDIEVENT *) (hdr->lpData);
+        evt->dwEvent += hdr->dwBytesRecorded - 3 * sizeof(long);
+        /* round up BytesRecorded to multiple of 4 */
+        hdr->dwBytesRecorded = (hdr->dwBytesRecorded + 3) & ~3;
+    }
+    rslt = winmm_write_flush(midi, timestamp);
+    return rslt;
+}
+
+
+static PmError winmm_write_byte(PmInternal *midi, unsigned char byte,
+                                PmTimestamp timestamp)
+{
+    /* write a sysex byte */
+    PmError rslt = pmNoError;
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    LPMIDIHDR hdr = m->hdr;
+    unsigned char *msg_buffer;
+    assert(m);
+    if (!hdr) {
+        m->hdr = hdr = get_free_output_buffer(midi);
+        assert(hdr);
+        midi->fill_base = (unsigned char *) m->hdr->lpData;
+        midi->fill_offset_ptr = &(hdr->dwBytesRecorded);
+        /* when buffer fills, Pm_WriteSysEx will revert to calling
+         * pmwin_write_byte, which expect to have space, so leave
+         * one byte free for pmwin_write_byte. Leave another byte
+         * of space for zero after message to make early version of 
+         * MIDI YOKE driver happy -- therefore dwBufferLength - 2 */
+        midi->fill_length = hdr->dwBufferLength - 2;
+        if (midi->latency != 0) {
+            unsigned long when = (unsigned long) timestamp;
+            unsigned long delta;
+            unsigned long *ptr;
+            if (when == 0) when = midi->now;
+            /* when is in real_time; translate to intended stream time */
+            when = when + m->delta + midi->latency;
+            /* make sure we don't go backward in time */
+            if (when < m->last_time) when = m->last_time;
+            delta = when - m->last_time;
+            m->last_time = when;
+
+            ptr = (unsigned long *) hdr->lpData;
+            *ptr++ = delta;
+            *ptr++ = 0;
+            *ptr = MEVT_F_LONG;
+            hdr->dwBytesRecorded = 3 * sizeof(long);
+            /* data will be added at an offset of dwBytesRecorded ... */
+        }
+    }
+    /* add the data byte */
+    msg_buffer = (unsigned char *) (hdr->lpData);
+    msg_buffer[hdr->dwBytesRecorded++] = byte;
+
+    /* see if buffer is full, leave one byte extra for pad */
+    if (hdr->dwBytesRecorded >= hdr->dwBufferLength - 1) {
+        /* write what we've got and continue */
+        rslt = winmm_end_sysex(midi, timestamp); 
+    }
+    return rslt;
+}
+
+#ifdef EXPANDING_SYSEX_BUFFERS
+note: this code is here as an aid in case you want sysex buffers
+      to expand to hold large messages completely. If so, you
+      will want to change SYSEX_BYTES_PER_BUFFER above to some
+      variable that remembers the buffer size. A good place to 
+      put this value would be in the hdr->dwUser field.
+
+            rslt = resize_sysex_buffer(midi, m->sysex_byte_count, 
+                                       m->sysex_byte_count * 2);
+
+            if (rslt == pmBufferMaxSize) /* if the buffer can't be resized */
+#endif
+#ifdef EXPANDING_SYSEX_BUFFERS
+            int bytesRecorded = hdr->dwBytesRecorded; /* this field gets wiped out, so we'll save it */
+            rslt = resize_sysex_buffer(midi, bytesRecorded, 2 * bytesRecorded);
+            hdr->dwBytesRecorded = bytesRecorded;
+
+            if (rslt == pmBufferMaxSize) /* if buffer can't be resized */
+#endif
+
+
+
+static PmTimestamp winmm_synchronize(PmInternal *midi)
+{
+    midiwinmm_type m;
+    unsigned long pm_stream_time_2;
+    unsigned long real_time;
+    unsigned long pm_stream_time;
+
+    /* only synchronize if we are using stream interface */
+    if (midi->latency == 0) return 0;
+
+    /* figure out the time */
+    m = (midiwinmm_type) midi->descriptor;
+    pm_stream_time_2 = pm_time_get(m);
+
+    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 = pm_time_get(m);
+        /* repeat if more than 1ms elapsed */
+    } while (pm_stream_time_2 > pm_stream_time + 1);
+    m->delta = pm_stream_time - real_time;
+    m->sync_time = real_time;
+    return real_time;
+}
+
+#ifdef USE_SYSEX_BUFFERS
+/* winmm_out_callback -- recycle sysex buffers */
+static void CALLBACK winmm_out_callback(HMIDIOUT hmo, UINT wMsg,
+                                        DWORD dwInstance, DWORD dwParam1, 
+                                        DWORD dwParam2)
+{
+    PmInternal *midi = (PmInternal *) dwInstance;
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    LPMIDIHDR hdr = (LPMIDIHDR) dwParam1;
+    int err = 0;  /* set to 0 so that no buffer match will also be an error */
+
+    /* Future optimization: eliminate UnprepareHeader calls -- they aren't
+       necessary; however, this code uses the prepared-flag to indicate which
+       buffers are free, so we need to do something to flag empty buffers if
+       we leave them prepared
+     */
+    /*
+    printf("out_callback: hdr %x, wMsg %x, MOM_DONE %x\n", 
+           hdr, wMsg, MOM_DONE);
+    */
+    if (wMsg == MOM_DONE) {
+        MMRESULT ret = midiOutUnprepareHeader(m->handle.out, hdr, 
+                                              sizeof(MIDIHDR));
+        assert(ret == MMSYSERR_NOERROR);
+    }
+    /* notify waiting sender that a buffer is available */
+    err = SetEvent(m->buffer_signal);
+    assert(err); /* false -> error */
+}
+#endif
+
+/* winmm_streamout_callback -- unprepare (free) buffer header */
+static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg,
+        DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
+{
+    PmInternal *midi = (PmInternal *) dwInstance;
+    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+    LPMIDIHDR hdr = (LPMIDIHDR) dwParam1;
+    int err;
+
+    /* Even if an error is pending, I think we should unprepare msgs and
+       signal their arrival
+     */
+    /* printf("streamout_callback: hdr %x, wMsg %x, MOM_DONE %x\n", 
+           hdr, wMsg, MOM_DONE); */
+    if (wMsg == MOM_DONE) {
+        MMRESULT ret = midiOutUnprepareHeader(m->handle.out, hdr, 
+                                              sizeof(MIDIHDR));
+        assert(ret == MMSYSERR_NOERROR);
+    }
+    /* signal client in case it is blocked waiting for buffer */
+    err = SetEvent(m->buffer_signal);
+    assert(err); /* false -> error */
+}
+
+
+/*
+=========================================================================================
+begin exported functions
+=========================================================================================
+*/
+
+#define winmm_in_abort pm_fail_fn
+pm_fns_node pm_winmm_in_dictionary = {
+                                         none_write_short,
+                                         none_sysex,
+                                         none_sysex,
+                                         none_write_byte,
+                                         none_write_short,
+                                         none_write_flush,
+                                         winmm_synchronize,
+                                         winmm_in_open,
+                                         winmm_in_abort,
+                                         winmm_in_close,
+                                         winmm_in_poll,
+                                         winmm_has_host_error,
+                                         winmm_get_host_error
+                                     };
+
+pm_fns_node pm_winmm_out_dictionary = {
+                                          winmm_write_short,
+                                          winmm_begin_sysex,
+                                          winmm_end_sysex,
+                                          winmm_write_byte,
+                                          winmm_write_short,  /* short realtime message */
+                                          winmm_write_flush,
+                                          winmm_synchronize,
+                                          winmm_out_open,
+                                          winmm_out_abort,
+                                          winmm_out_close,
+                                          none_poll,
+                                          winmm_has_host_error,
+                                          winmm_get_host_error
+                                      };
+
+
+/* initialize winmm interface. Note that if there is something wrong
+   with winmm (e.g. it is not supported or installed), it is not an
+   error. We should simply return without having added any devices to
+   the table. Hence, no error code is returned. Furthermore, this init
+   code is called along with every other supported interface, so the
+   user would have a very hard time figuring out what hardware and API
+   generated the error. Finally, it would add complexity to pmwin.c to
+   remember where the error code came from in order to convert to text.
+ */
+void pm_winmm_init( void )
+{
+    pm_winmm_mapper_input();
+    pm_winmm_mapper_output();
+    pm_winmm_general_inputs();
+    pm_winmm_general_outputs();
+}
+
+
+/* no error codes are returned, even if errors are encountered, because
+   there is probably nothing the user could do (e.g. it would be an error
+   to retry.
+ */
+void pm_winmm_term( void )
+{
+    int i;
+#ifdef DEBUG
+    char msg[PM_HOST_ERROR_MSG_LEN];
+#endif
+    int doneAny = 0;
+#ifdef DEBUG
+    printf("pm_winmm_term called\n");
+#endif
+    for (i = 0; i < pm_descriptor_index; i++) {
+        PmInternal * midi = descriptors[i].internalDescriptor;
+        if (midi) {
+            midiwinmm_type m = (midiwinmm_type) midi->descriptor;
+            if (m->handle.out) {
+                /* close next open device*/
+#ifdef DEBUG
+                if (doneAny == 0) {
+                    printf("begin closing open devices...\n");
+                    doneAny = 1;
+                }
+                /* report any host errors; this EXTEREMELY useful when
+                   trying to debug client app */
+                if (winmm_has_host_error(midi)) {
+                    winmm_get_host_error(midi, msg, PM_HOST_ERROR_MSG_LEN);
+                    printf("%s\n", msg);
+                }
+#endif
+                /* close all open ports */
+                (*midi->dictionary->close)(midi);
+            }
+        }
+    }
+    if (midi_in_caps) {
+        pm_free(midi_in_caps);
+        midi_in_caps = NULL;
+    }
+    if (midi_out_caps) {
+        pm_free(midi_out_caps);
+        midi_out_caps = NULL;
+    }
+#ifdef DEBUG
+    if (doneAny) {
+        printf("warning: devices were left open. They have been closed.\n");
+    }
+    printf("pm_winmm_term exiting\n");
+#endif
+    pm_descriptor_index = 0;
+}
index 53c5fe28415283767ce0b70e10edbf60e45142f6..94742001bcd5630fc12df0806e2bbdc162b42307 100644 (file)
@@ -1,5 +1,5 @@
-/* midiwin32.h -- system-specific definitions */\r
-\r
-void pm_winmm_init( void );\r
-void pm_winmm_term( void );\r
-\r
+/* midiwin32.h -- system-specific definitions */
+
+void pm_winmm_init( void );
+void pm_winmm_term( void );
+
index 753f5832ef427fe31d14c46ba614ae46883f451e..c23210e4dce50f289dc82865f14b171cde321209 100644 (file)
-/* 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
+/* ptmacosx.c -- portable timer implementation for mac os x */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <CoreAudio/HostTime.h>
+
+#import <mach/mach.h>
+#import <mach/mach_error.h>
+#import <mach/mach_time.h>
+#import <mach/clock.h>
+#include <unistd.h>
+
+#include "porttime.h"
+#include "sys/time.h"
+#include "pthread.h"
+
+#define NSEC_PER_MSEC 1000000
+#define THREAD_IMPORTANCE 30
+
+static int time_started_flag = FALSE;
+static UInt64 start_time;
+static pthread_t pt_thread_pid;
+
+/* note that this is static data -- we only need one copy */
+typedef struct {
+    int id;
+    int resolution;
+    PtCallback *callback;
+    void *userData;
+} pt_callback_parameters;
+
+static int pt_callback_proc_id = 0;
+
+static void *Pt_CallbackProc(void *p)
+{
+    pt_callback_parameters *parameters = (pt_callback_parameters *) p;
+    int mytime = 1;
+
+    kern_return_t error;
+    thread_extended_policy_data_t extendedPolicy;
+    thread_precedence_policy_data_t precedencePolicy;
+
+    extendedPolicy.timeshare = 0;
+    error = thread_policy_set(mach_thread_self(), THREAD_EXTENDED_POLICY,
+                              (thread_policy_t)&extendedPolicy,
+                              THREAD_EXTENDED_POLICY_COUNT);
+    if (error != KERN_SUCCESS) {
+        mach_error("Couldn't set thread timeshare policy", error);
+    }
+
+    precedencePolicy.importance = THREAD_IMPORTANCE;
+    error = thread_policy_set(mach_thread_self(), THREAD_PRECEDENCE_POLICY,
+                              (thread_policy_t)&precedencePolicy,
+                              THREAD_PRECEDENCE_POLICY_COUNT);
+    if (error != KERN_SUCCESS) {
+        mach_error("Couldn't set thread precedence policy", error);
+    }
+    
+    
+    /* to kill a process, just increment the pt_callback_proc_id */
+    /* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id, parameters->id); */
+    while (pt_callback_proc_id == parameters->id) {
+        /* wait for a multiple of resolution ms */
+        UInt64 wait_time;
+        int delay = mytime++ * parameters->resolution - Pt_Time();
+       PtTimestamp timestamp;
+        if (delay < 0) delay = 0;
+        wait_time = AudioConvertNanosToHostTime((UInt64)delay * NSEC_PER_MSEC);
+        wait_time += AudioGetCurrentHostTime();
+        error = mach_wait_until(wait_time);
+       timestamp = Pt_Time();
+        (*(parameters->callback))(timestamp, parameters->userData);
+    }
+    free(parameters);
+    return NULL;
+}
+
+
+PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
+{
+    if (time_started_flag) return ptAlreadyStarted;
+    start_time = AudioGetCurrentHostTime();
+    
+    if (callback) {
+        int res;
+        pt_callback_parameters *parms;
+
+        parms = (pt_callback_parameters *) malloc(sizeof(pt_callback_parameters));
+        if (!parms) return ptInsufficientMemory;
+        parms->id = pt_callback_proc_id;
+        parms->resolution = resolution;
+        parms->callback = callback;
+        parms->userData = userData;
+        res = pthread_create(&pt_thread_pid, NULL, Pt_CallbackProc, parms);
+        if (res != 0) return ptHostError;
+    }
+    
+    time_started_flag = TRUE;
+    return ptNoError;
+}
+
+
+PtError Pt_Stop()
+{
+    /* printf("Pt_Stop called\n"); */
+    pt_callback_proc_id++;
+    pthread_join(pt_thread_pid, NULL);
+    time_started_flag = FALSE;
+    return ptNoError;
+}
+
+
+int Pt_Started()
+{
+    return time_started_flag;
+}
+
+
+PtTimestamp Pt_Time()
+{
+    UInt64 clock_time, nsec_time;
+    clock_time = AudioGetCurrentHostTime() - start_time;
+    nsec_time = AudioConvertHostTimeToNanos(clock_time);
+    return (PtTimestamp)(nsec_time / NSEC_PER_MSEC);
+}
+
+
+void Pt_Sleep(int32_t duration)
+{
+    usleep(duration * 1000);
+}
index 0d547527824efabb0a340d55c9db67f7f2cf1bc6..e08c60af2bdbcf49f20b2dec16a5d8fdba446019 100644 (file)
-/*\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
-    , _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_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
-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
+/*
+    Copyright (C) 2013 Valeriy Kamyshniy
+
+    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_audiobackend.h"
+#include "waves_audioport.h"
+#include "waves_midiport.h"
+
+using namespace ARDOUR;
+
+void WavesAudioBackend::AudioDeviceManagerNotification (NotificationReason reason, void* parameter)
+{
+    switch (reason) {
+        case WCMRAudioDeviceManagerClient::DeviceDebugInfo:
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::DeviceDebugInfo -- " << (char*)parameter << std::endl;
+        break;
+        case WCMRAudioDeviceManagerClient::BufferSizeChanged:
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::BufferSizeChanged: " << *(uint32_t*)parameter << std::endl;
+                       _buffer_size_change(*(uint32_t*)parameter);
+        break;
+        case WCMRAudioDeviceManagerClient::RequestReset:
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::RequestReset" << std::endl;
+            break;
+        case WCMRAudioDeviceManagerClient::RequestResync:
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::RequestResync" << std::endl;
+            break;
+        case WCMRAudioDeviceManagerClient::SamplingRateChanged:
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::SamplingRateChanged: " << *(float*)parameter << std::endl;
+                       set_sample_rate(*(float*)parameter);
+            break;
+        case WCMRAudioDeviceManagerClient::DeviceDroppedSamples:
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::DeviceDroppedSamples" << std::endl;
+            break;
+        case WCMRAudioDeviceManagerClient::DeviceStoppedStreaming:
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::DeviceStoppedStreaming" << std::endl;
+            break;
+               case WCMRAudioDeviceManagerClient::DeviceStartsStreaming:
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::DeviceStartsStreaming" << std::endl;
+                       _call_thread_init_callback = true; // streaming will be started from device side, just set thread init flag
+            break;
+        case WCMRAudioDeviceManagerClient::DeviceConnectionLost:
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::DeviceConnectionLost" << std::endl;
+            break;
+        case WCMRAudioDeviceManagerClient::DeviceListChanged:
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::DeviceListChanged" << std::endl;
+            _device_list_change();
+            break;
+        case WCMRAudioDeviceManagerClient::IODeviceDisconnected:
+            std::cout << "-------------------------------  WCMRAudioDeviceManagerClient::DeviceListChanged" << std::endl;
+            _device_list_change();
+            break;
+        case WCMRAudioDeviceManagerClient::AudioCallback:
+            if (parameter) {
+                AudioCallbackData* audio_callback_data = (AudioCallbackData*)parameter;
+                _audio_device_callback (
+                    audio_callback_data->acdInputBuffer,
+                    audio_callback_data->acdOutputBuffer,
+                    audio_callback_data->acdFrames,
+                    audio_callback_data->acdSampleTime,
+                    audio_callback_data->acdCycleStartTimeNanos
+                );
+            }
+        break;
+        
+        default:
+        break;
+    };
+}
+
+
+WavesAudioBackend::WavesAudioBackend (AudioEngine& e)
+    : AudioBackend (e)
+    , _audio_device_manager (this)
+    , _midi_device_manager (*this)
+    , _device (NULL)
+    , _sample_format (FormatFloat)
+    , _interleaved (true)
+    , _input_channels (0)
+    , _max_input_channels (0)
+    , _output_channels (0)
+    , _max_output_channels (0)
+    , _sample_rate (0)
+    , _buffer_size (0)
+    , _systemic_input_latency (0)
+    , _systemic_output_latency (0)
+    , _call_thread_init_callback (false)
+    , _use_midi (true)
+    , _sample_time_at_cycle_start (0)
+    , _freewheeling (false)
+    , _freewheel_thread_active (false)
+    , _audio_cycle_period_nanos (0)
+    , _dsp_load_accumulator (0)
+    , _dsp_load_history_length(0)
+{
+}
+
+
+WavesAudioBackend::~WavesAudioBackend ()
+{
+    
+}
+
+std::string
+WavesAudioBackend::name () const
+{
+#ifdef __MACOS__
+    return std::string ("CoreAudio");
+#elif _WINDOWS
+    return std::string ("ASIO");
+#endif
+}
+
+
+bool
+WavesAudioBackend::is_realtime () const
+{
+    return true;
+}
+
+
+bool 
+WavesAudioBackend::requires_driver_selection () const
+{ 
+    return false; 
+}
+
+
+std::vector<std::string> 
+WavesAudioBackend::enumerate_drivers () const
+{ 
+    // this backend does not suppose driver selection
+    assert (false);
+
+    return std::vector<std::string> (); 
+}
+
+
+int 
+WavesAudioBackend::set_driver (const std::string& /*drivername*/)
+{
+    //Waves audio backend does not suppose driver selection
+    assert (false);
+
+    return -1; 
+}
+
+
+std::vector<AudioBackend::DeviceStatus> 
+WavesAudioBackend::enumerate_devices () const
+{   
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::enumerate_devices (): " << std::endl;
+
+    std::vector<DeviceStatus> devicesStatus;
+    const DeviceInfoVec& deviceInfoList = _audio_device_manager.DeviceInfoList(); 
+
+    for (DeviceInfoVecConstIter deviceInfoIter = deviceInfoList.begin ();  deviceInfoIter != deviceInfoList.end (); ++deviceInfoIter) {
+        // COMMENTED DBG LOGS */ std::cout << "\t Device found: " << (*deviceInfoIter)->m_DeviceName << std::endl;
+        devicesStatus.push_back (DeviceStatus ((*deviceInfoIter)->m_DeviceName, true));
+    }
+    
+    return devicesStatus;
+} 
+
+
+std::vector<float> 
+WavesAudioBackend::available_sample_rates (const std::string& device_name) const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::available_sample_rates (): [" << device_name << "]" << std::endl;
+
+       DeviceInfo devInfo;
+    WTErr err = _audio_device_manager.GetDeviceInfoByName(device_name, devInfo);
+    
+       if (eNoErr != err) {
+        std::cerr << "WavesAudioBackend::available_sample_rates (): Failed to find device [" << device_name << "]" << std::endl;
+        return std::vector<float> ();
+    }
+
+    // COMMENTED DBG LOGS */ std::cout << "\tFound " << devInfo.m_AvailableSampleRates.size () << " sample rates for " << device_name << ":";
+
+    std::vector<float> sample_rates (devInfo.m_AvailableSampleRates.begin (), devInfo.m_AvailableSampleRates.end ());
+    
+    // COMMENTED DBG LOGS */ for (std::vector<float>::iterator i = sample_rates.begin ();  i != sample_rates.end (); ++i) std::cout << " " << *i; std::cout << std::endl;
+
+    return sample_rates;
+}
+
+
+float WavesAudioBackend::default_sample_rate () const 
+{ 
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::default_sample_rate (): " << AudioBackend::default_sample_rate () << std::endl;
+    return AudioBackend::default_sample_rate (); 
+}
+
+
+std::vector<uint32_t> 
+WavesAudioBackend::available_buffer_sizes (const std::string& device_name) const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::available_buffer_sizes (): [" << device_name << "]" << std::endl;
+
+       std::vector<int> bs;
+
+       WTErr retVal;
+       retVal = _audio_device_manager.GetDeviceBufferSizes(device_name, bs);
+
+    if (retVal != eNoErr) {
+        std::cerr << "WavesAudioBackend::available_buffer_sizes (): Failed to get buffer size for device [" << device_name << "]" << std::endl;
+        return std::vector<uint32_t> ();
+    }
+
+    std::vector<uint32_t> buffer_sizes (bs.begin (), bs.end ());
+
+    // COMMENTED DBG LOGS */ std::cout << "\tFound " << buffer_sizes.size () << " buffer sizes for " << device_name << ":";
+    // 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;
+
+    return buffer_sizes;
+}
+
+
+uint32_t 
+WavesAudioBackend::available_input_channel_count (const std::string& device_name) const
+{
+    DeviceInfo devInfo;
+    WTErr err = _audio_device_manager.GetDeviceInfoByName(device_name, devInfo);
+    
+       if (eNoErr != err) {
+        std::cerr << "WavesAudioBackend::available_input_channel_count (): Failed to find device [" << device_name << "]" << std::endl;
+        return 0;
+    }
+
+    uint32_t num_of_input_channels = devInfo.m_MaxInputChannels;
+
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::available_input_channel_count (): " << num_of_input_channels << std::endl;
+    return num_of_input_channels;
+}
+
+
+uint32_t 
+WavesAudioBackend::available_output_channel_count (const std::string& device_name) const
+{
+    DeviceInfo devInfo;
+    WTErr err = _audio_device_manager.GetDeviceInfoByName(device_name, devInfo);
+    
+       if (eNoErr != err) {
+        std::cerr << "WavesAudioBackend::available_output_channel_count (): Failed to find device [" << device_name << "]" << std::endl;
+        return 0;
+    }
+
+    uint32_t num_of_output_channels = devInfo.m_MaxOutputChannels;
+
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::available_output_channel_count (): " << num_of_output_channels << std::endl;
+
+    return num_of_output_channels;
+}
+
+
+bool
+WavesAudioBackend::can_change_sample_rate_when_running () const
+{
+    // VERIFY IT CAREFULLY
+    return true;
+}
+
+
+bool
+WavesAudioBackend::can_change_buffer_size_when_running () const
+{
+    // VERIFY IT CAREFULLY
+    return true;
+}
+
+
+int
+WavesAudioBackend::set_device_name (const std::string& device_name)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_device_name (): " << device_name << std::endl;
+    
+    if (_ports.size ()) {
+        std::cerr << "WavesAudioBackend::set_device_name (): There are unregistered ports left after [" << (_device ? _device->DeviceName () : std::string ("<NULL>")) << "]!" << std::endl;
+        for (size_t i = 0; i < _ports.size (); ++i) {
+            std::cerr << "\t[" << _ports[i]->name () << "]!" << std::endl;
+        }
+        return -1;
+    }
+
+       if (_device && _device->Streaming () ) {
+               std::cerr << "WavesAudioBackend::set_device_name (): [" << _device->DeviceName () << "] is streaming! Current device must be stopped before setting another device as current" << std::endl;
+       }
+
+       // we must have only one device initialized at a time
+       // stop current device first
+       WTErr retVal;
+    if (_device) {
+        retVal = _device->SetActive (false);
+        if (retVal != eNoErr) {
+            std::cerr << "WavesAudioBackend::set_device_name (): [" << _device->DeviceName () << "]->SetActive (false) failed!" << std::endl;
+            return -1;
+        }
+    }
+
+       // deinitialize it
+       _audio_device_manager.DestroyCurrentDevice();
+       _device = 0;
+
+    WCMRAudioDevice * device = _audio_device_manager.InitNewCurrentDevice(device_name);
+
+    if (!device) {
+        std::cerr << "WavesAudioBackend::set_device_name (): Failed to initialize device [" << device_name << "]!" << std::endl;
+        return -1;
+    }
+
+
+    retVal = device->SetActive (true);
+    if (retVal != eNoErr) {
+        std::cerr << "WavesAudioBackend::set_device_name (): [" << device->DeviceName () << "]->SetActive () failed!" << std::endl;
+        return -1;
+    }
+
+    _device = device;
+    return 0;
+}
+
+
+int
+WavesAudioBackend::drop_device()
+{
+       WTErr wtErr = 0;
+
+       if (_device)
+       {
+               wtErr = _device->SetActive (false);
+               if (wtErr != eNoErr) {
+                       std::cerr << "WavesAudioBackend::drop_device (): [" << _device->DeviceName () << "]->SetActive () failed!" << std::endl;
+                       return -1;
+               }
+       }
+
+       _audio_device_manager.DestroyCurrentDevice();
+       _device = 0;
+
+       return 0;
+}
+
+
+int 
+WavesAudioBackend::set_sample_rate (float sample_rate)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_sample_rate (): " << sample_rate << std::endl;
+    
+    WTErr retVal = eNoErr;
+
+    if (!_device) {
+        std::cerr << "WavesAudioBackend::set_sample_rate (): No device is set!" << std::endl;
+        return -1;
+    }
+
+    
+    bool device_needs_restart = _device->Streaming ();
+    
+    if (device_needs_restart) {
+        retVal  = _device->SetStreaming (false);
+        // COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->_device->SetStreaming (false);"<< std::endl;
+        if (retVal != eNoErr) {
+            std::cerr << "WavesAudioBackend::set_sample_rate (): [" << _device->DeviceName () << "]->SetStreaming (false) failed (" << retVal << ") !" << std::endl;
+            return -1;
+        }
+    }
+    
+    retVal = _device->SetCurrentSamplingRate ((int)sample_rate);
+    
+    if (retVal != eNoErr) {
+        std::cerr << "WavesAudioBackend::set_sample_rate (): [" << _device->DeviceName() << "]->SetCurrentSamplingRate ((int)" << sample_rate << ") failed (" << retVal << ") !" << std::endl;
+        return -1;
+    }
+
+       _sample_rate_change(sample_rate);
+       
+    if (device_needs_restart) {
+        // COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetStreaming (true);"<< std::endl;
+        _call_thread_init_callback = true;
+        retVal  = _device->SetStreaming (true);
+        if (retVal != eNoErr) {
+            std::cerr << "WavesAudioBackend::set_sample_rate (): [" << _device->DeviceName () << "]->SetStreaming (true) failed (" << retVal << ") !" << std::endl;
+            return -1;
+        }
+    }
+    return 0;
+}
+
+
+int 
+WavesAudioBackend::set_buffer_size (uint32_t buffer_size)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_buffer_size (" << buffer_size << "):"<< std::endl;
+
+    WTErr retVal = eNoErr;
+
+    if (!_device) {
+        std::cerr << "WavesAudioBackend::set_buffer_size (): No device is set!" << std::endl;
+        return -1;
+    }
+
+    bool device_needs_restart = _device->Streaming ();
+    
+    if (device_needs_restart) {
+        retVal  = _device->SetStreaming (false);
+        // COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetStreaming (false);"<< std::endl;
+        if (retVal != eNoErr) {
+            std::cerr << "WavesAudioBackend::set_buffer_size (): [" << _device->DeviceName () << "]->SetStreaming (false) failed (" << retVal << ") !" << std::endl;
+            return -1;
+        }
+    }
+    
+    retVal = _device->SetCurrentBufferSize (buffer_size);
+    
+    if (retVal != eNoErr) {
+        std::cerr << "WavesAudioBackend::set_buffer_size (): [" << _device->DeviceName() << "]->SetCurrentBufferSize (" << buffer_size << ") failed (" << retVal << ") !" << std::endl;
+        return -1;
+    }
+    
+       _buffer_size_change(buffer_size);
+    
+    if (device_needs_restart) {
+        // COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetStreaming (true);"<< std::endl;
+        _call_thread_init_callback = true;
+        retVal  = _device->SetStreaming (true);
+        if (retVal != eNoErr) {
+            std::cerr << "WavesAudioBackend::set_buffer_size (): [" << _device->DeviceName () << "]->SetStreaming (true) failed (" << retVal << ") !" << std::endl;
+            return -1;
+        }
+    }
+    
+    return 0;
+}
+
+
+int 
+WavesAudioBackend::set_sample_format (SampleFormat sample_format)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_sample_format (): " << sample_format << std::endl;
+
+    _sample_format = sample_format;
+    return 0;
+}
+
+int 
+WavesAudioBackend::_reset_device (uint32_t buffer_size, float sample_rate)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::_reset_device (" << buffer_size <<", " << sample_rate << "):" << std::endl;
+
+    WTErr retVal = eNoErr;
+
+    if (!_device) {
+        std::cerr << "WavesAudioBackend::set_buffer_size (): No device is set!" << std::endl;
+        return -1;
+    }
+
+    bool device_needs_restart = _device->Streaming ();
+    
+    if (device_needs_restart) {
+        retVal  = _device->SetStreaming (false);
+        // COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetStreaming (false);"<< std::endl;
+        if (retVal != eNoErr) {
+            std::cerr << "WavesAudioBackend::_reset_device (): [" << _device->DeviceName () << "]->SetStreaming (false) failed (" << retVal << ") !" << std::endl;
+            return -1;
+        }
+        retVal  = _device->SetActive (false);
+        // COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetActive (false);"<< std::endl;
+        if (retVal != eNoErr) {
+            std::cerr << "WavesAudioBackend::_reset_device (): [" << _device->DeviceName () << "]->SetActive (false) failed (" << retVal << ") !" << std::endl;
+            return -1;
+        }
+    }
+    
+       retVal = _device->UpdateDeviceInfo ();
+       if (retVal != eNoErr) {
+               std::cerr << "WavesAudioBackend::_reset_device (): [" << _device->DeviceName() << "]->UpdateDeviceInfo () failed (" << retVal << ") !" << std::endl;
+               return -1;
+       }
+
+       if (buffer_size != 0)
+       {
+               retVal = _device->SetCurrentBufferSize (buffer_size);
+    
+               if (retVal != eNoErr) {
+                       std::cerr << "WavesAudioBackend::_reset_device (): [" << _device->DeviceName() << "]->SetCurrentBufferSize (" << buffer_size << ") failed (" << retVal << ") !" << std::endl;
+                       return -1;
+               }
+    
+           _buffer_size = buffer_size;
+       }
+       else
+       {
+               uint32_t current_buffer_size = _device->CurrentBufferSize();
+               // COMMENTED DBG LOGS */ std::cout << "\t\tcurrent_buffer_size: " << current_buffer_size << std::endl;
+               // COMMENTED DBG LOGS */ std::cout << "\t\t       _buffer_size: " << _buffer_size << std::endl;
+               if(_buffer_size != current_buffer_size)
+               {
+                       _buffer_size = current_buffer_size;
+                       engine.buffer_size_change (_buffer_size);
+                       // COMMENTED DBG LOGS */ std::cout << "\t\tengine.buffer_size_change (" << buffer_size <<")" << std::endl;
+               }
+       }
+
+       if(sample_rate > 0.0)
+       {
+               retVal = _device->SetCurrentSamplingRate ((int)sample_rate);
+    
+               if (retVal != eNoErr) {
+                       std::cerr << "WavesAudioBackend::set_sample_rate (): [" << _device->DeviceName() << "]->SetCurrentSamplingRate ((int)" << sample_rate << ") failed (" << retVal << ") !" << std::endl;
+                       return -1;
+               }
+           _sample_rate = sample_rate;
+       }
+       else
+       {
+               float current_sample_rate = _device->CurrentSamplingRate();
+               // COMMENTED DBG LOGS */ std::cout << "\t\tcurrent_sample_rate: " << current_sample_rate << std::endl;
+               // COMMENTED DBG LOGS */ std::cout << "\t\t       _sample_rate: " << _sample_rate << std::endl;
+               if(_sample_rate != current_sample_rate)
+               {
+                       _sample_rate = current_sample_rate;
+                       engine.sample_rate_change (_sample_rate);
+                       // COMMENTED DBG LOGS */ std::cout << "\t\tengine.sample_rate_change (" << _sample_rate <<")" << std::endl;
+               }
+       }
+
+    _init_dsp_load_history();
+    
+    if (device_needs_restart) {
+        // COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetActive (true);"<< std::endl;
+        retVal  = _device->SetActive (true);
+        if (retVal != eNoErr) {
+            std::cerr << "WavesAudioBackend::_reset_device (): [" << _device->DeviceName () << "]->SetActive (true) failed (" << retVal << ") !" << std::endl;
+            return -1;
+        }
+        // COMMENTED DBG LOGS */ std::cout << "\t\t[" << _device->DeviceName() << "]->SetStreaming (true);"<< std::endl;
+        _call_thread_init_callback = true;
+        retVal  = _device->SetStreaming (true);
+        if (retVal != eNoErr) {
+            std::cerr << "WavesAudioBackend::_reset_device (): [" << _device->DeviceName () << "]->SetStreaming (true) failed (" << retVal << ") !" << std::endl;
+            return -1;
+        }
+    }
+    
+    return 0;
+}
+
+
+int 
+WavesAudioBackend::_buffer_size_change (uint32_t new_buffer_size)
+{
+       _buffer_size = new_buffer_size;
+    _init_dsp_load_history();
+    return engine.buffer_size_change (new_buffer_size);
+}
+
+
+int 
+WavesAudioBackend::_sample_rate_change (float new_sample_rate)
+{
+       _sample_rate = new_sample_rate;
+    _init_dsp_load_history();
+    return engine.sample_rate_change (new_sample_rate);
+}
+
+
+int
+WavesAudioBackend::_device_list_change ()
+{
+       // requires GZ changes for device list update
+       // return engine.device_list_change ();
+       return 0;
+}
+
+
+int 
+WavesAudioBackend::set_interleaved (bool yn)
+{
+    /*you can ignore them totally*/
+    _interleaved = yn;
+    return 0;
+}
+
+
+int 
+WavesAudioBackend::set_input_channels (uint32_t input_channels)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_input_channels (): " << input_channels << std::endl;
+
+    _input_channels = input_channels;
+    return 0;
+}
+
+
+int 
+WavesAudioBackend::set_output_channels (uint32_t output_channels)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_output_channels (): " << output_channels << std::endl;
+
+    _output_channels = output_channels;
+    return 0;
+}
+
+
+std::string  
+WavesAudioBackend::device_name () const
+{
+    if (!_device) {
+        return "";
+    }
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::device_name (): " << _device->DeviceName () << std::endl;
+    
+    return _device->DeviceName ();
+}
+
+
+float        
+WavesAudioBackend::sample_rate () const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::sample_rate (): " << std::endl;
+
+    if (!_device) {
+        std::cerr << "WavesAudioBackend::sample_rate (): No device is set!" << std::endl;
+        return -1;
+    }
+
+    int sample_rate = _device->CurrentSamplingRate ();
+
+    // COMMENTED DBG LOGS */ std::cout << "\t[" << _device->DeviceName () << "]->CurrentSamplingRate () returned " << sample_rate << std::endl;
+
+    return (float)sample_rate;
+}
+
+
+uint32_t     
+WavesAudioBackend::buffer_size () const
+{
+
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::buffer_size (): " << std::endl;
+
+    if (!_device) {
+        std::cerr << "WavesAudioBackend::buffer_size (): No device is set!" << std::endl;
+        return 0;
+    }
+
+    int size = _device->CurrentBufferSize ();
+    
+    // COMMENTED DBG LOGS */ std::cout << "\t[" << _device->DeviceName () << "]->CurrentBufferSize () returned " << size << std::endl;
+
+    return (uint32_t)size;
+}
+
+
+SampleFormat 
+WavesAudioBackend::sample_format () const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::sample_format ()" << std::endl;
+    return _sample_format;
+}
+
+
+bool         
+WavesAudioBackend::interleaved () const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::interleaved ()" << std::endl;
+
+    return _interleaved;
+}
+
+
+uint32_t     
+WavesAudioBackend::input_channels () const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::input_channels ()" << std::endl;
+
+    return _input_channels;
+}
+
+
+uint32_t     
+WavesAudioBackend::output_channels () const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::output_channels ()" << std::endl;
+
+    return _output_channels;
+}
+
+
+std::string 
+WavesAudioBackend::control_app_name () const
+{
+    std::string app_name = ""; 
+
+    if (_device && !dynamic_cast<WCMRNativeAudioNoneDevice*> (_device))    {
+        app_name = "PortAudioMayKnowIt";
+    }
+
+    return app_name; 
+}
+
+
+void
+WavesAudioBackend::launch_control_app ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::launch_control_app ()" << std::endl;
+    if (!_device) {
+        std::cerr << "WavesAudioBackend::launch_control_app (): No device is set!" << std::endl;
+        return;
+    }
+    
+    WTErr err = _device->ShowConfigPanel (NULL);
+    
+    if (eNoErr != err) {
+        std::cerr << "WavesAudioBackend::launch_control_app (): [" << _device->DeviceName () << "]->ShowConfigPanel () failed (" << err << ")!" << std::endl;
+    }
+
+    // COMMENTED DBG LOGS */ else std::cout << "WavesAudioBackend::launch_control_app (): [" << _device->DeviceName () << "]->ShowConfigPanel ()  successfully launched!" << std::endl;
+}
+
+
+int
+WavesAudioBackend::_start (bool for_latency_measurement)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::_start ()" << std::endl;
+
+    if (!_device) {
+        std::cerr << "WavesAudioBackend::_start (): No device is set!" << std::endl;
+        return -1;
+    }
+
+    if (_register_system_audio_ports () != 0) {
+        std::cerr << "WavesAudioBackend::_start (): _register_system_audio_ports () failed!" << std::endl;
+        return -1;
+    }
+
+    if (_use_midi) {
+        if (_midi_device_manager.start () != 0) {
+            std::cerr << "WavesAudioBackend::_start (): _midi_device_manager.start () failed!" << std::endl;
+            return -1;
+        }
+        if (_register_system_midi_ports () != 0) {
+            std::cerr << "WavesAudioBackend::_start (): _register_system_midi_ports () failed!" << std::endl;
+            return -1;
+        }
+    }
+
+    if (engine.reestablish_ports () != 0) {
+        std::cerr << "WavesAudioBackend::_start (): engine.reestablish_ports () failed!" << std::endl;
+    }
+
+    manager.registration_callback ();
+
+    _call_thread_init_callback = true;
+    WTErr retVal  = _device->SetStreaming (true);
+    if (retVal != eNoErr) {
+        std::cerr << "WavesAudioBackend::_start (): [" << _device->DeviceName () << "]->SetStreaming () failed!" << std::endl;
+        return -1;
+    }
+
+    if (_use_midi) {
+        if (_midi_device_manager.stream (true)) {
+            std::cerr << "WavesAudioBackend::_start (): _midi_device_manager.stream (true) failed!" << std::endl;
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+
+void
+WavesAudioBackend::_audio_device_callback (const float* input_buffer, 
+                                           float* output_buffer, 
+                                           unsigned long nframes,
+                                           pframes_t sample_time,
+                                           uint64_t cycle_start_time_nanos)
+{
+    uint64_t dsp_start_time_nanos = __get_time_nanos();
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::_audio_device_callback ():" << _device->DeviceName () << std::endl;
+    _sample_time_at_cycle_start = sample_time;
+    _cycle_start_time_nanos = cycle_start_time_nanos;
+
+    if (_buffer_size != nframes) {
+        // COMMENTED DBG LOGS */ std::cout << "\tAudioEngine::thread_init_callback() buffer size and nframes are not equal: " << _buffer_size << "!=" << nframes << std::endl;
+        return;
+    }
+
+    _read_audio_data_from_device (input_buffer, nframes);
+    _read_midi_data_from_devices ();
+
+    if (_call_thread_init_callback) {
+        _call_thread_init_callback = false;
+        // COMMENTED DBG LOGS */ std::cout << "\tAudioEngine::thread_init_callback() invoked for " << std::hex << pthread_self() << std::dec << " !" << std::endl;
+        AudioEngine::thread_init_callback (this);
+    }
+
+    engine.process_callback (nframes);
+    
+    _write_audio_data_to_device (output_buffer, nframes);
+    _write_midi_data_to_devices (nframes);
+    
+    uint64_t dsp_end_time_nanos = __get_time_nanos();
+    
+    _dsp_load_accumulator -= *_dsp_load_history.begin();
+    _dsp_load_history.pop_front();
+    uint64_t dsp_load_nanos = dsp_end_time_nanos - dsp_start_time_nanos;
+    _dsp_load_accumulator += dsp_load_nanos;
+    _dsp_load_history.push_back(dsp_load_nanos);
+
+    return;
+}
+
+
+int
+WavesAudioBackend::stop ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::stop ()" << std::endl;
+
+    WTErr wtErr = eNoErr;
+    int retVal = 0;
+
+    // COMMENTED DBG LOGS */ std::cout << "\t[" << _device->DeviceName () << "]" << std::endl;
+
+       if (_device) {
+               wtErr = _device->SetStreaming (false);
+               if (wtErr != eNoErr) {
+                       std::cerr << "WavesAudioBackend::stop (): [" << _device->DeviceName () << "]->SetStreaming () failed!" << std::endl;
+                       retVal = -1;
+               }
+       }
+
+    _midi_device_manager.stop ();
+
+    _unregister_system_audio_ports ();
+    _unregister_system_midi_ports ();
+
+    return retVal;
+}
+
+
+int
+WavesAudioBackend::freewheel (bool start_stop)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::freewheel (" << start_stop << "):" << std::endl;
+
+    if (start_stop != _freewheeling) {
+        if (start_stop == true) {
+            WTErr retval = _device->SetStreaming (false);
+            if (retval != eNoErr) {
+                std::cerr << "WavesAudioBackend::freewheel (): [" << _device->DeviceName () << "]->SetStreaming () failed!" << std::endl;
+                return -1;
+            }
+            _call_thread_init_callback = true;
+            _freewheel_thread ();
+            engine.freewheel_callback (start_stop);
+        }
+        else {
+            _freewheel_thread_active = false; // stop _freewheel_thread ()
+            engine.freewheel_callback (start_stop);
+            _call_thread_init_callback = true;
+            WTErr retval = _device->SetStreaming (true);
+            if (retval != eNoErr) {
+                std::cerr << "WavesAudioBackend::freewheel (): [" << _device->DeviceName () << "]->SetStreaming () failed!" << std::endl;
+                return -1;
+            }
+        }
+        _freewheeling = start_stop;
+    }
+    // already doing what has been asked for
+    return 0;
+}
+
+
+void 
+WavesAudioBackend::_freewheel_thread ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::_freewheel_thread ():" << std::endl;
+    if (!_freewheel_thread_active) { // Lets create it
+        
+        // COMMENTED DBG LOGS */ std::cout << "\tCreating the thread _freewheel_thread () . . ." << std::endl;
+        pthread_attr_t attributes;
+        pthread_t thread_id;
+
+        ThreadData* thread_data = new ThreadData (this, boost::bind (&WavesAudioBackend::_freewheel_thread, this), __thread_stack_size ());
+
+        if (pthread_attr_init (&attributes)) {
+            std::cerr << "WavesAudioBackend::freewheel_thread (): pthread_attr_init () failed!" << std::endl;
+            return;
+        }
+   
+        if (pthread_attr_setstacksize (&attributes, __thread_stack_size ())) {
+            std::cerr << "WavesAudioBackend::freewheel_thread (): pthread_attr_setstacksize () failed!" << std::endl;
+            return;
+        }
+
+        _freewheel_thread_active = false;
+        if ((pthread_create (&thread_id, &attributes, __start_process_thread, thread_data))) {
+            _freewheel_thread_active = true;
+            std::cerr << "WavesAudioBackend::freewheel_thread (): pthread_create () failed!" << std::endl;
+            return;
+        }
+
+        // COMMENTED DBG LOGS */ std::cout << "\t. . . _freewheel_thread () complete." << std::endl;
+        return;
+    }
+    
+    if (_call_thread_init_callback) {
+        _call_thread_init_callback = false;
+        AudioEngine::thread_init_callback (this);
+    }
+
+    while (_freewheel_thread_active) {
+        engine.process_callback (_buffer_size);
+    }
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::_freewheel_thread (): FINISHED" << std::endl;
+    return;
+}
+
+
+float
+WavesAudioBackend::dsp_load () const
+{
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::dsp_load (): " << std::endl;
+
+    if (!_device) {
+        std::cerr << "WavesAudioBackend::cpu_load (): No device is set!" << std::endl;
+        return 0;
+    }
+
+    float average_dsp_load = (float)_dsp_load_accumulator/_dsp_load_history_length;
+    
+    return ( average_dsp_load  / _audio_cycle_period_nanos)*100.0;
+}
+
+
+void
+WavesAudioBackend::_init_dsp_load_history()
+{
+    if((_sample_rate <= 0.0) || (_buffer_size <= 0.0)) {
+        return;
+    }
+    
+    _audio_cycle_period_nanos = ((uint64_t)1000000000L * _buffer_size) / _sample_rate;
+    
+    _dsp_load_accumulator = 0;
+    
+    _dsp_load_history_length = (_sample_rate + _buffer_size - 1) / _buffer_size;
+    // COMMENTED DBG LOGS */ std::cout << "\t\t_dsp_load_history_length = " << _dsp_load_history_length << std::endl;
+    _dsp_load_history = std::list<uint64_t>(_dsp_load_history_length, 0);
+}
+
+
+void
+WavesAudioBackend::transport_start ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::transport_start (): " << std::endl;
+}
+
+
+void
+WavesAudioBackend::transport_stop () 
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::transport_stop (): " << std::endl;
+}
+
+
+TransportState
+WavesAudioBackend::transport_state () const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::transport_state (): " << std::endl;
+    return TransportStopped; 
+}
+
+
+void
+WavesAudioBackend::transport_locate (framepos_t pos)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::transport_locate (" << pos << "): " << std::endl;
+}
+
+
+framepos_t
+WavesAudioBackend::transport_frame () const
+{ 
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::transport_frame (): " << std::endl;
+    return 0; 
+}
+
+
+int
+WavesAudioBackend::set_time_master (bool yn)
+{ 
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_time_master (): " << yn << std::endl;
+    return 0; 
+}
+
+
+int
+WavesAudioBackend::usecs_per_cycle () const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::usecs_per_cycle (): " << std::endl;
+    return (1000000 * _sample_rate) / _buffer_size;
+}
+
+
+size_t
+WavesAudioBackend::raw_buffer_size (DataType data_type)
+{
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::raw_buffer_size (" << data_type.to_string () << "): " << std::endl;
+    switch (data_type) {
+    case DataType::AUDIO:
+            return WavesAudioPort::MAX_BUFFER_SIZE_BYTES;
+        break;
+
+    case DataType::MIDI:
+            return WavesMidiPort::MAX_BUFFER_SIZE_BYTES;
+        break;
+
+        default:
+            std::cerr << "WavesAudioBackend::raw_buffer_size (): unexpected data type (" << (uint32_t)data_type <<")!" << std::endl;
+        break;
+    }
+    return 0;
+}
+
+
+pframes_t
+WavesAudioBackend::sample_time ()
+{
+    // WARNING: This is approximate calculation. Implementation of accurate calculation is pending.
+    // http://kokkinizita.linuxaudio.org/papers/usingdll.pdf
+    
+    return _sample_time_at_cycle_start + ((__get_time_nanos () - _cycle_start_time_nanos)*_sample_rate)/1000000000L;
+}
+
+
+uint64_t
+WavesAudioBackend::__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 Count;
+    QueryPerformanceCounter (&Count);
+    return uint64_t ((Count.QuadPart * 1000000000L / __performance_counter_frequency));
+#endif
+}
+
+
+pframes_t
+WavesAudioBackend::sample_time_at_cycle_start ()
+{
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::sample_time_at_cycle_start (): " << _sample_time_at_cycle_start << std::endl;
+    return _sample_time_at_cycle_start;
+}
+
+
+pframes_t
+WavesAudioBackend::samples_since_cycle_start ()
+{
+    pframes_t diff_sample_time; 
+    diff_sample_time = sample_time () - _sample_time_at_cycle_start;
+    // COMMENTED DBG LOGS */ std::cout << "samples_since_cycle_start: " << diff_sample_time << std::endl;
+
+    return diff_sample_time;
+}
+
+
+bool
+WavesAudioBackend::get_sync_offset (pframes_t& /*offset*/) const
+{ 
+    // COMMENTED DBG LOGS */ std::cout << "get_sync_offset: false" << std::endl;
+
+    return false; 
+}
+
+
+int
+WavesAudioBackend::create_process_thread (boost::function<void ()> func)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::create_process_thread ():" << std::endl;
+    int retVal;
+    pthread_attr_t attributes;
+    size_t stacksize_aligned;
+    pthread_t thread_id;
+
+    // Align stacksize to PTHREAD_STACK_MIN.
+    stacksize_aligned = __thread_stack_size ();
+
+    ThreadData* td = new ThreadData (this, func, stacksize_aligned);
+
+    if ((retVal = pthread_attr_init (&attributes))) {
+        std::cerr << "Cannot set thread attr init res = " << retVal << endmsg;
+        return -1;
+    }
+   
+    if ((retVal = pthread_attr_setstacksize (&attributes, stacksize_aligned))) {
+        std::cerr << "Cannot set thread stack size (" << stacksize_aligned << ") res = " << retVal << endmsg;
+        return -1;
+    }
+
+    if ((retVal = pthread_create (&thread_id, &attributes, __start_process_thread, td))) {
+        std::cerr << "Cannot create thread res = " << retVal << endmsg;
+        return -1;
+    }
+
+    _backend_threads.push_back (thread_id);
+    // COMMENTED DBG LOGS */ std::cout << "\t\t\t. . . thread " << std::hex << thread_id << std::dec << " has been created" << std::endl;
+
+    return 0;
+}
+
+
+void*
+WavesAudioBackend::__start_process_thread (void* arg)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::__start_process_thread ():" << std::endl;
+    ThreadData* td = reinterpret_cast<ThreadData*> (arg);
+    boost::function<void ()> f = td->f;
+    delete td;
+    f ();
+    return 0;
+}
+
+
+int
+WavesAudioBackend::join_process_threads ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::join_process_thread ()" << std::endl;
+    int ret = 0;
+
+    for (std::vector<pthread_t>::const_iterator i = _backend_threads.begin ();
+         i != _backend_threads.end ();
+         ++i) {
+        // COMMENTED DBG LOGS */ std::cout << "\t\t\tstopping thread " << std::hex << *i << std::dec << "...\n";
+
+        void* status;  
+        if (pthread_join (*i, &status) != 0) {
+            std::cerr << "AudioEngine: cannot stop process thread !" << std::endl;
+            ret += -1;
+        }
+        // COMMENTED DBG LOGS */ std::cout << "\t\t\t\t...done" << std::endl;
+    }
+    // COMMENTED DBG LOGS */ std::cout << "\t\t\tall threads finished..." << std::endl;
+    _backend_threads.clear ();
+    // COMMENTED DBG LOGS */ std::cout << "\t\t\tthread list cleared..." << std::endl;
+
+    return ret;
+}
+
+
+bool 
+WavesAudioBackend::in_process_thread ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::in_process_thread ()" << std::endl;
+    for (std::vector<pthread_t>::const_iterator i = _backend_threads.begin ();
+        i != _backend_threads.end (); i++) {
+        if (pthread_equal (*i, pthread_self ()) != 0) {
+            return true;
+        }
+    }
+    return false;
+}
+
+
+size_t
+WavesAudioBackend::__thread_stack_size ()
+{
+    // Align stacksize to PTHREAD_STACK_MIN.
+#if defined (__MACOS__)
+    return (((thread_stack_size () - 1) / PTHREAD_STACK_MIN) + 1) * PTHREAD_STACK_MIN;
+#elif defined (_WINDOWS)
+    return thread_stack_size ();
+#endif
+}
+
+
+uint32_t 
+WavesAudioBackend::process_thread_count ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::process_thread_count (): returns " << _backend_threads.size () << std::endl;
+    return _backend_threads.size ();
+}
+
+
+void
+WavesAudioBackend::_read_audio_data_from_device (const float* input_buffer, pframes_t nframes)
+{
+#if defined(_WINDOWS)
+    const float **buffer = (const float**)input_buffer;
+    size_t copied_bytes = nframes*sizeof(float*);
+
+    for(std::vector<WavesAudioPort*>::iterator it = _physical_audio_inputs.begin ();
+        it != _physical_audio_inputs.end();
+        ++it)
+    {
+        memcpy((*it)->buffer(), *buffer, copied_bytes);
+        ++buffer;
+    }
+#else
+    std::vector<WavesAudioPort*>::iterator it = _physical_audio_inputs.begin ();
+
+    // Well, let's de-interleave here:
+    const Sample* source = input_buffer;
+
+    for (uint32_t chann_cnt = 0; (chann_cnt < _max_input_channels) && (it != _physical_audio_inputs.end ()); ++chann_cnt, ++source, ++it) {
+        const Sample* src = source;
+        Sample* tgt = (*it)->buffer ();
+
+        for (uint32_t frame = 0; frame < nframes; ++frame, src += _max_input_channels, ++tgt) {
+            *tgt = *src;
+        }
+    }
+#endif
+}
+
+void
+WavesAudioBackend::_write_audio_data_to_device (float* output_buffer, pframes_t nframes)
+{
+#if defined(_WnonononoINDOWS)
+    float **buffer = (float**)output_buffer;
+    size_t copied_bytes = nframes*sizeof(float);
+    int i = 0;
+    for(std::vector<WavesAudioPort*>::iterator it = _physical_audio_outputs.begin ();
+        it != _physical_audio_outputs.end();
+        ++it)
+    {
+        memcpy(*buffer, (*it)->buffer(), copied_bytes);
+        //*buffer = (*it)->buffer();
+        buffer++;
+    }
+#else
+    // Well, let's interleave here:
+    std::vector<WavesAudioPort*>::iterator it = _physical_audio_outputs.begin ();
+    Sample* target = output_buffer;
+
+    for (uint32_t chann_cnt = 0;
+         (chann_cnt < _max_output_channels) && (it != _physical_audio_outputs.end ());
+         ++chann_cnt, ++target, ++it) {
+        const Sample* src = (Sample*) ((*it)->get_buffer (nframes));
+        Sample* tgt = target;
+        for (uint32_t frame = 0; frame < nframes; ++frame, tgt += _max_output_channels, ++src) {
+            *tgt = *src;
+        }
+    }
+#endif
+}
+
+
+static boost::shared_ptr<WavesAudioBackend> __instance;
+
+
+boost::shared_ptr<AudioBackend>
+WavesAudioBackend::__waves_backend_factory (AudioEngine& e)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::__waves_backend_factory ():" << std::endl;
+    if (!__instance) {
+        __instance.reset (new WavesAudioBackend (e));
+    }
+    return __instance;
+}
+
+
+#if defined(_WINDOWS)
+
+uint64_t WavesAudioBackend::__performance_counter_frequency;
+
+#endif
+
+int 
+WavesAudioBackend::__instantiate (const std::string& arg1, const std::string& arg2)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::__instantiate ():" << "[" << arg1 << "], [" << arg2 << "]" << std::endl;
+    __instantiated_name = arg1;
+#if defined(_WINDOWS)
+
+       LARGE_INTEGER Frequency;
+       QueryPerformanceFrequency(&Frequency);
+       __performance_counter_frequency = Frequency.QuadPart;
+       std::cout << "__performance_counter_frequency:" << __performance_counter_frequency << std::endl;
+
+#endif
+    return 0;
+}
+
+
+int 
+WavesAudioBackend::__deinstantiate ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::__deinstantiate ():" << std::endl;
+    __instance.reset ();
+    return 0;
+}
+
+
+bool
+WavesAudioBackend::__already_configured ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::__already_configured ():" << std::endl;
+    return false;
+}
+
+
+void*
+WavesAudioBackend::private_handle () const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WHY DO CALL IT: WavesAudioBackend::private_handle: " << std::endl;
+    return NULL;
+}
+
+
+bool
+WavesAudioBackend::available () const
+{
+    // COMMENTED SECONDARY DBG LOGS */// std::cout << "WavesAudioBackend::available: " << std::endl;
+    return true;
+}
+
+
+const std::string&
+WavesAudioBackend::my_name () const
+{
+    // COMMENTED SECONDARY DBG LOGS */// std::cout << "WavesAudioBackend::my_name: " << _port_prefix_name << std::endl;
+    return __instantiated_name;
+}
+
+
+bool
+WavesAudioBackend::can_monitor_input () const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::can_monitor_input: " << std::endl;
+    return false;
+}
+
+std::string WavesAudioBackend::__instantiated_name;
+
+AudioBackendInfo WavesAudioBackend::__backend_info = {
+#ifdef __MACOS__
+    "CoreAudio",
+#elif _WINDOWS
+    "ASIO",
+#endif
+    __instantiate,
+    WavesAudioBackend::__deinstantiate,
+    WavesAudioBackend::__waves_backend_factory,
+    WavesAudioBackend::__already_configured,
+};
+
+#ifdef __MINGW64__
+       extern "C" __declspec(dllexport) ARDOUR::AudioBackendInfo* descriptor ()
+#else
+       extern "C" ARDOURBACKEND_API ARDOUR::AudioBackendInfo* descriptor ()
+#endif
+{
+    // COMMENTED DBG LOGS */ std::cout  << "waves_backend.dll : ARDOUR::AudioBackendInfo* descriptor (): " << std::endl;
+    return &WavesAudioBackend::backend_info ();
+}
index 3a56f7b55ab9a27ba48e327cb18e5c8b484934ee..6fd91913d1d6faff955d2555b03d0a6f8f40f3d8 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014 Waves Audio Ltd.
+    Copyright (C) 2013 Valeriy Kamyshniy
 
     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
@@ -41,7 +41,7 @@
 class ArdourAudioDeviceManager : public WCMRCoreAudioDeviceManager
 {
   public:
-    ArdourAudioDeviceManager (WCMRAudioDeviceManagerClient *client) : WCMRCoreAudioDeviceManager (client, eFullDuplexDevices, true, eCABS_Simple, false) {};
+    ArdourAudioDeviceManager (WCMRAudioDeviceManagerClient *client) : WCMRCoreAudioDeviceManager (client, eAllDevices) {};
 };
 
 #elif defined (_WINDOWS)
@@ -51,7 +51,7 @@ class ArdourAudioDeviceManager : public WCMRCoreAudioDeviceManager
 class ArdourAudioDeviceManager : public WCMRPortAudioDeviceManager
 {
   public:
-    ArdourAudioDeviceManager (WCMRAudioDeviceManagerClient *client) : WCMRPortAudioDeviceManager (client, eFullDuplexDevices, paASIO) {};
+    ArdourAudioDeviceManager (WCMRAudioDeviceManagerClient *client) : WCMRPortAudioDeviceManager (client, eAllDevices) {};
 };
 
 #endif
@@ -103,10 +103,14 @@ class WavesMidiPort;
 
     virtual int set_device_name (const std::string& name);
 
+       virtual int drop_device();
+
     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);
@@ -123,6 +127,8 @@ class WavesMidiPort;
     
     virtual uint32_t buffer_size () const;
     
+    virtual SampleFormat sample_format () const;
+    
     virtual bool interleaved () const;
     
     virtual uint32_t input_channels () const;
@@ -275,6 +281,7 @@ class WavesMidiPort;
     WavesMidiDeviceManager _midi_device_manager;
 
     WCMRAudioDevice *_device;
+    SampleFormat _sample_format;
     bool _interleaved;
     static std::string __instantiated_name;
     uint32_t _input_channels;
@@ -317,8 +324,15 @@ class WavesMidiPort;
                                  pframes_t sample_time,
                                  uint64_t cycle_start_time_nanos);
 
+       int _reset_device (uint32_t buffer_size, float sample_rate);
     void _changed_midi_devices ();
 
+       // DO change sample rate and buffer size
+       int _buffer_size_change(uint32_t new_buffer_size);
+       int _sample_rate_change(float new_sample_rate);
+    
+    int _device_list_change();
+    
     int _register_system_audio_ports ();
     int _register_system_midi_ports ();
 
index c0d2fcd3159319d01dcdac6372d703bc11e886d4..e1869cbf1fb7accda79f6aa8ddf38ea96b12d82e 100644 (file)
@@ -1,90 +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
+/*
+    Copyright (C) 2013 Valeriy Kamyshniy
+
+    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_dataport.h"
+#include "waves_audiobackend.h"
+
+using namespace ARDOUR;
+
+
+int 
+WavesAudioBackend::set_systemic_input_latency (uint32_t systemic_input_latency)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_systemic_input_latency (): " << systemic_input_latency << std::endl;
+
+    _systemic_input_latency = systemic_input_latency;
+    return 0;
+}
+
+
+int 
+WavesAudioBackend::set_systemic_output_latency (uint32_t systemic_output_latency)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_systemic_output_latency (): " << systemic_output_latency << std::endl;
+
+    _systemic_output_latency = systemic_output_latency;
+    return 0;
+}
+
+uint32_t     
+WavesAudioBackend::systemic_input_latency () const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::systemic_input_latency ()" << std::endl;
+
+    return _systemic_input_latency;
+}
+
+
+uint32_t     
+WavesAudioBackend::systemic_output_latency () const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::systemic_output_latency ()" << std::endl;
+
+    return _systemic_output_latency;
+}
+
+
+void
+WavesAudioBackend::update_latencies ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "update_latencies:" << std::endl;
+}
+
+
+void
+WavesAudioBackend::set_latency_range (PortHandle port_handle, bool for_playback, LatencyRange latency_range)
+{
+    if (!_registered (port_handle)) {
+        std::cerr << "WavesAudioBackend::set_latency_range (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
+        return;
+    }
+    ((WavesDataPort*)port_handle)->set_latency_range (latency_range, for_playback);
+}
+
+
+LatencyRange
+WavesAudioBackend::get_latency_range (PortHandle port_handle, bool for_playback)
+{
+    if (!_registered (port_handle)) {
+        std::cerr << "WavesAudioBackend::get_latency_range (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
+        LatencyRange lr = {0,0};
+        return lr;
+    }   
+    return ((WavesDataPort*)port_handle)->latency_range (for_playback);
+}
index 94c674d073728ee16cd8f75e5bab1f9a8f11f144..13019b9a99a582ef5415b7d2f81174e2b88cd671 100644 (file)
-/*\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
+/*
+    Copyright (C) 2013 Valeriy Kamyshniy
+
+    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 <boost/assign/list_of.hpp>
+
+#include "waves_audiobackend.h"
+#include "waves_midiport.h"
+#include "waves_midi_event.h"
+#include "waves_midi_buffer.h"
+
+using namespace ARDOUR;
+
+#ifdef __MACOS__
+
+const std::vector<std::string> WavesAudioBackend::__available_midi_options = boost::assign::list_of ("None") ("CoreMIDI");
+
+#elif _WINDOWS
+
+const std::vector<std::string> WavesAudioBackend::__available_midi_options = boost::assign::list_of ("None") ("Multimedia Extensions");
+
+#endif
+
+
+std::vector<std::string> 
+WavesAudioBackend::enumerate_midi_options () const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::enumerate_midi_options ()" << std::endl;
+    return __available_midi_options;
+}
+
+
+int 
+WavesAudioBackend::set_midi_option (const std::string& option)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_midi_option ( " << option << " )" << std::endl;
+    if (option == __available_midi_options[0]) {
+        _use_midi = false;
+        // COMMENTED DBG LOGS */ std::cout << "\tNO MIDI system used)" << std::endl;
+    }
+    else if (option == __available_midi_options[1]) {
+        _use_midi = true;
+        // COMMENTED DBG LOGS */ std::cout << "\tNO MIDI system used)" << std::endl;
+    }
+    else {
+        std::cerr << "WavesAudioBackend::set_midi_option (): Invalid MIDI option!" << std::endl;
+        return -1;
+    }
+
+    return 0;
+}
+
+
+std::string
+WavesAudioBackend::midi_option () const
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::midi_option ():" << std::endl;
+    return * (__available_midi_options.begin () + (_use_midi?1:0));
+}
+
+
+int
+WavesAudioBackend::midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buffer, void* port_buffer, uint32_t event_index)
+{
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::midi_event_get ():" << std::endl;
+
+    if (buffer == NULL) {
+        std::cerr << "WavesAudioBackend::midi_event_get () : NULL in the 'buffer' argument!\n";
+        return -1;
+    }
+
+    if (port_buffer == NULL) {
+        std::cerr << "WavesAudioBackend::midi_event_get () : NULL in the 'port_buffer' argument!\n";
+        return -1;
+    }
+
+    WavesMidiBuffer& source = * (WavesMidiBuffer*)port_buffer;
+
+    if (event_index >= source.size ()) {
+        std::cerr << "WavesAudioBackend::midi_event_get () : 'event_index' is out of the number of events stored in 'port_buffer'!\n";
+        return -1;
+    }
+
+    WavesMidiEvent* waves_midi_event = source[event_index];
+
+    timestamp = waves_midi_event->timestamp ();
+    size = waves_midi_event->size ();
+    *buffer = waves_midi_event->data ();
+
+    return 0;
+}
+
+
+int
+WavesAudioBackend::midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size)
+{
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::midi_event_put ():" << std::endl;
+    if (buffer == NULL) {
+        std::cerr << "WavesAudioBackend::midi_event_put () : NULL in the 'buffer' argument!\n";
+        return -1;
+    }
+
+    if (port_buffer == NULL) {
+        std::cerr << "WavesAudioBackend::midi_event_put () : NULL in the 'port_buffer' argument!\n";
+        return -1;
+    }
+
+    WavesMidiBuffer& target = * (WavesMidiBuffer*)port_buffer;
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "\t [" << target.name () << "]"<< std::endl;
+
+    if (target.size () && (pframes_t)target.back ()->timestamp () > timestamp) {
+        std::cerr << "WavesAudioBackend::midi_event_put (): The MIDI Event to put is a bit late!" << std::endl;
+        std::cerr << "\tprev timestamp is " << (pframes_t)target.back ()->timestamp () << " as the current one is " << timestamp << std::endl;
+        return -1;
+    }
+
+    target.push_back (new WavesMidiEvent (timestamp, buffer, size));
+    return 0;
+}
+
+
+uint32_t
+WavesAudioBackend::get_midi_event_count (void* port_buffer)
+{
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::get_midi_event_count (): " << std::endl;
+    
+    if (port_buffer == NULL) {
+        std::cerr << "WavesAudioBackend::get_midi_event_count () : NULL in the 'port_buffer' argument!\n";
+        return -1;
+    }
+
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "\tcount = " << (* (WavesMidiBuffer*)port_buffer).size () << std::endl;
+
+    return (* (WavesMidiBuffer*)port_buffer).size ();
+}
+
+
+void
+WavesAudioBackend::midi_clear (void* port_buffer)
+{
+    // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::midi_clear (): " << std::endl;
+    if (port_buffer == NULL) {
+        std::cerr << "WavesAudioBackend::midi_clear () : NULL in the 'port_buffer' argument!\n";
+        return;
+    }
+
+    (* (WavesMidiBuffer*)port_buffer).clear ();
+}
+
+
+void
+WavesAudioBackend::_changed_midi_devices ()
+{
+    if (_midi_device_manager.stream (false)) {
+        std::cerr << "WavesAudioBackend::_changed_midi_devices (): _midi_device_manager.stream (false) failed!" << std::endl;
+        return;
+    }
+
+    _midi_device_manager.stop ();
+
+    if (_midi_device_manager.start () != 0) {
+        std::cerr << "WavesAudioBackend::_changed_midi_devices (): _midi_device_manager.start () failed!" << std::endl;
+        return;
+    }
+
+    if (_register_system_midi_ports () != 0) {
+        std::cerr << "WavesAudioBackend::_changed_midi_devices (): _register_system_midi_ports () failed!" << std::endl;
+        return;
+    }
+    
+    manager.registration_callback ();
+
+    if (_midi_device_manager.stream (true)) {
+        std::cerr << "WavesAudioBackend::_changed_midi_devices (): _midi_device_manager.stream (true) failed!" << std::endl;
+        return;
+    }
+}
+
+
+void
+WavesAudioBackend::_unregister_system_midi_ports ()
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::_unregister_system_midi_ports ()" << std::endl;
+    std::vector<WavesMidiPort*> physical_midi_ports = _physical_midi_inputs;
+    physical_midi_ports.insert (physical_midi_ports.begin (), _physical_midi_outputs.begin (), _physical_midi_outputs.end ());
+
+    for (std::vector<WavesMidiPort*>::const_iterator it = physical_midi_ports.begin (); it != physical_midi_ports.end (); ++it) {
+        std::vector<WavesDataPort*>::iterator port_iterator = std::find (_ports.begin (), _ports.end (), *it);
+        if (port_iterator == _ports.end ()) {
+            std::cerr << "WavesAudioBackend::_unregister_system_midi_ports (): Failed to find port [" << (*it)->name () << "]!"  << std::endl;
+        }
+        else
+            _ports.erase (port_iterator);
+        delete *it;
+    }
+    _physical_midi_inputs.clear ();
+    _physical_midi_outputs.clear ();
+}
+
+
+int
+WavesAudioBackend::_register_system_midi_ports ()
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::_register_system_midi_ports ()" << std::endl;
+
+    LatencyRange lr = {0,0};
+    lr.min = lr.max = _buffer_size;
+
+    for (size_t i = 0; i<_ports.size ();)    {
+        WavesMidiPort* midi_port = dynamic_cast<WavesMidiPort*> (_ports[i]);
+        if (!midi_port || !midi_port->is_physical () || !midi_port->is_terminal ()) {
+            ++i;
+            continue;
+        }
+
+        if ((midi_port->is_input () && !midi_port->midi_device ()->is_output ()) ||
+            (midi_port->is_output () && !midi_port->midi_device ()->is_input ())) {
+            disconnect_all (midi_port);
+            unregister_port (midi_port);
+            continue; // to be here for further additions in the end of this loop
+        }
+
+        ++i;
+    }
+
+    const std::vector<WavesMidiDevice *>&  devices = _midi_device_manager.devices ();
+
+    for (std::vector<WavesMidiDevice*>::const_iterator it = devices.begin (); it != devices.end (); ++it) {
+        if ((*it)->is_input ()) {
+            std::string port_name = "system_midi:" + (*it)->name () + " capture";
+            WavesDataPort* port = _find_port (port_name);
+            WavesMidiPort* midi_port = dynamic_cast<WavesMidiPort*> (port);
+            if (midi_port && (midi_port->type () != DataType::MIDI || 
+                midi_port->midi_device () != *it || 
+                !midi_port->is_output () || 
+                !midi_port->is_physical () ||
+                !midi_port->is_terminal ())) {
+                std::cerr << "WavesAudioBackend::_register_system_midi_ports (): the port [" << midi_port->name () << "] is inconsystently constructed!" << std::endl;
+                disconnect_all (midi_port);
+                unregister_port (midi_port);
+                port = NULL;
+            }
+
+            if (port == NULL) {
+                port = _register_port ( port_name, DataType::MIDI , static_cast<ARDOUR::PortFlags> (IsOutput | IsPhysical | IsTerminal));
+                if (port == NULL) {
+                    return -1;
+                }
+                ((WavesMidiPort*)port)->set_midi_device (*it);
+            }
+            port->set_latency_range (lr, false); 
+        }
+
+        if ((*it)->is_output ()) {
+            std::string port_name = "system_midi:" + (*it)->name () + " playback";
+            WavesDataPort* port = _find_port (port_name);
+            WavesMidiPort* midi_port = dynamic_cast<WavesMidiPort*> (port);
+            if (midi_port && (midi_port->type () != DataType::MIDI || 
+                midi_port->midi_device () != *it || 
+                !midi_port->is_input () || 
+                !midi_port->is_physical () ||
+                !midi_port->is_terminal ())) {
+                std::cerr << "WavesAudioBackend::_register_system_midi_ports (): the port [" << midi_port->name () << "] is inconsystently constructed!" << std::endl;
+                disconnect_all (midi_port);
+                unregister_port (midi_port);
+            }
+
+            if (port == NULL) {
+                port = _register_port (port_name,
+                                       DataType::MIDI,
+                                       static_cast<ARDOUR::PortFlags> (IsInput | IsPhysical | IsTerminal));
+                if (port == NULL) {
+                    return -1;
+                }
+            }
+
+            ((WavesMidiPort*)port)->set_midi_device ((*it));
+            port->set_latency_range (lr, true);
+        }
+    }
+    
+    return 0;
+}
+
+
+int
+WavesAudioBackend::_read_midi_data_from_devices ()
+{
+    // COMMENTED FREQUENT DBG LOGS */ std::cout  << "WavesAudioBackend::_read_midi_data_from_devices ():" << std::endl;
+    if (!_midi_device_manager.is_streaming ())
+        return 0;
+    
+    _midi_device_manager.do_read ();
+
+    for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_inputs.begin (); it != _physical_midi_inputs.end (); ++it) {
+        WavesMidiDevice* midi_device = (*it)->midi_device ();
+        
+        WavesMidiBuffer& waves_midi_buffer = (*it)->buffer ();
+        waves_midi_buffer.clear ();
+        
+        while (WavesMidiEvent *waves_midi_event = midi_device->dequeue_input_waves_midi_event ()) {
+            int32_t timestamp_st = _buffer_size - (_sample_time_at_cycle_start - waves_midi_event->timestamp ());
+            
+            if (timestamp_st < 0) {
+                timestamp_st = 0;
+            }
+            else if (timestamp_st >= (int32_t)_buffer_size) {
+                timestamp_st = _buffer_size - 1;
+            }
+            waves_midi_event->set_timestamp (timestamp_st);
+            waves_midi_buffer.push_back (waves_midi_event);
+        }
+    }
+    return 0;
+}
+
+
+int
+WavesAudioBackend::_write_midi_data_to_devices (pframes_t nframes)
+{
+    if (!_midi_device_manager.is_streaming ())
+        return 0;
+    
+    for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_outputs.begin (); it != _physical_midi_outputs.end (); ++it) {
+        WavesMidiDevice* midi_device = (*it)->midi_device (); 
+        WavesMidiBuffer &waves_midi_buffer = * (WavesMidiBuffer*) (*it)->get_buffer (nframes);
+
+        for (WavesMidiBufferIterator it = waves_midi_buffer.begin (); it != waves_midi_buffer.end ();) {
+             WavesMidiEvent* waves_midi_event = *it;
+            
+            waves_midi_buffer.erase (it);
+            
+            waves_midi_event->set_timestamp (_sample_time_at_cycle_start + waves_midi_event->timestamp () + nframes);
+            midi_device->enqueue_output_waves_midi_event (waves_midi_event);
+       }
+    }
+    _midi_device_manager.do_write ();
+    return 0;
+}
index 6225468864ac307e13ef5a2bffa56bb23ffc44da..f798ff4c14e1536369be043a7d66c8bf930fef9c 100644 (file)
-/*\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
+/*
+    Copyright (C) 2013 Valeriy Kamyshniy
+
+    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_audiobackend.h"
+#include "waves_audioport.h"
+#include "waves_midiport.h"
+#include "waves_midi_event.h"
+
+using namespace ARDOUR;
+
+uint32_t
+WavesAudioBackend::port_name_size () const
+{
+    return 256+64;
+}
+
+int
+WavesAudioBackend::set_port_name (PortHandle port_handle, const std::string& port_name)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::set_port_name (): [" << std::hex << port_handle << std::dec << "], [" << port_name << "]" << std::endl;
+    
+    if (!_registered (port_handle)) {
+        std::cerr << "WavesAudioBackend::set_port_name (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
+        return -1;
+    }
+
+    return ((WavesAudioPort*)port_handle)->set_name (__instantiated_name + ":" + port_name);
+}
+
+
+std::string
+WavesAudioBackend::get_port_name (PortHandle port_handle) const
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::get_port_name (): [" << std::hex << port_handle << std::dec << "]" << std::endl;
+    if (!_registered (port_handle)) {
+        std::cerr << "WavesAudioBackend::get_port_name (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
+        return std::string ();
+    }
+    // COMMENTED DBG LOGS */ else std::cout  << "\t[" << ((WavesAudioPort*)port_handle)->name () << "]" << std::endl;
+
+    return ((WavesAudioPort*)port_handle)->name ();
+}
+
+
+PortEngine::PortHandle
+WavesAudioBackend::get_port_by_name (const std::string& port_name) const
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::get_port_by_name (): [" << port_name << "]" << std::endl;
+
+    PortHandle port_handle = (PortHandle)_find_port (port_name);
+    if (!port_handle) {
+        std::cerr << "WavesAudioBackend::get_port_by_name (): Failed to find port [" << port_name << "]!" << std::endl;
+    }
+
+    return port_handle;
+}
+
+
+WavesDataPort* 
+WavesAudioBackend::_find_port (const std::string& port_name) const
+{
+    for (std::vector<WavesDataPort*>::const_iterator it = _ports.begin (); it != _ports.end (); ++it) {
+        if ((*it)->name () == port_name) {
+            return *it;
+        }
+    }
+
+    return NULL;
+}
+
+
+int
+WavesAudioBackend::get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>& port_names) const
+{
+  
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::get_ports (): \n\tPattern: [" << port_name_pattern << "]\n\tType: " << type << "\n\tFlags: " << flags << endl;
+    
+    unsigned found_ports =0;
+    
+    for (size_t i = 0; i < _ports.size (); ++i) {
+        WavesDataPort* port = _ports[i];
+        
+        if ((port->type () == type) && (port->flags () & flags)) {
+            port_names.push_back (port->name ());
+            found_ports++;
+        }
+    }
+    return found_ports;
+}
+
+
+DataType
+WavesAudioBackend::port_data_type (PortHandle port_handle) const
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::port_data_type" << std::endl;
+
+    if (!_registered (port_handle)) {
+        std::cerr << "WavesAudioBackend::port_data_type (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
+        return DataType::NIL;
+    }
+    
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::port_data_type: " << endl;
+    
+    return ((WavesAudioPort*)port_handle)->type ();
+}
+
+
+PortEngine::PortHandle
+WavesAudioBackend::register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::register_port (): " << type.to_string () << " [" << shortname << "]" << std::endl;
+
+    if (shortname.size () == 0) {
+        std::cerr << "WavesAudioBackend::register_port (): Invalid (empty) port name!" << std::endl;
+        return NULL;
+    }
+
+    if (flags & IsPhysical) {
+        std::cerr << "WavesAudioBackend::register_port (): Unexpected attribute for port [" << shortname << "]! The port must not be physical!";
+        return NULL;
+    }
+
+    return (PortEngine::PortHandle)_register_port (__instantiated_name + ":" + shortname, type, flags);
+}
+
+
+WavesDataPort*
+WavesAudioBackend::_register_port (const std::string& port_name, ARDOUR::DataType type, ARDOUR::PortFlags flags)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::_register_port (): [" << port_name << "]" << std::endl;
+
+    if (_find_port (port_name) != NULL) {
+        std::cerr << "WavesAudioBackend::register_port () : Port [" << port_name << "] is already registered!" << std::endl;
+        return NULL;
+    }
+
+    WavesDataPort* port = NULL;
+    switch (type) {
+        case ARDOUR::DataType::AUDIO: {
+            WavesAudioPort* audio_port = new WavesAudioPort (port_name, flags);
+            if (flags & IsPhysical)
+            {
+                if (flags & IsOutput)
+                {
+                    _physical_audio_inputs.push_back (audio_port);
+                    // COMMENTED DBG LOGS */ std::cout  << "\t\t" << port_name << " added to physical AUDIO Inputs !" << std::endl;
+                }
+                else if (flags & IsInput)
+                {
+                    _physical_audio_outputs.push_back (audio_port);
+                    // COMMENTED DBG LOGS */ std::cout  << "\t\t" << port_name << " added to physical AUDIO Outputs !" << std::endl;
+                }
+            }
+            port = audio_port;
+        } break;
+        case ARDOUR::DataType::MIDI: {
+            WavesMidiPort* midi_port = new WavesMidiPort (port_name, flags);
+            if (flags & IsPhysical)
+            {
+                if (flags & IsOutput)
+                {
+                    _physical_midi_inputs.push_back (midi_port);
+                    // COMMENTED DBG LOGS */ std::cout  << "\t\t" << port_name << " added to physical MIDI Inputs !" << std::endl;
+                }
+                else if (flags & IsInput)
+                {
+                    _physical_midi_outputs.push_back (midi_port);
+                    // COMMENTED DBG LOGS */ std::cout  << "\t\t" << port_name << " added to physical MIDI Outputs !" << std::endl;
+                }
+            }
+            port = midi_port;
+        } break;
+        default:
+            std::cerr << "WavesAudioBackend::register_port () : Invalid data type (" << (uint32_t)type << ") applied to port [" << port_name << "]!" << std::endl;
+        return NULL;
+    }
+    
+    _ports.push_back (port);
+
+    return port;
+}
+
+
+void
+WavesAudioBackend::unregister_port (PortHandle port_handle)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::unregister_port ():" << std::hex << port_handle << std::dec << std::endl;
+
+    // so far we suppose all disconnections will be done prior to unregistering.
+    WavesDataPort* port = (WavesDataPort*)port_handle;
+    std::vector<WavesDataPort*>::iterator port_iterator = std::find (_ports.begin (), _ports.end (), (WavesDataPort*)port_handle);
+    if (port_iterator == _ports.end ()) {
+        std::cerr << "WavesAudioBackend::unregister_port (): Failed to find port [" << std::hex << port_handle << std::dec << "]!"  << std::endl;
+        return;
+    }
+    // COMMENTED DBG LOGS */ std::cout  << "\t[" << ((WavesDataPort*)port_handle)->name () << "]" << std::endl;
+
+    _ports.erase (port_iterator);
+
+    if (port->is_physical ()) {
+        if (port->is_output ()) {
+            switch (port->type ()) {
+                case ARDOUR::DataType::AUDIO: {
+                    std::vector<WavesAudioPort*>::iterator audio_port_iterator = std::find (_physical_audio_inputs.begin (), _physical_audio_inputs.end (), port);
+                    if (audio_port_iterator == _physical_audio_inputs.end ())    {
+                        std::cerr << "WavesAudioBackend::unregister_port (): Failed to find port [" << port->name () << "] in the list of registered physical audio inputs!" << std::endl;
+                        return;
+                    }
+                    _physical_audio_inputs.erase (audio_port_iterator);
+                }
+                break;
+                case ARDOUR::DataType::MIDI: {
+                    std::vector<WavesMidiPort*>::iterator midi_port_iterator = std::find (_physical_midi_inputs.begin (), _physical_midi_inputs.end (), port);
+                    if (midi_port_iterator == _physical_midi_inputs.end ()) {
+                        std::cerr << "WavesAudioBackend::unregister_port (): Failed to find port [" << port->name () << "] in the list of registered physical midi inputs!" << std::endl;
+                        return;
+                    }
+                    _physical_midi_inputs.erase (midi_port_iterator);
+                }
+                break;
+                default:
+                    std::cerr << "WavesAudioBackend::unregister_port (): Invalid type (" << port->type () << " applied to [" << port->name () << "]!" << std::endl;
+                break;
+            }
+        }
+        else if (port->flags () & IsInput) {
+            switch (port->type ()) {
+                case ARDOUR::DataType::AUDIO: {
+                    std::vector<WavesAudioPort*>::iterator audio_port_iterator = std::find (_physical_audio_outputs.begin (), _physical_audio_outputs.end (), port);
+                    if (audio_port_iterator == _physical_audio_outputs.end ())
+                    {
+                        std::cerr << "WavesAudioBackend::unregister_port: Failed to find port [" << port->name () << std::dec << "] in the list of registered physical audio outputs!\n";
+                        return;
+                    }
+                    _physical_audio_outputs.erase (audio_port_iterator);
+                }
+                break;
+                case ARDOUR::DataType::MIDI: {
+
+                    std::vector<WavesMidiPort*>::iterator midi_port_iterator = std::find (_physical_midi_outputs.begin (), _physical_midi_outputs.end (), port);
+                    if (midi_port_iterator == _physical_midi_outputs.end ())
+                    {
+                        std::cerr << "WavesAudioBackend::unregister_port: Failed to find port [" << port->name () << std::dec << "] in the list of registered physical midi outputs!\n";
+                        return;
+                    }
+                    _physical_midi_outputs.erase (midi_port_iterator);
+                }
+                break;
+                default:
+                    std::cerr << "WavesAudioBackend::unregister_port (): Invalid type (" << port->type () << " applied to [" << port->name () << "]!" << std::endl;
+                break;
+            }
+        }
+    }
+
+    delete port;
+}
+
+
+int
+WavesAudioBackend::connect (const std::string& src_port_name, const std::string& dst_port_name)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::connect (" << src_port_name << ", " << dst_port_name << "):" << std::endl;
+
+    WavesDataPort* src_port = _find_port (src_port_name);
+    if (src_port == NULL) {
+        std::cerr << "WavesAudioBackend::connect: Failed to find source port " << src_port_name << " !" << std::endl;
+        return -1;
+    }
+    
+    WavesDataPort* dst_port = _find_port (dst_port_name);
+    if (dst_port == NULL) {
+        std::cerr << "WavesAudioBackend::connect: Failed to find destination port " << dst_port_name << " !" << std::endl;
+        return -1;
+    }
+
+    // COMMENTED DBG LOGS */ std::cout  << "\t\t (" << src_port << ", " << dst_port << "):" << std::endl;
+    return src_port->connect (dst_port);
+}
+
+
+int
+WavesAudioBackend::connect (PortHandle src_port_handle, const std::string& dst_port_name)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::connect ():" << std::endl;
+    if (!_registered (src_port_handle)) {
+        std::cerr << "WavesAudioBackend::connect: Failed to find source port [" << std::hex << src_port_handle << std::dec << "]!" << std::endl;
+        return -1;
+    }
+
+    // COMMENTED DBG LOGS */ std::cout  << "\t[" << std::hex << src_port_handle << std::dec << "]" << std::endl;
+    // COMMENTED DBG LOGS */ std::cout  << "\t[" << dst_port_name << "]" << std::endl;
+
+    WavesDataPort* dst_port = _find_port (dst_port_name);
+    if (dst_port == NULL) {
+        std::cerr << "WavesAudioBackend::connect (): Failed to find destination port [" << dst_port_name << "]!" << std::endl;
+        return -1;
+    }
+
+    return ((WavesDataPort*)src_port_handle)->connect (dst_port);
+}
+
+
+int
+WavesAudioBackend::disconnect (PortHandle src_port_handle, const std::string& dst_port_name)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::disconnect (" << src_port_handle << ", " << dst_port_name << "):" << std::endl;
+    if (!_registered (src_port_handle)) {
+        std::cerr << "WavesAudioBackend::disconnect (): Failed to find source port [" << std::hex << src_port_handle << std::dec << "]!" << std::endl;
+        return -1;
+    }
+    
+    // COMMENTED DBG LOGS */ std::cout  << "\t[" << std::hex << src_port_handle << std::dec << "]" << std::endl;
+    // COMMENTED DBG LOGS */ std::cout  << "\t[" << dst_port_name << "]" << std::endl;
+
+    WavesDataPort* dst_port = _find_port (dst_port_name);
+    if (dst_port == NULL) {
+        std::cerr << "WavesAudioBackend::disconnect (): Failed to find destination port [" << dst_port_name << "]!" << std::endl;
+        return -1;
+    }
+
+    return ((WavesDataPort*)src_port_handle)->disconnect (dst_port);
+}
+
+
+int
+WavesAudioBackend::disconnect_all (PortHandle port_handle)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::disconnect_all ():" << std::endl;
+    if (!_registered (port_handle)) {
+        std::cerr << "WavesAudioBackend::disconnect_all : Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
+        return -1;
+    }
+
+ ((WavesDataPort*)port_handle)->disconnect_all ();
+
+    return 0;
+}
+
+
+int
+WavesAudioBackend::disconnect (const std::string& src_port_name, const std::string& dst_port_name)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::disconnect (" << src_port_name << ", " << dst_port_name << "):" << std::endl;
+
+    WavesDataPort* src_port = _find_port (src_port_name);
+    if (src_port == NULL) {
+        std::cerr << "WavesAudioBackend::disconnect : Failed to find source port!\n";
+        return -1;
+    }
+    
+    WavesDataPort* dst_port = _find_port (dst_port_name);
+    if (dst_port == NULL) {
+        std::cerr << "WavesAudioBackend::disconnect : Failed to find destination port!\n";
+        return -1;
+    }
+
+    return dst_port->disconnect (src_port);
+}
+
+
+bool
+WavesAudioBackend::connected (PortHandle port_handle, bool process_callback_safe)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::connected ():" << std::endl;
+    if (!_registered (port_handle)) {
+        std::cerr << "WavesAudioBackend::connected (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
+        return false;
+    }
+    
+    return ((WavesDataPort*)port_handle)->is_connected ();
+}
+
+
+bool
+WavesAudioBackend::connected_to (PortHandle src_port_handle, const std::string& dst_port_name, bool process_callback_safe)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::connected_to (" << src_port_handle << ", " << dst_port_name << ")" << std::endl;
+
+    if (!_registered (src_port_handle)) {
+        std::cerr << "WavesAudioBackend::connected_to : Failed to find source port!" << std::endl;
+        return false;
+    }
+
+    WavesDataPort* dst_port = _find_port (dst_port_name);
+    if (dst_port == NULL) {
+        std::cerr << "WavesAudioBackend::connected_to : Failed to find destination port!" << std::endl;
+        return -1;
+    }
+    // COMMENTED DBG LOGS */ std::cout  << "\t return " << ((((WavesDataPort*)src_port_handle)->is_connected (dst_port)) ? "YES":"NO") << ", " << dst_port_name << ")" << std::endl;
+    return ((WavesDataPort*)src_port_handle)->is_connected (dst_port);
+}
+
+
+bool
+WavesAudioBackend::physically_connected (PortHandle port_handle, bool process_callback_safe)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::physically_connected ():" << std::endl;
+
+    if (!_registered (port_handle)) {
+        std::cerr << "WavesAudioBackend::physically_connected (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
+        return false;
+    }
+
+    return ((WavesDataPort*)port_handle)->is_physically_connected ();
+}
+
+
+int
+WavesAudioBackend::get_connections (PortHandle port_handle, std::vector<std::string>& names, bool process_callback_safe)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::get_connections ()" << std::endl;
+    
+    if (!_registered (port_handle)) {
+        std::cerr << "WavesAudioBackend::get_connections (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
+        return -1;
+    }
+
+    if (names.size ()) {
+        std::cerr << "WavesAudioBackend::get_connections () : Parameter 'names' is not empty!\n";
+        return -1;
+    }
+    const std::vector<WavesDataPort*>& connected_ports = ((WavesDataPort*)port_handle)->get_connections ();
+
+    for (std::vector<WavesDataPort*>::const_iterator it = connected_ports.begin (); it != connected_ports.end (); ++it) {
+        names.push_back ((*it)->name ());
+    }
+
+    return (int)names.size ();
+}
+
+
+int
+WavesAudioBackend::request_input_monitoring (PortHandle, bool)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::request_input_monitoring: " << std::endl;
+    return 0;
+}
+
+
+int
+WavesAudioBackend::ensure_input_monitoring (PortHandle, bool)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::ensure_input_monitoring: " << std::endl;
+    return 0;
+}
+
+
+bool
+WavesAudioBackend::monitoring_input (PortHandle)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::monitoring_input: " << std::endl;
+    return false;
+}
+
+
+bool
+WavesAudioBackend::port_is_physical (PortHandle port_handle) const
+{
+    
+    if (!_registered (port_handle)) {
+        std::cerr << "WavesAudioBackend::port_is_physical (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
+        return -1;
+    }
+    
+    return (((WavesAudioPort*)port_handle)->flags () & IsPhysical) != 0;
+}
+
+
+void
+WavesAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>& names)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::get_physical_outputs ():" << std::endl << "\tdatatype = " << type << std::endl;
+
+    switch (type) {
+        case ARDOUR::DataType::AUDIO: {
+            for (std::vector<WavesAudioPort*>::iterator it = _physical_audio_outputs.begin (); it != _physical_audio_outputs.end (); ++it) {
+                // COMMENTED DBG LOGS */ std::cout  << "\t" << (*it)->name () << std::endl;
+                names.push_back ((*it)->name ());
+            }
+        } break;
+        case ARDOUR::DataType::MIDI: {
+            for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_outputs.begin (); it != _physical_midi_outputs.end (); ++it) {
+                // COMMENTED DBG LOGS */ std::cout  << "\t" << (*it)->name () << std::endl;
+                names.push_back ((*it)->name ());
+            }
+        } break;
+        default:
+            break;
+    }
+}
+
+
+void
+WavesAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>& names)
+{
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::get_physical_inputs ():" << std::endl << "\tdatatype = " << type << std::endl;
+    switch (type) {
+        case ARDOUR::DataType::AUDIO: {
+            for (std::vector<WavesAudioPort*>::iterator it = _physical_audio_inputs.begin (); it != _physical_audio_inputs.end (); ++it) {
+                // COMMENTED DBG LOGS */ std::cout  << "\t" << (*it)->name () << std::endl;
+                names.push_back ((*it)->name ());
+            }
+        } break;
+        case ARDOUR::DataType::MIDI: {
+            for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_inputs.begin (); it != _physical_midi_inputs.end (); ++it) {
+                // COMMENTED DBG LOGS */ std::cout  << "\t" << (*it)->name () << std::endl;
+                names.push_back ((*it)->name ());
+            }
+        } break;
+        default:
+        break;
+    }
+}
+
+
+ChanCount
+WavesAudioBackend::n_physical_outputs () const
+{
+    ChanCount chan_count;
+    chan_count.set (DataType::AUDIO, _physical_audio_outputs.size ());
+    chan_count.set (DataType::MIDI, _physical_midi_outputs.size ());
+
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::n_physical_outputs ():" << std::endl << "\ttotal = " << chan_count.n_total () << std::endl;
+
+    return chan_count;
+}
+
+
+ChanCount
+WavesAudioBackend::n_physical_inputs () const
+{
+    ChanCount chan_count;
+    chan_count.set (DataType::AUDIO, _physical_audio_inputs.size ());
+    chan_count.set (DataType::MIDI, _physical_midi_inputs.size ());
+
+    // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::n_physical_outputs ():" << std::endl << "\ttotal = " << chan_count.n_total () << std::endl;
+
+    return chan_count;
+}
+
+
+void*
+WavesAudioBackend::get_buffer (PortHandle port_handle, pframes_t nframes)
+{
+    // Here we would check if the port is registered. However, we will not do it as
+    // it's relatively VERY SLOW operation. So let's count on consistency
+    // of the caller as get_buffer normally is called hundreds of "kilotimes" per second.
+
+    if (port_handle == NULL) {
+        std::cerr << "WavesAudioBackend::get_buffer : Invalid port handler <NULL>!" << std::endl;
+        return NULL;
+    }  
+    
+    return ((WavesAudioPort*)port_handle)->get_buffer (nframes);
+}
+
+
+int
+WavesAudioBackend::_register_system_audio_ports ()
+{
+    if (!_device) {
+        std::cerr << "WavesAudioBackend::_register_system_audio_ports (): No device is set!" << std::endl;
+        return -1;
+    }
+    
+    std::vector<std::string> input_channels = _device->InputChannels ();
+    _max_input_channels = input_channels.size ();
+    
+    uint32_t channels = (_input_channels ? _input_channels : input_channels.size ());
+    uint32_t port_number = 0;
+
+    LatencyRange lr = {0,0};
+
+    // Get latency for capture
+    lr.min = lr.max = _device->GetLatency (false) + _device->CurrentBufferSize () + _systemic_input_latency;
+    for (std::vector<std::string>::iterator it = input_channels.begin (); 
+         (port_number < channels) && (it != input_channels.end ());
+        ++it) {
+        std::ostringstream port_name;
+        port_name << "capture_" << ++port_number;
+
+        WavesDataPort* port = _register_port ("system:" + port_name.str (), DataType::AUDIO , static_cast<PortFlags> (IsOutput | IsPhysical | IsTerminal));
+        if (port == NULL) {
+            std::cerr << "WavesAudioBackend::_create_system_audio_ports (): Failed registering port [" << port_name << "] for [" << _device->DeviceName () << "]" << std::endl;
+            return-1;
+        }
+        set_latency_range (port, false, lr);
+    }
+    
+    std::vector<std::string> output_channels = _device->OutputChannels ();
+    _max_output_channels = output_channels.size ();
+    channels = (_output_channels ? _output_channels : _max_output_channels);
+    port_number = 0;
+    
+    // Get latency for playback
+    lr.min = lr.max = _device->GetLatency (true) + _device->CurrentBufferSize () + _systemic_output_latency;
+
+    for (std::vector<std::string>::iterator it = output_channels.begin ();
+         (port_number < channels) && (it != output_channels.end ());
+        ++it) {
+        std::ostringstream port_name;
+        port_name << "playback_" << ++port_number;
+        WavesDataPort* port = _register_port ("system:" + port_name.str (), DataType::AUDIO , static_cast<PortFlags> (IsInput| IsPhysical | IsTerminal));
+        if (port == NULL) {
+            std::cerr << "WavesAudioBackend::_create_system_audio_ports (): Failed registering port ]" << port_name << "] for [" << _device->DeviceName () << "]" << std::endl;
+            return-1;
+        }
+        set_latency_range (port, true, lr);
+    }
+    
+    return 0;
+}
+
+
+void
+WavesAudioBackend::_unregister_system_audio_ports ()
+{
+    std::vector<WavesAudioPort*> physical_audio_ports = _physical_audio_inputs;
+    physical_audio_ports.insert (physical_audio_ports.begin (), _physical_audio_outputs.begin (), _physical_audio_outputs.end ());
+        
+    for (std::vector<WavesAudioPort*>::const_iterator it = physical_audio_ports.begin (); it != physical_audio_ports.end (); ++it) {
+        std::vector<WavesDataPort*>::iterator port_iterator = std::find (_ports.begin (), _ports.end (), *it);
+        if (port_iterator == _ports.end ()) {
+            std::cerr << "WavesAudioBackend::_unregister_system_audio_ports (): Failed to find port [" << (*it)->name () << "]!"  << std::endl;
+        }
+        else {
+            _ports.erase (port_iterator);
+        }
+        delete *it;
+    }
+
+    _physical_audio_inputs.clear ();
+    _physical_audio_outputs.clear ();
+}
+
+
index 62bacdbceaddf51be18fba2bba10d7381d10dd47..600066b83c3b0055ba253cbc334e8b08f436ad75 100644 (file)
@@ -1,62 +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
+/*
+    Copyright (C) 2013 Valeriy Kamyshniy
+
+    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_audioport.h"
+
+using namespace ARDOUR;
+
+WavesAudioPort::WavesAudioPort (const std::string& port_name, PortFlags flags)
+    : WavesDataPort (port_name, flags)    
+{
+    memset (_buffer, 0, sizeof (_buffer));
+}
+
+
+void* WavesAudioPort::get_buffer (pframes_t nframes)
+{
+    if (is_input ()) {
+        
+        std::vector<WavesDataPort*>::const_iterator it = get_connections ().begin ();
+        
+        if (it != get_connections ().end ()) {
+            /* In fact, the static casting to (const WavesAudioPort*) is not that safe.
+             * However, mixing the buffers is assumed in the time critical conditions.
+             * Base class WavesDataPort takes is supposed to provide enough consistentcy
+             * of the connections.
+             */
+            for (memcpy (_buffer, ((const WavesAudioPort*)*it)->const_buffer (), nframes * sizeof (Sample)), ++it;
+                                it != get_connections ().end ();
+                                ++it) {
+                Sample* tgt = buffer ();
+                const Sample* src = ((const WavesAudioPort*)*it)->const_buffer ();
+                for (uint32_t frame = 0; frame < nframes; ++frame, ++tgt, ++src)    {
+                    *tgt += *src;
+                }
+            }
+        }
+    }
+    return _buffer;
+}
+
+
+void
+WavesAudioPort::_wipe_buffer()
+{
+       memset (_buffer, 0, sizeof (_buffer));
+}
\ No newline at end of file
index a0f878bee54636fcc18e51c0988777f709b6f454..e377760fc439949c49d0c13dab43ae03bf514d91 100644 (file)
@@ -1,58 +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
+/*
+    Copyright (C) 2013 Paul Davis
+
+    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_audioport_h__
+#define __libardour_waves_audioport_h__
+
+#include "memory.h"
+#include "waves_dataport.h"
+        
+namespace ARDOUR {
+
+class WavesAudioPort : public WavesDataPort {
+
+public:
+    enum BufferSize {
+        MAX_BUFFER_SIZE_SAMPLES = 8192,
+        MAX_BUFFER_SIZE_BYTES = sizeof (Sample) * MAX_BUFFER_SIZE_SAMPLES
+    };
+
+    WavesAudioPort (const std::string& port_name, PortFlags flags);
+
+    virtual ~WavesAudioPort () { };
+
+    virtual DataType type () const {    return DataType::AUDIO; };
+
+    inline Sample* buffer () { return _buffer; }
+    inline const Sample* const_buffer () const { return _buffer; }
+
+    virtual void* get_buffer (pframes_t nframes);
+
+protected:
+       virtual void _wipe_buffer();
+
+private:
+
+    Sample _buffer[MAX_BUFFER_SIZE_SAMPLES];
+};
+
+} // namespace
+
+#endif /* __libardour_waves_audioport_h__ */
+    
index 84f4efaf6c36939816debce92f91bfd8ea93d699..f97bd978462c1df3645dbb636231138f4f502bbd 100644 (file)
-/*\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
+/*
+    Copyright (C) 2013 Valeriy Kamyshniy
+
+    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_dataport.h"
+
+using namespace ARDOUR;
+
+WavesDataPort::WavesDataPort (const std::string& inport_name, PortFlags inflags)
+    : _name (inport_name)
+    , _flags (inflags)
+{
+    _capture_latency_range.min = 
+    _capture_latency_range.max = 
+    _playback_latency_range.min = 
+    _playback_latency_range.max = 0;
+}
+
+
+WavesDataPort::~WavesDataPort ()
+{
+    disconnect_all ();
+}
+
+
+int WavesDataPort::connect (WavesDataPort *port)
+{
+    if (!port) {
+        std::cerr << "WavesDataPort::connect (): invalid (null) port to connect to!" << std::endl;
+        return -1;
+    }
+
+    if (type () != port->type ())    {
+        std::cerr << "WavesDataPort::connect (): wrong type of the port to connect to!" << std::endl;
+        return -1;
+    }
+
+    if (is_output () && port->is_output ()) {
+        std::cerr << "WavesDataPort::connect (): attempt to connect output port to output port!" << std::endl;
+        return -1;
+    }
+
+    if (is_input () && port->is_input ()) {
+        std::cerr << "WavesDataPort::connect (): attempt to connect input port to input port!" << std::endl;
+        return -1;
+    }
+
+    if (this == port) {
+        std::cerr << "WavesDataPort::connect (): attempt to connect port to itself!" << std::endl;
+        return -1; 
+    }
+
+    if (is_connected (port)) {
+        std::cerr << "WavesDataPort::connect (): the ports are already connected!" << std::endl;
+        return -1;
+    }
+
+    _connect (port, true);
+    return 0;
+}
+
+
+void WavesDataPort::_connect (WavesDataPort *port, bool api_call)
+{
+    _connections.push_back (port);
+    if (api_call) {
+        port->_connect (this, false);
+    }
+}
+
+
+int WavesDataPort::disconnect (WavesDataPort *port)
+{
+    if (port == NULL) {
+        std::cerr << "WavesDataPort::disconnect (): invalid (null) port to disconnect from!" << std::endl;
+        return -1;
+    }
+
+    if (!is_connected (port)) {
+        std::cerr << "WavesDataPort::disconnect (): the ports are not connected!" << std::endl;
+        return -1;
+    }
+
+    _disconnect (port, true);
+
+    return 0;
+}
+
+
+void WavesDataPort::_disconnect (WavesDataPort *port, bool api_call)
+{
+    std::vector<WavesDataPort*>::iterator it = std::find (_connections.begin (), _connections.end (), port);
+    
+    if (it != _connections.end ()) { // actually, it's supposed to be always true.
+        _connections.erase (it);
+    }
+
+    if (api_call) {
+        port->_disconnect (this, false);
+    }
+
+       if (is_input() && _connections.empty())
+       {
+               _wipe_buffer();
+       }
+}
+
+
+void WavesDataPort::disconnect_all ()
+{
+    while (!_connections.empty ()) {
+        _connections.back ()->_disconnect (this, false);
+        _connections.pop_back ();
+    }
+}
+
+
+bool WavesDataPort::is_physically_connected () const
+{
+    for (std::vector<WavesDataPort*>::const_iterator it = _connections.begin (); it != _connections.end (); ++it) {
+        if ((*it)->is_physical ()) {
+            return true;
+        }
+    }
+
+    return false;
+}
index fd8dd8090bf219b9e131ea1b3473cbacd51df344..d8b095351cfb01895d34cc66a218556b6bc777df 100644 (file)
-/*\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
+/*
+    Copyright (C) 2013 Paul Davis
+
+    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_dataport_h__
+#define __libardour_waves_dataport_h__
+
+#include "ardour/types.h"
+#include "memory.h"
+        
+namespace ARDOUR {
+
+class WavesDataPort {
+public:
+
+    virtual ~WavesDataPort ();
+
+    inline const std::string& name () const
+    {
+        return _name;
+    }
+    
+    int set_name (const std::string &name)
+    {
+        _name = name;
+        return 0;
+    }
+
+    virtual DataType type () const = 0;
+
+    inline PortFlags flags () const
+    {
+        return _flags;
+    }
+
+    inline bool is_input () { return flags () & IsInput; }
+    inline bool is_output () { return flags () & IsOutput; }
+    inline bool is_physical () { return flags () & IsPhysical; }
+    inline bool is_terminal () { return flags () & IsTerminal; }
+    inline operator void* () { return (void*)this; }
+
+    inline const LatencyRange& latency_range (bool for_playback) const
+    {
+        return for_playback ? _playback_latency_range : _capture_latency_range;
+    }
+
+    inline void set_latency_range (const LatencyRange &latency_range, bool for_playback)
+    {
+        if (for_playback)
+        {
+            _playback_latency_range = latency_range;
+        }
+        else
+        {
+            _capture_latency_range = latency_range;
+        }
+    }
+
+    int connect (WavesDataPort *port);
+    
+    int disconnect (WavesDataPort *port);
+    
+    void disconnect_all ();
+
+    bool inline is_connected (const WavesDataPort *port) const
+    {
+        return std::find (_connections.begin (), _connections.end (), port) != _connections.end ();
+    }
+
+    bool inline is_connected () const
+    {
+        return _connections.size () != 0;
+    }
+
+    bool is_physically_connected () const;
+
+    inline const std::vector<WavesDataPort *>& get_connections () const { return _connections; }
+
+    virtual void* get_buffer (pframes_t nframes) = 0;
+
+protected:
+    WavesDataPort (const std::string& inport_name, PortFlags inflags);
+       virtual void _wipe_buffer() = 0;
+
+private:
+
+    std::string _name;
+    const PortFlags _flags;
+    LatencyRange _capture_latency_range;
+    LatencyRange  _playback_latency_range;
+    std::vector<WavesDataPort*> _connections;
+
+    void _connect (WavesDataPort* port, bool api_call);
+    void _disconnect (WavesDataPort* port, bool api_call);
+};
+
+} // namespace
+
+#endif /* __libardour_waves_dataport_h__ */
+    
index 24527de0e57f420a2afef0a73a428c97d3ba7d12..03f5ca71db5bd216c603d9b9a100cd40c993efbe 100644 (file)
@@ -1,50 +1,49 @@
-/*\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
+/*
+    Copyright (C) 2013 Valeriy amyshniy
+
+    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_buffer.h"
+#include "waves_midi_event.h"
+
+using namespace ARDOUR;
+
+WavesMidiBuffer::WavesMidiBuffer (std::string name)
+    : std::vector<WavesMidiEvent*> ()
+    , _name (name)
+{
+}
+
+WavesMidiBuffer::~WavesMidiBuffer ()
+{
+    clear ();
+}
+
+void WavesMidiBuffer::clear ()
+{
+    for (WavesMidiBufferIterator it = begin (); it !=  end (); ++it)
+        delete *it;
+
+    std::vector<WavesMidiEvent*>::clear ();
+}
+
+WavesMidiBuffer& WavesMidiBuffer::operator += (const WavesMidiBuffer& source)
+{
+    for (WavesMidiBufferConstIterator it = source.begin (); it !=  source.end (); ++it) {
+        push_back (new WavesMidiEvent (**it));
+    }
+    return *this;
+}
index b1f6e90c36da87ae1b1b759e82e0dcf75919aab5..5e58b783bb40e6a0237c318394e818e1ab624cb4 100644 (file)
@@ -1,47 +1,48 @@
-/*\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
+/*
+    Copyright (C) 2013 Valeriy amyshniy
+
+    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_buffer_h__
+#define __libardour_waves_midi_buffer_h__
+
+#include "ardour/types.h"
+
+namespace ARDOUR {
+
+class WavesMidiEvent;
+
+class WavesMidiBuffer : public std::vector<WavesMidiEvent*>
+{
+public:
+    WavesMidiBuffer (std::string name);
+    ~WavesMidiBuffer ();
+    void clear ();
+    WavesMidiBuffer& operator += (const WavesMidiBuffer& source);
+
+    inline const std::string name () { return _name; } // for DBG purpouses;
+
+private:
+    const std::string _name;
+};
+
+typedef std::vector<WavesMidiEvent*>::iterator WavesMidiBufferIterator;
+typedef std::vector<WavesMidiEvent*>::const_iterator WavesMidiBufferConstIterator;
+
+} // namespace
+
+#endif /* __libardour_waves_midi_buffer_h__ */
index aa305955a6696574e49012e4352815b6b750d734..0f84c6d26249f1d39652e1d3c5f1a0b19ffdcc99 100644 (file)
-/*\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
+/*
+    Copyright (C) 2013 Gorobchenko Dmytro
+
+    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.h"
+#include "waves_midi_event.h"
+
+// use non-zero latency because we want output to be timestapmed
+#define LATENCY 0
+
+#define QUEUE_LENGTH 1024
+
+using namespace ARDOUR;
+
+WavesMidiDevice::WavesMidiDevice (const std::string& device_name)
+    : _pm_input_id (pmNoDevice)
+    , _pm_output_id (pmNoDevice)
+    , _name (device_name)
+    , _input_queue (NULL)
+    , _output_queue (NULL)
+    , _input_pm_stream (NULL)
+    , _output_pm_stream (NULL)
+    , _incomplete_waves_midi_event (NULL)
+{
+    validate ();
+}
+
+WavesMidiDevice::~WavesMidiDevice ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::~WavesMidiDevice ():" << name () << std::endl;
+    close ();
+}
+
+void
+WavesMidiDevice::validate ()
+{
+    _pm_input_id = 
+    _pm_output_id = pmNoDevice;
+    int count = Pm_CountDevices ();
+
+    for (int i = 0; i < count; i++) {
+
+        const PmDeviceInfo* pm_device_info = Pm_GetDeviceInfo (i);
+
+        if (pm_device_info == NULL) {
+            continue;
+        }
+        if (name () == pm_device_info->name) {
+            if (pm_device_info->input){
+                _pm_input_id = i;
+            }
+            if (pm_device_info->output){
+                _pm_output_id = i;
+            }
+        }
+    }
+}
+
+int
+WavesMidiDevice::open (PmTimeProcPtr time_proc, void* time_info)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::open ():" << name () << std::endl;
+    
+    if (is_input () && !_input_pm_stream) {
+        if (pmNoError != Pm_OpenInput (&_input_pm_stream, 
+                                      _pm_input_id,
+                                      NULL,
+                                      1024,
+                                      time_proc,
+                                      time_info)) {
+                std::cerr << "WavesMidiDevice::open (): Pm_OpenInput () failed for " << _pm_input_id << "-[" << name () <<  "]!" << std::endl;
+                _input_pm_stream = NULL;
+                _pm_input_id = pmNoDevice;
+                return -1;
+        }
+        _input_queue = Pm_QueueCreate (QUEUE_LENGTH, sizeof (const WavesMidiEvent*));
+        if (NULL == _input_queue) {
+            std::cerr << "WavesMidiDevice::open (): _input_queue = Pm_QueueCreate () failed for " << _pm_input_id << "-[" << name () <<  "]!" << std::endl;
+            close ();
+            return -1;
+        }
+    }
+
+    if (is_output () && !_output_pm_stream) {
+        if (pmNoError != Pm_OpenOutput (&_output_pm_stream, 
+                                       _pm_output_id, 
+                                       NULL,
+                                       1024,
+                                       time_proc,
+                                       time_info,
+                                       LATENCY)) {
+                std::cerr << "WavesMidiDevice::open (): Pm_OpenOutput () failed for " << _pm_output_id << "-[" << name () <<  "]!" << std::endl;
+                _output_pm_stream = NULL;
+                _pm_output_id = pmNoDevice;
+                return -1;
+        }
+        _output_queue = Pm_QueueCreate (QUEUE_LENGTH, sizeof (const WavesMidiEvent*));
+        if (NULL == _output_queue) {
+            std::cerr << "WavesMidiDevice::open (): _output_queue = Pm_QueueCreate () failed for " << _pm_output_id << "-[" << name () <<  "]!" << std::endl;
+            close ();
+            return -1;
+        }
+    }
+    return 0;
+}
+
+
+void
+WavesMidiDevice::close ()
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::close ():" << name () << std::endl;
+    WavesMidiEvent *waves_midi_event;
+
+    if (_input_pm_stream) {
+        Pm_Close (_input_pm_stream);
+        while (1 == Pm_Dequeue (_input_queue, &waves_midi_event)) {
+            delete waves_midi_event;
+        }
+
+        Pm_QueueDestroy (_input_queue);
+        _input_queue = NULL;
+        _input_pm_stream = NULL;
+        _pm_input_id = pmNoDevice;
+    }
+
+
+    if ( _output_pm_stream ) {
+        Pm_Close (_output_pm_stream);
+        while (1 == Pm_Dequeue (_output_queue, &waves_midi_event)) {
+            delete waves_midi_event;
+        }
+        Pm_QueueDestroy (_output_queue);
+        _output_queue = NULL;
+        _output_pm_stream = NULL;
+        _pm_output_id = pmNoDevice;
+    }
+}
+
+void
+WavesMidiDevice::do_io ()
+{
+    read_midi ();
+    write_midi ();
+}
+
+void
+WavesMidiDevice::read_midi ()
+{
+    if (NULL == _input_pm_stream) {
+        return;
+    }
+
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_read_midi (): " << _pm_device_id << "-[" << name () << "]" << std::endl;
+
+    while (Pm_Poll (_input_pm_stream) > 0) {
+        PmEvent pm_event; // just one message at a time
+        int result = Pm_Read (_input_pm_stream, &pm_event, 1);
+        if (result < 0) {
+            std::cerr << "WavesMidiDevice::_read_midi (): Pm_Read () failed (" << result << ") for [" << name () << "]!" << std::endl;
+            break;
+        }
+        // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_read_midi (): " << _pm_device_id << "-[" << name () << "] evt-tm:" << pm_event.timestamp << std::endl;
+        if (_incomplete_waves_midi_event == NULL ) {
+            // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_read_midi (): " << _pm_device_id << "-[" << name () << "] : new _incomplete_waves_midi_event" << std::endl;
+            _incomplete_waves_midi_event = new WavesMidiEvent (pm_event.timestamp);
+        }
+        
+        WavesMidiEvent *nested_pm_event = _incomplete_waves_midi_event->append_data (pm_event);
+        if (nested_pm_event) {
+            Pm_Enqueue (_input_queue, &nested_pm_event);
+            // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_read_midi (): " << _pm_device_id << "-[" << name () << "] : Pm_Enqueue (_input_queue, nested_pm_event)" << std::endl;
+        }
+        switch ( _incomplete_waves_midi_event->state ()) {
+            case WavesMidiEvent::BROKEN:
+                delete _incomplete_waves_midi_event;
+                _incomplete_waves_midi_event = NULL;
+                // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_read_midi (): " << _pm_device_id << "-[" << name () << "] : case WavesMidiEvent::BROKEN:" << std::endl;
+            break;
+            case WavesMidiEvent::COMPLETE:
+                // 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;
+                Pm_Enqueue (_input_queue, &_incomplete_waves_midi_event);
+                _incomplete_waves_midi_event = NULL;
+            break;
+            default:
+            break;
+        }
+    }
+}
+
+
+void
+WavesMidiDevice::write_midi ()
+{
+    if (NULL == _output_pm_stream) {
+        return;
+    }
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_write_midi (): " << _pm_device_id << "-[" << name () << "]" << std::endl;
+
+    PmError err;
+    WavesMidiEvent *waves_midi_event;
+
+    while (1 == Pm_Dequeue (_output_queue, &waves_midi_event)) {
+        if (waves_midi_event->sysex ()) {
+            // LATENCY compensation
+            err = Pm_WriteSysEx (_output_pm_stream, waves_midi_event->timestamp () - LATENCY, waves_midi_event->data ());
+            if (0 > err) {
+                std::cout << "WavesMidiDevice::write_event_to_device (): [" << name () << "] Pm_WriteSysEx () failed (" << err << ")!" << std::endl;
+            };
+            // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_write_midi (): SYSEX used, ev->tm:" << waves_midi_event->timestamp () - LATENCY << std::endl;
+        }
+        else
+        {
+            err = Pm_WriteShort (_output_pm_stream, waves_midi_event->timestamp () - LATENCY, * (PmMessage*)waves_midi_event->data ());
+            if (0 > err) {
+                std::cout << "WavesMidiDevice::write_event_to_device (): [" << name () << "] Pm_WriteShort () failed (" << err << ")!" << std::endl;
+            }
+            // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::_write_midi (): SHORTMSG used, ev->tm:" << waves_midi_event->timestamp () - LATENCY <<  std::endl;
+        }
+        delete waves_midi_event;
+    }
+    return;
+}
+
+int
+WavesMidiDevice::enqueue_output_waves_midi_event (const WavesMidiEvent* waves_midi_event)
+{
+    // COMMENTED DBG LOGS */ std::cout << "WavesMidiDevice::enqueue_output_waves_midi_event (): " << _pm_device_id << "-[" << name () << "]" << std::endl;
+
+    if (waves_midi_event == NULL) {
+        std::cerr << "WavesMidiDevice::put_event_to_callback (): 'waves_midi_event' is NULL!" << std::endl;
+        return -1;
+    }
+
+    PmError err = Pm_Enqueue (_output_queue, &waves_midi_event);
+
+    if (0 > err) {
+        std::cerr << "WavesMidiDevice::put_event_to_callback (): Pm_Enqueue () failed (" << err << ")!" << std::endl;
+        return -1;
+    };
+
+    return 0;
+}
+
+WavesMidiEvent* 
+WavesMidiDevice::dequeue_input_waves_midi_event ()
+{
+    WavesMidiEvent* waves_midi_event;
+    if (Pm_Dequeue (_input_queue, &waves_midi_event) == 1) {
+        return waves_midi_event;
+    }
+    return NULL;
+}
+
index a8b734736dfd9b81ee17ba0bd0f0186a5d71b5b0..ce3bb3c486f03d385ca05a2cefd110e835514e1e 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014 Waves Audio Ltd.
+    Copyright (C) 2013 Gorobchenko Dmytro
 
     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
index 84667a2dbd44179bb03ef3f460b000c7b40e372f..f3cd7424c9e64747d756f4699a599e3c2618b5d3 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014 Waves Audio Ltd.
+    Copyright (C) 2013 Paul Davis
 
     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
index 75a2757f90162803a4f677949fd2d8b6fd7215c5..9d9124fc832d5181e9b20b39888c70529d627ae5 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014 Waves Audio Ltd.
+    Copyright (C) 2013 Gorobchenko Dmytro
 
     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
index 532555c95814fd311a3a9ab1c0bdb4adefb82a45..08b8bdfc655dadd62318fd91dfbdae10bcd35af8 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014 Waves Audio Ltd.
+    Copyright (C) 2013 Valeriy amyshniy
 
     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
@@ -16,7 +16,6 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 */
-
 #include "memory.h"
 #include "waves_midi_event.h"
 
index 9015a2ce816889ebac990da89fba2ae017e163d0..510438e8884780c9f946073c2bd83df6e2d81e70 100644 (file)
@@ -1,75 +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
+/*
+    Copyright (C) 2013 Valeriy amyshniy
+
+    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_event_h__
+#define __libardour_waves_midi_event_h__
+
+#include <stdlib.h>
+#include <portmidi/portmidi.h>
+#include "ardour/types.h"
+
+namespace ARDOUR {
+
+class WavesMidiEvent
+{
+public:
+    enum State {
+        INCOMPLETE,
+        BROKEN,
+        COMPLETE
+    };
+
+    WavesMidiEvent (PmTimestamp timestamp);
+    WavesMidiEvent (PmTimestamp timestamp, const uint8_t* data, size_t datalen);
+    WavesMidiEvent (const WavesMidiEvent& source);
+    ~WavesMidiEvent ();
+    
+    WavesMidiEvent *append_data (const PmEvent &midi_event);
+
+    inline State state () const { return _state; };
+    inline size_t size () const { return _size; };
+    inline PmTimestamp timestamp () const { return _timestamp; };
+    inline void set_timestamp (PmTimestamp time_stamp) { _timestamp = time_stamp; };
+    inline const unsigned char* const_data () const { return _data; };
+    inline unsigned char* data () { return _data; };
+    inline bool operator< (const WavesMidiEvent &other) const { return timestamp () < other.timestamp (); };
+    inline bool sysex () const { return _data && (*_data == SYSEX); };
+
+private:
+
+    enum
+    {
+        SYSEX = 0xF0,
+        EOX = 0xF7,
+        REAL_TIME_FIRST = 0xF8,
+        STATUS_FIRST = 0x80
+    };
+
+    size_t _size;
+    PmTimestamp _timestamp;
+    uint8_t *_data;
+    State _state;
+
+    static size_t _midi_message_size (PmMessage midi_message);
+};
+
+
+} // namespace
+
+#endif /* __libardour_waves_midi_event_h__ */
index 8a77776c5eca5d10d148119031f56ee7a518498b..cadf36eb2a6515b57e37bde3bc28c74d9cab3134 100644 (file)
@@ -1,61 +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
+/*
+    Copyright (C) 2013 Gorobchenko Dmytro
+
+    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_midiport.h"
+#include "waves_midi_event.h"
+
+using namespace ARDOUR;
+
+WavesMidiPort::WavesMidiPort (const std::string& port_name, PortFlags flags)
+    : WavesDataPort (port_name, flags)
+    , _midi_device (NULL)
+    , _waves_midi_buffer (port_name)
+{       
+}
+
+void* 
+WavesMidiPort::get_buffer (pframes_t nframes)
+{
+    if (is_input ()) {
+               std::vector<WavesDataPort*>::const_iterator cit = get_connections ().begin ();
+        if (cit != get_connections ().end ()) {
+                       _waves_midi_buffer.clear ();
+                       WavesMidiBuffer& target = _waves_midi_buffer;
+
+                       do      {
+                               /* In fact, the static casting to (const WavesMidiPort*) is not that safe.
+                                * However, mixing the buffers is assumed in the time critical conditions.
+                                * Base class WavesDataPort is supposed to provide enough consistentcy
+                                * of the connections.
+                                */
+                               target += ((const WavesMidiPort*)*cit)->const_buffer ();
+                       }while((++cit) != get_connections ().end ());
+
+                       std::sort (target.begin (), target.end ());
+               }
+       }
+
+    return &_waves_midi_buffer;
+}
+
+void
+WavesMidiPort::_wipe_buffer()
+{
+       _waves_midi_buffer.clear ();
+}
\ No newline at end of file
index 6df1c2b04a914ad747269a4137645a5bbf5bc44a..09bbf1b1f0d3f48611f1db240dca763c08ff7174 100644 (file)
@@ -1,64 +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
+/*
+    Copyright (C) 2013 Gorobchenko Dmytro
+
+    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_midiport_h__
+#define __libardour_waves_midiport_h__
+
+#include "waves_dataport.h"
+#include "waves_midi_buffer.h"
+
+namespace ARDOUR {
+
+class WavesMidiEvent;
+class WavesMidiDevice;
+class WavesMidiEvent;
+
+class WavesMidiPort : public WavesDataPort {
+public:
+    enum BufferSize {
+        // This value has nothing to do with reality as buffer of MIDI Port is not a flat array.
+        // It's an iterated list.
+        MAX_BUFFER_SIZE_BYTES = 8192
+    };
+
+    WavesMidiPort (const std::string& port_name, PortFlags flags);
+    virtual ~WavesMidiPort (){};
+
+    virtual DataType type () const {    return DataType::MIDI; };
+
+    virtual void* get_buffer (pframes_t nframes);
+
+    inline WavesMidiBuffer& buffer () { return _waves_midi_buffer; }
+    inline const WavesMidiBuffer& const_buffer () const { return _waves_midi_buffer; }
+
+    inline void set_midi_device (WavesMidiDevice* midi_device) { _midi_device = midi_device; };
+    inline WavesMidiDevice* midi_device () const { return _midi_device; };
+
+protected:
+       virtual void _wipe_buffer();
+
+private:
+    WavesMidiDevice * _midi_device;
+    WavesMidiBuffer _waves_midi_buffer;
+};
+
+} // namespace
+
+#endif /* __libardour_waves_midiport_h__ */
+    
index 165acc32953362c21720fb9ef3f2ab800eb14c9d..477fd25af9509d9ad9ad125c26b337083dead473 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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__
        
index 7d7fd8c1a96b905d8419ba7f14992efff1f51283..587c60ac60c2d1477ad2f83cb5475e773e2d8178 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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__
 
index 6193da38bb7ae0ce623db5c1e18492e7e3bb14ad..0658e6a9e6abff38b276787d67b54ea03fb26d25 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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__
        
index ea5c840d97ff118fb6d8ccee8547c2bf5ff85974..346ab441862cb0c9075c968cdcc4b532ed32817e 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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__
 
index 6f51bfa3f6d180dcce5c11cd83e8cd290ca6a791..041bf3792bc60fdcb0cc40cd5f4ecfadf26201d9 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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__
        
index c28547eddb6b4f913c053d7a21ff731e9503c6de..2f91df333a25a146ca6886cec357f1e19880013b 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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__
 
index 5dd8f0ed50dc2abd7fbc02b3788dd1fc3b92c2d5..313b38ea4621b8566e1240c3ed6c46a2fc0f5c87 100644 (file)
@@ -1,49 +1,31 @@
-/*
-    Copyright (C) 2013 Waves Audio Ltd.
+#ifndef __IncludeWindows_h__
+#define __IncludeWindows_h__
 
-    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.
+#ifdef _WINDOWS
 
-    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.
+/* Copy to include
+#include "IncludeWindows.h"
+*/
 
-    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 _WIN32_WINNT
+#define _WIN32_WINNT   0x0601   // Windows 7
+#endif
+
+#ifndef WINVER
+#define WINVER                 0x0601   // Windows 7
+#endif
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifndef NOMINMAX
+#define NOMINMAX // DO NOT REMOVE NOMINMAX - DOING SO CAUSES CONFLICTS WITH STD INCLUDES (<limits> ...)
+#endif
+
+#include <WinSock2.h>
+#include <Windows.h>
+#include <objbase.h>
+#endif // #if _WINDOWS 
+#endif // #ifndef __IncludeWindows_h__
 
-*/
-#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
index ae5ef3a9231aa8a88b739f308f002ec0cf0c03a3..00ee1c247f8f6882ab152051ded83a13f57390f7 100644 (file)
@@ -1,23 +1,6 @@
-/*
-    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.
-
-*/
 //----------------------------------------------------------------------------------
 //
+// Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
 //
 //! \file      WCMRAudioDeviceManager.cpp
 //!
 #include "WCMRAudioDeviceManager.h"
 
 
-
-
-
-
 //**********************************************************************************************
 // WCMRAudioDevice::WCMRAudioDevice 
 //
 //!            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)
+WCMRAudioDevice::WCMRAudioDevice (WCMRAudioDeviceManager *pManager) :
+       m_pMyManager (pManager)
+       , 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)
 {
-       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;
-       
-
 }
 
 
@@ -565,6 +538,7 @@ uint32_t WCMRAudioDevice::GetLatency (bool isInput)
     return 0;
 }
 
+
 //**********************************************************************************************
 // WCMRAudioDeviceManager::WCMRAudioDeviceManager
 //
@@ -576,15 +550,13 @@ uint32_t WCMRAudioDevice::GetLatency (bool isInput)
 //! 
 //**********************************************************************************************
 WCMRAudioDeviceManager::WCMRAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter)
-       : m_pTheClient (pTheClient)
-       , m_eAudioDeviceFilter(eCurAudioDeviceFilter)
+    : m_eAudioDeviceFilter(eCurAudioDeviceFilter)
+    , m_CurrentDevice(0)
+    , m_pTheClient (pTheClient)
 {
-       //The derived classes will do lot more init!
-       return;
 }
 
 
-
 //**********************************************************************************************
 // WCMRAudioDeviceManager::~WCMRAudioDeviceManager
 //
@@ -599,19 +571,21 @@ WCMRAudioDeviceManager::~WCMRAudioDeviceManager()
 {
     AUTO_FUNC_DEBUG;
 
+       std::cout << "API::Destroying AudioDeviceManager " << std::endl;
        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!
+               // clean up device info list
+        {
+            wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
+            while( m_DeviceInfoVec.size() )
+            {
+                DeviceInfo* devInfo = m_DeviceInfoVec.back();
+                m_DeviceInfoVec.pop_back();
+                delete devInfo;
+            }
+        }
+               delete m_CurrentDevice;
+
        }
        catch (...)
        {
@@ -621,107 +595,46 @@ WCMRAudioDeviceManager::~WCMRAudioDeviceManager()
 }
 
 
-
-
-//**********************************************************************************************
-// 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()
+WCMRAudioDevice* WCMRAudioDeviceManager::InitNewCurrentDevice(const std::string & deviceName)
 {
-       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);
+       return initNewCurrentDeviceImpl(deviceName);
 }
 
 
-
-
-//**********************************************************************************************
-// 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
+void WCMRAudioDeviceManager::DestroyCurrentDevice()
 {
-       return (m_Devices);
+       return destroyCurrentDeviceImpl();
 }
 
 
-
-//**********************************************************************************************
-// *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
+const DeviceInfoVec WCMRAudioDeviceManager::DeviceInfoList() 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);
+    wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
+       return m_DeviceInfoVec;
 }
 
-//**********************************************************************************************
-// *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()
+
+WTErr WCMRAudioDeviceManager::GetDeviceInfoByName(const std::string & nameToMatch, DeviceInfo & devInfo) const
 {
-       //Need to check all our devices...
-       WCMRAudioDevice *pRetVal = NULL;
-       
-       WCMRAudioDeviceListIter deviceIter = m_Devices.begin();
-       if(deviceIter != m_Devices.end())
+    wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
+       DeviceInfoVecConstIter iter = m_DeviceInfoVec.begin();
+       for (; iter != m_DeviceInfoVec.end(); ++iter)
        {
-               pRetVal = *deviceIter;
+               if (nameToMatch == (*iter)->m_DeviceName)
+        {
+                       devInfo = *(*iter);
+            return eNoErr;
+        }
        }
-       return (pRetVal);
+
+       return eRMResNotFound;
 }
 
 
+WTErr WCMRAudioDeviceManager::GetDeviceBufferSizes(const std::string & nameToMatch, std::vector<int>& bufferSizes) const
+{
+       return getDeviceBufferSizesImpl(nameToMatch, bufferSizes);
+}
 
 
 //**********************************************************************************************
index 0d6aa55dea6c625bcfe34f0226ece0ae1cec8edc..a3b1baa784dce9379651f3f6198098771e5bf7d0 100644 (file)
@@ -1,23 +1,6 @@
-/*
-    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.
-
-*/
 //----------------------------------------------------------------------------------
 //
+// Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
 //
 //! \file      WCMRAudioDeviceManager.h
 //!
 #include "WCRefManager.h"
 #include "BasicTypes/WUTypes.h"
 #include "WUErrors.h"
+#include "WCThreadSafe.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
+typedef unsigned int DeviceID;
+
+struct DeviceInfo
+{
+       DeviceID m_DeviceId;
+       std::string m_DeviceName;
+       std::vector<int> m_AvailableSampleRates;
+       unsigned int m_MaxInputChannels;
+       unsigned int m_MaxOutputChannels;
+
+    DeviceInfo():
+    m_DeviceId(-1), m_DeviceName("Unknown"), m_MaxInputChannels(0), m_MaxOutputChannels(0)
+       {};
+    
+       DeviceInfo(unsigned int deviceID, const std::string & deviceName):
+               m_DeviceId(deviceID), m_DeviceName(deviceName), m_MaxInputChannels(0), m_MaxOutputChannels(0)
+       {};
+};
 
+typedef std::vector<DeviceInfo*> DeviceInfoVec;
+typedef DeviceInfoVec::iterator DeviceInfoVecIter;
+typedef DeviceInfoVec::const_iterator DeviceInfoVecConstIter;
 
 /// for notification... A client must derive it's class from us.
 class WCMRAudioDeviceManagerClient
@@ -71,6 +70,7 @@ class WCMRAudioDeviceManagerClient
                BufferSizeChanged,
                ClockSourceChanged,
                DeviceStoppedStreaming,
+               DeviceStartsStreaming,
                DeviceDroppedSamples,
                DeviceConnectionLost,
                DeviceGenericError,
@@ -123,7 +123,7 @@ public:
        {
                DeviceAvailable,
                DeviceDisconnected,
-               DeviceError
+               DeviceErrors
        };
 
        WCMRAudioDevice (WCMRAudioDeviceManager *pManager);///<Constructor
@@ -167,6 +167,8 @@ public:
        virtual WTErr SendCustomCommand (int customCommand, void *pCommandParam); ///< Send a custom command to the audiodevice...
     
     virtual uint32_t GetLatency (bool isInput); ///Get latency.
+
+       virtual WTErr UpdateDeviceInfo () = 0;
     
 protected:
        WCMRAudioDeviceManager *m_pMyManager; ///< The manager who's managing this device, can be used for sending notifications!
@@ -191,6 +193,7 @@ protected:
        float m_MonitorGain; ///< Amount of gain to apply for monitoring signal.
 };
 
+
 // This enum is for choosing filter for audio devices scan
 typedef enum eAudioDeviceFilter
 {
@@ -202,65 +205,44 @@ typedef enum eAudioDeviceFilter
        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();
-    }
+  
+       WCMRAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter); ///< constructor
+       virtual ~WCMRAudioDeviceManager(void); ///< Destructor
 
-    const WCMRAudioDeviceList& Devices() const
-    {
-        //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
-        return Devices_Private();
-    }
+       //interfaces
+       WCMRAudioDevice*        InitNewCurrentDevice(const std::string & deviceName);
+       void                            DestroyCurrentDevice();
+       const DeviceInfoVec DeviceInfoList () const;
+    WTErr               GetDeviceInfoByName(const std::string & nameToMatch, DeviceInfo & devInfo) const;
+       WTErr                           GetDeviceBufferSizes(const std::string & nameToMatch, std::vector<int>& bufferSizes) const;
 
-    WCMRAudioDevice* GetDeviceByName(const std::string & nameToMatch) const
-    {
-        //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
-        return GetDeviceByName_Private(nameToMatch);
-    }
+    //virtual void             EnableVerboseLogging(bool /*bEnable*/, const std::string& /*logFilePath*/) { };
 
-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*/) { };
+       //notify backend
+       void                                    NotifyClient (WCMRAudioDeviceManagerClient::NotificationReason forReason, void *pParam = NULL);
 
 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.
+    mutable wvNS::wvThread::ThreadMutex         m_AudioDeviceInfoVecMutex; // mutex to lock device info list
+       DeviceInfoVec                               m_DeviceInfoVec;
        
-       WCMRAudioDeviceList m_Devices; ///< List of all relevant devices devices
-       eAudioDeviceFilter m_eAudioDeviceFilter; // filter of 'm_Devices'
+    eAudioDeviceFilter                          m_eAudioDeviceFilter;
+       WCMRAudioDevice*                            m_CurrentDevice;
+
+private:
+       // override in derived classes
+       // made private to avoid pure virtual function call
+       virtual WCMRAudioDevice*        initNewCurrentDeviceImpl(const std::string & deviceName) = 0;
+       virtual void                            destroyCurrentDeviceImpl() = 0;
+       virtual WTErr                           getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& bufferSizes) const = 0;
+    virtual WTErr                              generateDeviceListImpl() = 0;
+    virtual WTErr                              updateDeviceListImpl() = 0;
+    
+       WCMRAudioDeviceManagerClient    *m_pTheClient; ///< The device manager's client, used to send notifications.
 };
 
 #endif //#ifndef __WCMRAudioDeviceManager_h_
index b66d2519cab7e155f3f2535fd488ceac5bb276f4..10da07fef19900af8f5c31a93297b559e23734f1 100644 (file)
@@ -1,23 +1,6 @@
-/*
-    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.
-
-*/
 //----------------------------------------------------------------------------------
 //
+// Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
 //
 //! \file   WCMRCoreAudioDeviceManager.cpp
 //!
@@ -58,6 +41,8 @@ static const int DEFAULT_SR = 44100;
 ///< The default buffer size.
 static const int DEFAULT_BUFFERSIZE = 128;
 
+static const int NONE_DEVICE_ID = -1;
+
 ///< 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.
@@ -166,7 +151,7 @@ WCMRCoreAudioDevice::WCMRCoreAudioDevice (WCMRCoreAudioDeviceManager *pManager,
         m_CurrentBufferSize = (int)bufferSize;
     
     
-    UpdateDeviceInfo(true /*updateSRSupported*/, true /* updateBufferSizes */);
+    UpdateDeviceInfo();
 
     //should use a valid current SR...
     if (m_SamplingRates.size())
@@ -252,14 +237,11 @@ WCMRCoreAudioDevice::~WCMRCoreAudioDevice ()
 // 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)
+WTErr WCMRCoreAudioDevice::UpdateDeviceInfo ()
 {
     AUTO_FUNC_DEBUG;
     
@@ -272,17 +254,8 @@ WTErr WCMRCoreAudioDevice::UpdateDeviceInfo (bool updateSRSupported, bool update
     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();
-    }
+    errSR = UpdateDeviceSampleRates();
+    errBS = UpdateDeviceBufferSizes();
 
     if(errName != eNoErr || errIn != eNoErr || errOut != eNoErr || errSR != eNoErr || errBS != eNoErr)
     {
@@ -786,7 +759,7 @@ WTErr WCMRCoreAudioDevice::SetCurrentSamplingRate (int newRate)
     retVal = SetAndCheckCurrentSamplingRate (newRate);
     if(retVal == eNoErr)
     {
-        retVal = UpdateDeviceInfo (false/*updateSRSupported*/, true/*updateBufferSizes*/);
+        retVal = UpdateDeviceInfo ();
     }
 
     //reactivate it.    
@@ -1759,7 +1732,7 @@ WTErr WCMRCoreAudioDevice::SetActive (bool newState)
         m_DropsReported = 0;
         m_IgnoreThisDrop = true;
 
-        UpdateDeviceInfo(true /*updateSRSupported */, true /* updateBufferSizes#*/);
+        UpdateDeviceInfo();
 
     }
     
@@ -2317,14 +2290,10 @@ OSStatus WCMRCoreAudioDevice::GetStreamLatency(AudioDeviceID device, bool isInpu
 //! \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)
+WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient,
+                            eAudioDeviceFilter eCurAudioDeviceFilter, bool useMultithreading, bool bNocopy)
+  : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter)
   , m_UseMultithreading (useMultithreading)
-  , m_eCABS_Method(eCABS_method)
   , m_bNoCopyAudioBuffer(bNocopy)
 {
     AUTO_FUNC_DEBUG;
@@ -2347,13 +2316,13 @@ WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerCli
     }
 
     //add a listener to find out when devices change...
-    AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, StaticPropertyChangeProc, this);
-
+    AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, DevicePropertyChangeCallback, this);
+    
     //Always add the None device first...
-    m_Devices.push_back (new WCMRNativeAudioNoneDevice(this));
+    m_NoneDevice = new WCMRNativeAudioNoneDevice(this);
 
     //prepare our initial list...
-    UpdateDeviceList_Private();
+    generateDeviceListImpl();
 
     return;
 }
@@ -2376,25 +2345,7 @@ WCMRCoreAudioDeviceManager::~WCMRCoreAudioDeviceManager()
 
     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!
-
+        delete m_NoneDevice;
     }
     catch (...)
     {
@@ -2405,313 +2356,511 @@ WCMRCoreAudioDeviceManager::~WCMRCoreAudioDeviceManager()
 }
 
 
-//**********************************************************************************************
-// 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)
+WCMRAudioDevice* WCMRCoreAudioDeviceManager::initNewCurrentDeviceImpl(const std::string & deviceName)
 {
-    WCMRCoreAudioDeviceManager *pMyManager = (WCMRCoreAudioDeviceManager *)inClientData;
-    
-    if (pMyManager)
-        return pMyManager->PropertyChangeProc (inPropertyID);
-
-    return 0;
+    destroyCurrentDeviceImpl();
+    
+    std::cout << "API::PortAudioDeviceManager::initNewCurrentDevice " << deviceName << std::endl;
+       if (deviceName == m_NoneDevice->DeviceName() )
+       {
+               m_CurrentDevice = m_NoneDevice;
+               return m_CurrentDevice;
+       }
+    
+       DeviceInfo devInfo;
+    WTErr err = GetDeviceInfoByName(deviceName, devInfo);
+    
+       if (eNoErr == err)
+       {
+               try
+               {
+                       std::cout << "API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName << std::endl;
+                       TRACE_MSG ("API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName);
+            
+            m_CurrentDevice = new WCMRCoreAudioDevice (this, devInfo.m_DeviceId, m_UseMultithreading, m_bNoCopyAudioBuffer);
+               }
+               catch (...)
+               {
+                       std::cout << "Unabled to create PA Device: " << devInfo.m_DeviceId << std::endl;
+                       DEBUG_MSG ("Unabled to create PA Device: " << devInfo.m_DeviceId);
+               }
+       }
+    
+       return m_CurrentDevice;
 }
 
 
-
-//**********************************************************************************************
-// 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)
+void WCMRCoreAudioDeviceManager::destroyCurrentDeviceImpl()
 {
-    OSStatus retVal = 0;
-    switch (inPropertyID)
+    if (m_CurrentDevice != m_NoneDevice)
+        delete m_CurrentDevice;
+    
+    m_CurrentDevice = 0;
+}
+    
+    
+WTErr WCMRCoreAudioDeviceManager::getDeviceAvailableSampleRates(DeviceID deviceId, std::vector<int>& sampleRates)
+{
+    AUTO_FUNC_DEBUG;
+    
+    WTErr retVal = eNoErr;
+    OSStatus err = kAudioHardwareNoError;
+    UInt32 propSize = 0;
+    
+    sampleRates.clear();
+    
+    //! 1. Get sample rate property size.
+    err = AudioDeviceGetPropertyInfo(deviceId, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, NULL);
+    if (err == kAudioHardwareNoError)
     {
-    case kAudioHardwarePropertyDevices:
-        m_UpdateDeviceListRequested++;
-        break;
-    default:
-        break;
+        //! 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(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]))
+                    {
+                        sampleRates.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;
 }
-
-//**********************************************************************************************
-// 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)
+    
+    
+WTErr WCMRCoreAudioDeviceManager::getDeviceMaxInputChannels(DeviceID deviceId, unsigned int& inputChannels)
 {
-    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);
+    AUTO_FUNC_DEBUG;
+    WTErr retVal = eNoErr;
+    OSStatus err = kAudioHardwareNoError;
+    UInt32 propSize = 0;
+    inputChannels = 0;
     
-    std::ostringstream stream_str;
-    while (p_splited_orig_str != 0) 
+    // 1. Get property cannels input size.
+    err = AudioDeviceGetPropertyInfo (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 (deviceId, 0, 1/* Input */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers);
+            if (err == kAudioHardwareNoError)
+            {
+                // Calculate the number of input channels
+                for (UInt32 streamIndex = 0; streamIndex < pStreamBuffers->mNumberBuffers; streamIndex++)
+                {
+                    inputChannels += 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
     {
-        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);
+        retVal = eCoreAudioFailed;
+        DEBUG_MSG("Failed to get device Input channels property size. Device Name: " << m_DeviceName.c_str());
     }
-    delete[] orig_c_str;
-    return_str = stream_str.str();
+    
+    return retVal;
 }
+    
 
-
-//**********************************************************************************************
-// 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()
+WTErr WCMRCoreAudioDeviceManager::getDeviceMaxOutputChannels(DeviceID deviceId, unsigned int& outputChannels)
+{
+    AUTO_FUNC_DEBUG;
+    
+    WTErr retVal = eNoErr;
+    OSStatus err = kAudioHardwareNoError;
+    UInt32 propSize = 0;
+    outputChannels = 0;
+    
+    //! 1. Get property cannels output size.
+    err = AudioDeviceGetPropertyInfo (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 (deviceId, 0, 0/* Output */, kAudioDevicePropertyStreamConfiguration, &propSize, pStreamBuffers);
+            if (err == kAudioHardwareNoError)
+            {
+                // Calculate the number of output channels
+                for (UInt32 streamIndex = 0; streamIndex < pStreamBuffers->mNumberBuffers; streamIndex++)
+                {
+                    outputChannels += 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());
+    }
+    return retVal;
+}
+    
+    
+WTErr WCMRCoreAudioDeviceManager::generateDeviceListImpl()
 {
     AUTO_FUNC_DEBUG;
     
+    // lock the list first
+    wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
+    m_DeviceInfoVec.clear();
+    
+    //First, get info from None device which is always present
+    if (m_NoneDevice)
+    {
+        DeviceInfo *pDevInfo = new DeviceInfo(NONE_DEVICE_ID, m_NoneDevice->DeviceName() );
+        pDevInfo->m_AvailableSampleRates = m_NoneDevice->SamplingRates();
+        m_DeviceInfoVec.push_back(pDevInfo);
+    }
     
     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;
     
+    try
+    {
         //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*/)
+        
+        //now add the ones that are not there...
+        for (size_t deviceIndex = 0; deviceIndex < numDevices; deviceIndex++)
         {
-            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++)
+            DeviceInfo* pDevInfo = 0;
+            
+            //Get device name and create new DeviceInfo entry
+            //Get property name size.
+            osErr = AudioDeviceGetPropertyInfo(deviceIDs[deviceIndex], 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL);
+            if (osErr == kAudioHardwareNoError)
             {
-                if (myDeviceID == deviceIDs[reportedDeviceIndex])
+                //Get property: name.
+                char* deviceName = new char[propSize];
+                osErr = AudioDeviceGetProperty(deviceIDs[deviceIndex], 0, 0, kAudioDevicePropertyDeviceName, &propSize, deviceName);
+                if (osErr == kAudioHardwareNoError)
                 {
-                    deviceFound = true;
-                    break;
+                    pDevInfo = new DeviceInfo(deviceIDs[deviceIndex], deviceName);
                 }
-            }
-        
-            if (!deviceFound)
-            {
-                //it's no longer there, need to remove it!
-                WCMRAudioDevice *pTheDeviceToErase = *deviceIter;
-                deviceIter = m_Devices.erase (deviceIter);
-                if (pTheDeviceToErase->Active())
+                else
                 {
-                    NotifyClient (WCMRAudioDeviceManagerClient::DeviceConnectionLost);
+                    retVal = eCoreAudioFailed;
+                    DEBUG_MSG("Failed to get device name. Device ID: " << m_DeviceID);
                 }
-                SAFE_RELEASE (pTheDeviceToErase);
+                
+                delete [] deviceName;
             }
             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;
-                }
+                retVal = eCoreAudioFailed;
+                DEBUG_MSG("Failed to get device name property size. Device ID: " << m_DeviceID);
             }
-        
-            if (!deviceFound)
+            
+            if (pDevInfo)
             {
-                //add it to our list...
-                //build a device object...
-                WCMRCoreAudioDevice *pNewDevice = new WCMRCoreAudioDevice (this, deviceIDs[reportedDeviceIndex], m_UseMultithreading, m_bNoCopyAudioBuffer);
-                bool bDeleteNewDevice = true;
+                //Retrieve all the information we need for the device
+                WTErr wErr = eNoErr;
                 
-                if (pNewDevice)
+                //Get available sample rates for the device
+                std::vector<int> availableSampleRates;
+                wErr = getDeviceAvailableSampleRates(pDevInfo->m_DeviceId, availableSampleRates);
+                
+                if (wErr != eNoErr)
+                {
+                    DEBUG_MSG ("Failed to get device available sample rates. Device ID: " << m_DeviceID);
+                    delete pDevInfo;
+                    continue; //proceed to the next device
+                }
+                
+                pDevInfo->m_AvailableSampleRates = availableSampleRates;
+                
+                //Get max input channels
+                uint32 maxInputChannels;
+                wErr = getDeviceMaxInputChannels(pDevInfo->m_DeviceId, maxInputChannels);
+                
+                if (wErr != eNoErr)
+                {
+                    DEBUG_MSG ("Failed to get device max input channels count. Device ID: " << m_DeviceID);
+                    delete pDevInfo;
+                    continue; //proceed to the next device
+                }
+                
+                pDevInfo->m_MaxInputChannels = maxInputChannels;
+                
+                //Get max output channels
+                uint32 maxOutputChannels;
+                wErr = getDeviceMaxOutputChannels(pDevInfo->m_DeviceId, maxOutputChannels);
+                
+                if (wErr != eNoErr)
+                {
+                    DEBUG_MSG ("Failed to get device max output channels count. Device ID: " << m_DeviceID);
+                    delete pDevInfo;
+                    continue; //proceed to the next device
+                }
+                
+                pDevInfo->m_MaxOutputChannels = maxOutputChannels;
+                
+                //Now check if this device is acceptable according to current input/output settings
+                bool bRejectDevice = false;
+                switch(m_eAudioDeviceFilter)
                 {
-
-                    // 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)
+                        if (pDevInfo->m_MaxInputChannels != 0)
                         {
-                            m_Devices.push_back (pNewDevice);
+                            m_DeviceInfoVec.push_back(pDevInfo);
                         }
                         else
                         {
                             // Delete unnecesarry device
-                            bDeleteNewDevice = true;
+                            bRejectDevice = true;
                         }
                         break;
                     case eOutputOnlyDevices:
-                        if ((int) pNewDevice->OutputChannels().size() != 0)
+                        if (pDevInfo->m_MaxOutputChannels != 0)
                         {
-                            m_Devices.push_back (pNewDevice);
+                            m_DeviceInfoVec.push_back(pDevInfo);
                         }
                         else
                         {
                             // Delete unnecesarry device
-                            bDeleteNewDevice = true;
+                            bRejectDevice = true;
                         }
                         break;
                     case eFullDuplexDevices:
-                        if ((int) pNewDevice->InputChannels().size() != 0 && (int) pNewDevice->OutputChannels().size() != 0)
+                        if (pDevInfo->m_MaxInputChannels != 0 && pDevInfo->m_MaxOutputChannels != 0)
                         {
-                            m_Devices.push_back (pNewDevice);
+                            m_DeviceInfoVec.push_back(pDevInfo);
                         }
                         else
                         {
                             // Delete unnecesarry device
-                            bDeleteNewDevice = true;
+                            bRejectDevice = true;
                         }
                         break;
                     case eAllDevices:
                     default:
-                        m_Devices.push_back (pNewDevice);
+                        m_DeviceInfoVec.push_back(pDevInfo);
                         break;
-                    }
                 }
                 
-                if(bDeleteNewDevice)
+                if(bRejectDevice)
                 {
                     syslog (LOG_NOTICE, "%s rejected, In Channels = %d, Out Channels = %d\n",
-                            pNewDevice->DeviceName().c_str(), (int) pNewDevice->InputChannels().size(),
-                            (int) pNewDevice->OutputChannels().size());
+                            pDevInfo->m_DeviceName.c_str(), pDevInfo->m_MaxInputChannels, pDevInfo->m_MaxOutputChannels);
                     // 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);
+                    delete pDevInfo;
                 }
             }
         }
-    
-
+        
+        
         //If no devices were found, that's not a good thing!
-        if (m_Devices.empty())
+        if (m_DeviceInfoVec.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);
+    
+    delete[] 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 WCMRCoreAudioDeviceManager::updateDeviceListImpl()
 {
-    //WTErr retVal = eNoErr;
+    wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
+    WTErr err = generateDeviceListImpl();
     
+    if (eNoErr != err)
     {
-        //wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+        std::cout << "API::PortAudioDeviceManager::updateDeviceListImpl: Device list update error: "<< err << std::endl;
+        return err;
+    }
+    
+    if (m_CurrentDevice)
+    {
+        // if we have device initialized we should find out if this device is still connected
+        DeviceInfo devInfo;
+        WTErr deviceLookUpErr = GetDeviceInfoByName(m_CurrentDevice->DeviceName(), devInfo );
+    
+        if (eNoErr != deviceLookUpErr)
+        {
+            NotifyClient (WCMRAudioDeviceManagerClient::IODeviceDisconnected);
+            return err;
+        }
+    }
+    
+    NotifyClient (WCMRAudioDeviceManagerClient::DeviceListChanged);
+    
+    return err;
+}
 
-        //If there's something specific to CoreAudio manager idle handling do it here...
-        if (m_UpdateDeviceListRequested != m_UpdateDeviceListProcessed)
+
+WTErr WCMRCoreAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& bufferSizes) const
+{
+    AUTO_FUNC_DEBUG;
+    
+    WTErr retVal = eNoErr;
+    OSStatus err = kAudioHardwareNoError;
+    UInt32 propSize = 0;
+    
+    bufferSizes.clear();
+    
+    //first check if the request has been made for None device
+       if (deviceName == m_NoneDevice->DeviceName() )
+       {
+               bufferSizes = m_NoneDevice->BufferSizes();
+               return retVal;
+       }
+    
+    DeviceInfo devInfo;
+    retVal = GetDeviceInfoByName(deviceName, devInfo);
+    
+    if (eNoErr == retVal)
+    {
+        // 1. Get buffer size range
+        AudioValueRange bufferSizesRange;
+        propSize = sizeof (AudioValueRange);
+        err = AudioDeviceGetProperty (devInfo.m_DeviceId, 0, 0, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &bufferSizesRange);
+        if(err == kAudioHardwareNoError)
         {
-            m_UpdateDeviceListProcessed = m_UpdateDeviceListRequested;
-            UpdateDeviceList_Private();
-            NotifyClient (WCMRAudioDeviceManagerClient::DeviceListChanged);
+            // 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]))
+                {
+                    bufferSizes.push_back (gAllBufferSizes[bsize]);
+                }
+            }
+            
+            //if we didn't get a single hit, let's simply add the min. and the max...
+            if (bufferSizes.empty())
+            {
+                bufferSizes.push_back ((int)bufferSizesRange.mMinimum);
+                bufferSizes.push_back ((int)bufferSizesRange.mMaximum);
+            }
+        }
+        else
+        {
+            retVal = eCoreAudioFailed;
+            DEBUG_MSG("Failed to get device buffer sizes range. Device Name: " << m_DeviceName.c_str());
         }
-    }   
+    }
+    else
+       {
+               retVal = eRMResNotFound;
+               std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl;
+       }
 
-    //Note that the superclass is going to call all the devices' DoIdle() anyway...
-    return (WCMRAudioDeviceManager::DoIdle());
+    
+    return retVal;
 }
 
+
+OSStatus WCMRCoreAudioDeviceManager::DevicePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData)
+{
+    switch (inPropertyID)
+    {
+        case kAudioHardwarePropertyDevices:
+            {
+                WCMRCoreAudioDeviceManager* pManager = (WCMRCoreAudioDeviceManager*)inClientData;
+                if (pManager)
+                    pManager->updateDeviceListImpl();
+            }
+            break;
+        default:
+            break;
+    }
+    
+    return 0;
+}
index 96d2a9d70ec13941a4c947259aa650a8978674c2..5cfbedb9c9a7c0ec79d91814748e4407c50f3df6 100644 (file)
@@ -1,23 +1,6 @@
-/*
-    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.
-
-*/
 //----------------------------------------------------------------------------------
 //
+// Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
 //
 //! \file      WCMRCoreAudioDeviceManager.h
 //!
@@ -138,7 +121,7 @@ protected:
        uint32_t m_NextSampleToUse;
 #endif //WV_USE_TONE_GEN
        
-       WTErr UpdateDeviceInfo (bool updateSRSupported, bool updateBufferSizes);
+       WTErr UpdateDeviceInfo ();
        WTErr UpdateDeviceName();
        WTErr UpdateDeviceInputs();
        WTErr UpdateDeviceOutputs();
@@ -181,40 +164,28 @@ class WCMRCoreAudioDeviceManager : public WCMRAudioDeviceManager
 public:
 
        WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter,
-               bool useMultithreading = true, eCABS_Method eCABS_method = eCABS_Simple, bool bNocopy = false); ///< constructor
+               bool useMultithreading = true, 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.
+    static OSStatus DevicePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData);
+    
+    virtual WCMRAudioDevice*   initNewCurrentDeviceImpl(const std::string & deviceName);
+       virtual void                            destroyCurrentDeviceImpl();
+       virtual WTErr                           generateDeviceListImpl();
+    virtual WTErr                              updateDeviceListImpl();
+       virtual WTErr                           getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& bufferSizes) const;
+    
        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);
+           
+private:
+    // helper functions for this class only
+    WTErr getDeviceAvailableSampleRates(DeviceID deviceId, std::vector<int>& sampleRates);
+    WTErr getDeviceMaxInputChannels(DeviceID deviceId, unsigned int& inputChannels);
+    WTErr getDeviceMaxOutputChannels(DeviceID deviceId, unsigned int& outputChannels);
+    
+    WCMRAudioDevice*                   m_NoneDevice;
 };
 
 #endif //#ifndef __WCMRCoreAudioDeviceManager_h_
index 0cba7ee851465156324e19991def8c9766734d83..b04bb7ab71867005099d9ae21a1e3e0f8c62a48b 100644 (file)
@@ -1,23 +1,6 @@
-/*
-    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.
-
-*/
 //----------------------------------------------------------------------------------
 //
+// Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
 //
 //! \file      WCMRNativeAudio.cpp
 //!
@@ -136,6 +119,12 @@ WTErr WCMRNativeAudioNoneDevice::SetCurrentBufferSize (int newSize)
 }
 
 
+WTErr WCMRNativeAudioNoneDevice::UpdateDeviceInfo ()
+{
+       return eNoErr;
+}
+
+
 WTErr WCMRNativeAudioNoneDevice::SetStreaming (bool newState)
 {
        if (Streaming() == newState)
@@ -144,7 +133,8 @@ WTErr WCMRNativeAudioNoneDevice::SetStreaming (bool newState)
        }
 
        WCMRAudioDevice::SetStreaming(newState);
-       if(Streaming())
+
+       if (Streaming())
        {
                if (m_SilenceThread)
                        std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the inactive NONE-DEVICE was streaming!" << std::endl;
index dc350ff6be413377ad3cc109b37cc09a950feee0..75c5e1430c9e91567d3f7210096e286f2d7d2e63 100644 (file)
@@ -1,23 +1,6 @@
-/*
-    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.
-
-*/
 //----------------------------------------------------------------------------------
 //
+// Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
 //
 //! \file      WCMRNativeAudio.h
 //!
@@ -42,9 +25,10 @@ class WCMRNativeAudioDevice : public WCMRAudioDevice
 {
 public:
 
-       WCMRNativeAudioDevice (WCMRAudioDeviceManager *pManager, bool useMultithreading = true, bool bNoCopy = false) : WCMRAudioDevice (pManager), 
-               m_UseMultithreading (useMultithreading),
-        m_bNoCopyAudioBuffer(bNoCopy)
+       WCMRNativeAudioDevice (WCMRAudioDeviceManager *pManager, bool useMultithreading = true, bool bNoCopy = false) :
+               WCMRAudioDevice (pManager)
+               , m_UseMultithreading (useMultithreading)
+        , m_bNoCopyAudioBuffer(bNoCopy)
                {}
        virtual ~WCMRNativeAudioDevice () {}
 
@@ -52,7 +36,6 @@ 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.
 
-
 };
 
 
@@ -65,6 +48,7 @@ public:
        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!
+       virtual WTErr UpdateDeviceInfo ();
 
 private:
 
@@ -75,11 +59,11 @@ private:
 #else
        inline void _usleep(uint64_t usec) { ::usleep(usec); }
 #endif
-    static const size_t __m_NumInputChannels = 32;
-    static const size_t __m_NumOutputChannels = 32;
+    static const size_t __m_NumInputChannels = 0;
+    static const size_t __m_NumOutputChannels = 0;
        pthread_t m_SilenceThread;
-    float *_m_inputBuffer;\r
-    float *_m_outputBuffer;\r
+    float *_m_inputBuffer;
+    float *_m_outputBuffer;
     static uint64_t __get_time_nanos ();
 #if defined (_WINDOWS)
        HANDLE _waitableTimerForUsleep;
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.cpp b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.cpp
new file mode 100644 (file)
index 0000000..2f6cd71
--- /dev/null
@@ -0,0 +1,1697 @@
+//----------------------------------------------------------------------------------
+//
+// Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
+//
+//! \file      WCMRPortAudioDeviceManager.cpp
+//!
+//! WCMRPortAudioDeviceManager and related class declarations
+//!
+//---------------------------------------------------------------------------------*/
+#include "WCMRPortAudioDeviceManager.h"
+#include "MiscUtils/safe_delete.h"
+#include "UMicroseconds.h"
+#include <sstream>
+#include <algorithm>
+using namespace wvNS;
+#include "IncludeWindows.h"
+#include <MMSystem.h>
+#include "pa_asio.h"
+#include "asio.h"
+
+///< 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
+       };
+       
+
+///< The default SR.
+static const int DEFAULT_SR = 44100;
+///< The default buffer size.
+static const int DEFAULT_BUFFERSIZE = 128;
+
+static const int NONE_DEVICE_ID = -1;
+
+///< Number of stalls to wait before notifying user...
+static const int NUM_STALLS_FOR_NOTIFICATION = 100; // 100 corresponds to 100 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 HUNDRED_NANO_TO_MILLI_CONSTANT 10000
+#define CONSUMPTION_CALCULATION_INTERVAL 500 // Milli Seconds
+
+
+// This wrapper is used to adapt device DoIdle method as entry point for MS thread
+DWORD WINAPI WCMRPortAudioDevice::__DoIdle__(LPVOID lpThreadParameter)
+{
+       WCMRPortAudioDevice* pDevice = (WCMRPortAudioDevice*)lpThreadParameter;
+       pDevice->DoIdle();
+       return 0;
+}
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::WCMRPortAudioDevice 
+//
+//! Constructor for the audio device. Opens the PA device
+//! and gets information about the device.
+//! Starts the thread which will process requests to this 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.
+//! 
+//**********************************************************************************************
+WCMRPortAudioDevice::WCMRPortAudioDevice (WCMRPortAudioDeviceManager *pManager, unsigned int deviceID, bool useMultithreading, bool bNoCopy) :
+       WCMRNativeAudioDevice (pManager, useMultithreading, bNoCopy)
+       , m_SampleCounter(0)
+       , m_BufferSizeChangeRequested (0)
+       , m_BufferSizeChangeReported (0)
+       , m_ResetRequested (0)
+       , m_ResetReported (0)
+       , m_ResyncRequested (0)
+       , m_ResyncReported (0)
+       , m_DropsDetected(0)
+       , m_DropsReported(0)
+       , m_IgnoreThisDrop(true)
+       , m_hDeviceProcessingThread(NULL)
+       , m_DeviceProcessingThreadID(0)
+       , m_hUpdateDeviceInfoRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hUpdateDeviceInfoDone(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hActivateRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hActivationDone(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hDeActivateRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hDeActivationDone(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hStartStreamingRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hStartStreamingDone(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hStopStreamingRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hStopStreamingDone(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hResetRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hResetDone(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hResetFromDevRequestedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hBufferSizeChangedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hSampleRateChangedEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hExitIdleThread(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_hDeviceInitialized(CreateEvent(NULL, FALSE, FALSE, NULL))
+       , m_lastErr(eNoErr)
+{
+    AUTO_FUNC_DEBUG;
+
+       //Set initial device info...
+       m_DeviceID = deviceID;
+       m_PortAudioStream = NULL;
+       m_CurrentSamplingRate = DEFAULT_SR;
+       m_CurrentBufferSize = DEFAULT_BUFFERSIZE;
+       m_StopRequested = true;
+       m_pInputData = NULL;
+
+       //initialize device processing thread
+       //the divice become alive and now is able to process requests
+       m_hDeviceProcessingThread = CreateThread( NULL, 0, __DoIdle__, (LPVOID)this, 0, &m_DeviceProcessingThreadID );
+
+       if (!m_hDeviceProcessingThread)
+       {
+               DEBUG_MSG("API::Device " << m_DeviceName << " cannot create processing thread");
+               throw eGenericErr;
+       }
+
+       WaitForSingleObject(m_hDeviceInitialized, INFINITE);
+
+       if (ConnectionStatus() == DeviceErrors)
+       {
+               throw m_lastErr;
+       }
+}
+
+
+void WCMRPortAudioDevice::initDevice()
+{
+       // Initialize COM for this thread
+       std::cout << "API::Device " << m_DeviceID << " initializing COM" << std::endl;
+
+       if (S_OK == CoInitialize(NULL) )
+       {
+               // Initialize PA
+               Pa_Initialize();
+
+               updateDeviceInfo();
+
+               //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];
+                       }
+               }
+               else
+                       std::cout << "API::Device " << m_DeviceName << " Device does not support any sample rate of ours" << std::endl;
+       
+               //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);
+               }
+
+               std::cout << "API::Device " << m_DeviceName << " Device has been initialized" << std::endl;
+               m_ConnectionStatus = DeviceDisconnected;
+               m_lastErr = eNoErr;
+       }
+       else
+       {
+               /*Replace with debug trace*/std::cout << "API::Device " << m_DeviceName << " cannot initialize COM" << std::endl;
+               DEBUG_MSG("Device " << m_DeviceName << " cannot initialize COM");
+               m_ConnectionStatus = DeviceErrors;
+               m_lastErr = eSomeThingNotInitailzed;
+               SetEvent(m_hExitIdleThread);
+       }
+
+       SetEvent(m_hDeviceInitialized);
+}
+
+void WCMRPortAudioDevice::terminateDevice()
+{
+       std::cout << "API::Device " << m_DeviceName << " Terminating DEVICE" << std::endl;
+
+       //If device is streaming, need to stop it!
+       if (Streaming())
+       {
+               stopStreaming();
+       }
+               
+       //If device is active (meaning stream is open) we need to close it.
+       if (Active())
+       {
+               deactivateDevice();
+       }
+
+       std::cout << "API::Device " << m_DeviceName << " Terminating PA" << std::endl;
+
+       //Deinitialize PA
+       Pa_Terminate();
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::~WCMRPortAudioDevice 
+//
+//! 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.
+//! 
+//**********************************************************************************************
+WCMRPortAudioDevice::~WCMRPortAudioDevice ()
+{
+    AUTO_FUNC_DEBUG;
+
+       std::cout << "API::Destroying Device Instance: " << DeviceName() << std::endl;
+       try
+       {
+               //Stop deviceprocessing thread
+               SignalObjectAndWait(m_hExitIdleThread, m_hDeviceProcessingThread, INFINITE, false);
+
+               std::cout << "API::Device " << m_DeviceName << " Processing Thread is stopped" << std::endl;
+
+               CloseHandle(m_hDeviceProcessingThread);
+
+               //Now it's safe to free all event handlers
+               CloseHandle(m_hUpdateDeviceInfoRequestedEvent);
+               CloseHandle(m_hUpdateDeviceInfoDone);
+               CloseHandle(m_hActivateRequestedEvent);
+               CloseHandle(m_hActivationDone);
+               CloseHandle(m_hDeActivateRequestedEvent);
+               CloseHandle(m_hDeActivationDone);
+               CloseHandle(m_hStartStreamingRequestedEvent);
+               CloseHandle(m_hStartStreamingDone);
+               CloseHandle(m_hStopStreamingRequestedEvent);
+               CloseHandle(m_hStopStreamingDone);
+               CloseHandle(m_hResetRequestedEvent);
+               CloseHandle(m_hResetDone);
+               CloseHandle(m_hResetFromDevRequestedEvent);
+               CloseHandle(m_hBufferSizeChangedEvent);
+               CloseHandle(m_hSampleRateChangedEvent);
+               CloseHandle(m_hExitIdleThread);
+               CloseHandle(m_hDeviceInitialized);
+       }
+       catch (...)
+       {
+               //destructors should absorb exceptions, no harm in logging though!!
+               DEBUG_MSG ("Exception during destructor");
+       }
+}
+
+
+WTErr WCMRPortAudioDevice::UpdateDeviceInfo ()
+{
+       std::cout << "API::Device (ID:)" << m_DeviceID << " Updating device info" << std::endl;
+       
+       SignalObjectAndWait(m_hUpdateDeviceInfoRequestedEvent, m_hUpdateDeviceInfoDone, INFINITE, false);
+
+       return eNoErr;
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::updateDeviceInfo 
+//
+//! Must be called be device processing thread
+//! Updates Device Information about channels, sampling rates, buffer sizes.
+//!
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+void WCMRPortAudioDevice::updateDeviceInfo (bool callerIsWaiting/*=false*/)
+{
+    AUTO_FUNC_DEBUG;
+
+       //get device info
+       const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
+       
+       //update name.
+       m_DeviceName = pDeviceInfo->name;
+
+       std::cout << "API::Device " << m_DeviceName << " Getting device info " << std::endl;
+
+       //following parameters are needed opening test stream and for sample rates validation
+       PaStreamParameters inputParameters, outputParameters;
+       PaStreamParameters *pInS = NULL, *pOutS = NULL;
+
+       inputParameters.device = m_DeviceID;
+       inputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxInputChannels);
+       inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
+       inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+       inputParameters.hostApiSpecificStreamInfo = 0;
+
+       if (inputParameters.channelCount)
+               pInS = &inputParameters;
+
+       outputParameters.device = m_DeviceID;
+       outputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxOutputChannels);
+       outputParameters.sampleFormat = paFloat32;
+       outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+       outputParameters.hostApiSpecificStreamInfo = 0;
+
+       if (outputParameters.channelCount)
+               pOutS = &outputParameters;
+
+       std::cout << "API::Device" << m_DeviceName << " Updating sample rates " << std::endl;
+       ////////////////////////////////////////////////////////////////////////////////////
+       //update list of supported SRs...
+       m_SamplingRates.clear();
+               
+       // now iterate through our standard SRs and check if they are supported by device
+       // store them for this device
+       for(int sr=0; gAllSampleRates[sr] > 0; sr++)
+       {
+               PaError err = Pa_IsFormatSupported(pInS, pOutS, gAllSampleRates[sr]);
+               if( err == paFormatIsSupported)
+               {
+                       m_SamplingRates.push_back ((int)gAllSampleRates[sr]);
+               }
+       }
+
+       std::cout << "API::Device" << m_DeviceName << " Updating buffer sizes" << std::endl;
+       ///////////////////////////////////////////////////////////////////////////////////
+       //update buffer sizes
+       m_BufferSizes.clear();
+       bool useDefaultBuffers = true;
+       PaError paErr = paNoError;
+
+       //sometimes devices change buffer size if sample rate changes
+       //it updates buffer size during stream opening
+       //we need to find out how device would behave with current sample rate
+       //try opening test stream to load device driver for current sample rate and buffer size
+       //(skip this step if the device is Active)
+       if ( !Active() )
+       {
+               if (paNoError != testStateValidness(m_CurrentSamplingRate, m_CurrentBufferSize) )
+               {
+                       //buffer size did change
+                       Pa_Terminate();
+                       Pa_Initialize();
+
+                       // test validness with current sample rate and device prefered buffer size
+                       paErr = testStateValidness(m_CurrentSamplingRate, 0);
+               }
+       }
+
+       if (paErr == paNoError)
+       {
+               // In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel 
+               long minSize, maxSize, preferredSize, granularity;
+               paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
+       
+               if (paErr == paNoError)
+               {
+                       std::cout << "API::Device " << m_DeviceName << " Buffers: " << minSize << " " << maxSize << " " << preferredSize << std::endl;
+                       
+                       m_BufferSizes.push_back (preferredSize);
+                       useDefaultBuffers = false;
+               }
+               else
+               {
+                       std::cout << "API::Device" << m_DeviceName << " Preffered buffer size is not supported" << std::endl;
+               }
+       }
+       else
+       {
+               std::cout << "API::Device" << m_DeviceName << " Device does not start with sample rate: "<< m_CurrentSamplingRate << " and default buffer size" << std::endl;
+       }
+
+       if (useDefaultBuffers)
+       {
+               std::cout << "API::Device" << m_DeviceName << " Using default buffer sizes " <<std::endl;
+               for(int bsize=0; bsize < (sizeof(gAllBufferSizes)/sizeof(gAllBufferSizes[0])); bsize++)
+                       m_BufferSizes.push_back (gAllBufferSizes[bsize]);
+       }
+
+       /////////////////////////////////////////////////////////////////////////////////////////
+       //update channels info
+       {
+               int maxInputChannels = pDeviceInfo->maxInputChannels;
+               int maxOutputChannels = pDeviceInfo->maxOutputChannels;
+
+               //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());
+               }
+       
+       
+               //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());
+               }
+       }
+
+       std::cout << "API::Device" << m_DeviceName << " Device info update has been finished" << std::endl;
+
+       if (callerIsWaiting)
+               SetEvent(m_hUpdateDeviceInfoDone);
+}
+
+
+PaError WCMRPortAudioDevice::testStateValidness(int sampleRate, int bufferSize)
+{
+       PaError paErr = paNoError;
+
+       //get device info
+       const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
+
+       //following parameters are needed opening test stream and for sample rates validation
+       PaStreamParameters inputParameters, outputParameters;
+       PaStreamParameters *pInS = NULL, *pOutS = NULL;
+
+       inputParameters.device = m_DeviceID;
+       inputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxInputChannels);
+       inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
+       inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+       inputParameters.hostApiSpecificStreamInfo = 0;
+
+       if (inputParameters.channelCount)
+               pInS = &inputParameters;
+
+       outputParameters.device = m_DeviceID;
+       outputParameters.channelCount = std::min<int>(2, pDeviceInfo->maxOutputChannels);
+       outputParameters.sampleFormat = paFloat32;
+       outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+       outputParameters.hostApiSpecificStreamInfo = 0;
+
+       if (outputParameters.channelCount)
+               pOutS = &outputParameters;
+
+       PaStream *portAudioStream = NULL;
+               
+       //sometimes devices change buffer size if sample rate changes
+       //it updates buffer size during stream opening
+       //we need to find out how device would behave with current sample rate
+       //try opening test stream to load device driver for current sample rate and buffer size
+       paErr = Pa_OpenStream (&portAudioStream, pInS, pOutS, m_CurrentSamplingRate, m_CurrentBufferSize, paDitherOff, NULL, NULL);
+       
+       if (portAudioStream)
+       {
+               // close test stream
+               Pa_CloseStream (portAudioStream);
+               portAudioStream = NULL;
+       }
+
+       return paErr;
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::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 WCMRPortAudioDevice::CurrentSamplingRate ()
+{
+    AUTO_FUNC_DEBUG;
+       //ToDo: Perhaps for ASIO devices that are active, we should retrive the SR from the device...
+       
+       return (m_CurrentSamplingRate);
+}
+
+
+WTErr WCMRPortAudioDevice::SetActive (bool newState)
+{
+       if (newState == true)
+       {
+               std::cout << "API::Device " << m_DeviceName << " Activation requested" << std::endl;
+               SignalObjectAndWait(m_hActivateRequestedEvent, m_hActivationDone, INFINITE, false);
+       }
+       else
+       {
+               std::cout << "API::Device " << m_DeviceName << " Deactivation requested" << std::endl;
+               SignalObjectAndWait(m_hDeActivateRequestedEvent, m_hDeActivationDone, INFINITE, false);
+       }
+
+       if (newState == Active() )
+               return eNoErr;
+       else
+               return eGenericErr;
+}
+
+
+WTErr WCMRPortAudioDevice::SetStreaming (bool newState)
+{
+       if (newState == true)
+       {
+               std::cout << "API::Device " << m_DeviceName << " Stream start requested" << std::endl;
+               SignalObjectAndWait(m_hStartStreamingRequestedEvent, m_hStartStreamingDone, INFINITE, false);
+       }
+       else
+       {
+               std::cout << "API::Device " << m_DeviceName << " Stream stop requested" << std::endl;
+               SignalObjectAndWait(m_hStopStreamingRequestedEvent, m_hStopStreamingDone, INFINITE, false);
+       }
+
+       if (newState == Streaming() )
+               return eNoErr;
+       else
+               return eGenericErr;
+}
+
+
+WTErr WCMRPortAudioDevice::ResetDevice()
+{
+       std::cout << "API::Device: " << m_DeviceName << " Reseting device" << std::endl;
+       
+       SignalObjectAndWait(m_hResetRequestedEvent, m_hResetDone, INFINITE, false);
+
+       if (ConnectionStatus() == DeviceErrors)
+       {
+               return m_lastErr;
+       }
+
+       return eNoErr;
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::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 WCMRPortAudioDevice::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)
+               return (retVal);
+
+       //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;
+               return (retVal);
+       }
+       
+       if (Streaming())
+       {
+               //Can't change, perhaps use an "in use" type of error
+               retVal = eGenericErr;
+               return (retVal);
+       }
+       
+       if (oldActive)
+       {
+               //Deactivate it for the change...
+               SetActive (false);
+       }
+       
+       //make the change...
+       m_CurrentSamplingRate = newRate;
+
+       // Before reactivating the device: opening stream we should try getting buffer size update from the device
+       // because for new sampling rate some devices may change buffer size as well
+       int oldBufferSize = m_CurrentBufferSize;
+       
+       retVal = ResetDevice();
+
+       //reactivate it.        
+       if (oldActive && retVal == eNoErr)
+       {
+               retVal = SetActive (true);
+       }
+
+       if (retVal != eNoErr)
+       {
+               //revert changes if the device was not activated
+               m_CurrentSamplingRate = oldRate;
+               m_CurrentBufferSize = oldBufferSize;
+               int bufferSize = m_CurrentBufferSize;
+               m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
+               retVal = eCommandLineParameter;
+       }
+       
+       return (retVal);
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::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 WCMRPortAudioDevice::CurrentBufferSize ()
+{
+       return m_CurrentBufferSize;
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::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 WCMRPortAudioDevice::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)
+               return (retVal);
+       
+       //see if this is one of our supported rates...
+       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
+               retVal = eCommandLineParameter;
+               return (retVal);
+       }
+       
+       if (Streaming())
+       {
+               //Can't change, perhaps use an "in use" type of error
+               retVal = eGenericErr;
+               return (retVal);
+       }
+       
+       if (oldActive)
+       {
+               //Deactivate it for the change...
+               SetActive (false);
+       }
+       
+       //make the change...
+       m_CurrentBufferSize = newSize;
+
+       //reactivate it.        
+       if (oldActive)
+       {
+               retVal = SetActive (true);
+       }
+
+       return (retVal);
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::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.
+//! 
+//**********************************************************************************************
+WCMRPortAudioDevice::ConnectionStates WCMRPortAudioDevice::ConnectionStatus ()
+{
+    AUTO_FUNC_DEBUG;
+       //ToDo: May want to do something more to extract the actual status!
+       return (m_ConnectionStatus);
+       
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::activateDevice
+//
+//!    IS CALLED BY PROCESS THREAD
+//! Sets the device into "active" state. Essentially, opens the PA device. 
+//!            If it's an ASIO device it may result in buffer size change in some cases.
+//!
+//**********************************************************************************************
+void WCMRPortAudioDevice::activateDevice (bool callerIsWaiting/*=false*/)
+{
+       AUTO_FUNC_DEBUG;
+
+       PaError paErr = paNoError;
+       
+       // if device is not active activate it
+       if (!Active() )
+       {
+               PaStreamParameters inputParameters, outputParameters;
+               PaStreamParameters *pInS = NULL, *pOutS = NULL;
+
+               const PaDeviceInfo *pDeviceInfo = Pa_GetDeviceInfo(m_DeviceID);
+               const PaHostApiInfo *pHostApiInfo = Pa_GetHostApiInfo(pDeviceInfo->hostApi);
+
+               inputParameters.device = m_DeviceID;
+               inputParameters.channelCount = (int)m_InputChannels.size();
+               inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
+               inputParameters.suggestedLatency = Pa_GetDeviceInfo(m_DeviceID)->defaultLowInputLatency;
+               inputParameters.hostApiSpecificStreamInfo = 0;
+
+               if (inputParameters.channelCount)
+                       pInS = &inputParameters;
+
+               outputParameters.device = m_DeviceID;
+               outputParameters.channelCount = (int)m_OutputChannels.size();
+               outputParameters.sampleFormat = paFloat32;
+               outputParameters.suggestedLatency = Pa_GetDeviceInfo(m_DeviceID)->defaultLowOutputLatency;
+               outputParameters.hostApiSpecificStreamInfo = 0;
+
+               if (outputParameters.channelCount)
+                       pOutS = &outputParameters;
+               
+               std::cout << "API::Device" << m_DeviceName << " Opening device stream " << std::endl;
+               std::cout << "Sample rate: " << m_CurrentSamplingRate << " buffer size: " << m_CurrentBufferSize << std::endl;
+               paErr = Pa_OpenStream(&m_PortAudioStream, 
+                                                         pInS,
+                                                         pOutS,
+                                                         m_CurrentSamplingRate,
+                                                         m_CurrentBufferSize,
+                                                         paDitherOff,
+                                                         WCMRPortAudioDevice::TheCallback,
+                                                         this);
+
+               if(paErr == paNoError)
+               {
+                       m_DropsDetected = 0;
+                       m_DropsReported = 0;
+                       m_IgnoreThisDrop = true;
+
+                       if (pHostApiInfo->type == paASIO)
+                       {
+                               m_BufferSizeChangeRequested = 0;
+                               m_BufferSizeChangeReported = 0;
+                               m_ResetRequested = 0;
+                               m_ResetReported = 0;
+                               m_ResyncRequested = 0;
+                               m_ResyncReported = 0;
+                               PaAsio_SetMessageHook (StaticASIOMessageHook, this);
+                       }
+                       m_IsActive = true;
+                       m_ConnectionStatus = DeviceAvailable;
+                       m_lastErr = eNoErr;
+               }
+               else
+               {
+                       //failed, do not update device state
+                       std::cout << "Failed to open pa stream stream " << paErr << std::endl;
+                       DEBUG_MSG( "Failed to open pa stream stream " << paErr );
+                       m_ConnectionStatus = DeviceErrors;
+                       m_lastErr = eAsioFailed;
+               }
+
+       
+       }
+
+       if (callerIsWaiting)
+               SetEvent(m_hActivationDone);
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::deactivateDevice
+//
+//!    IS CALLED BY PROCESS THREAD
+//! Sets the device into "inactive" state. Essentially, closes the PA device. 
+//!
+//**********************************************************************************************
+void WCMRPortAudioDevice::deactivateDevice (bool callerIsWaiting/*=false*/)
+{
+    AUTO_FUNC_DEBUG;
+
+       PaError paErr = paNoError;
+       
+       if (Active() )
+       {
+               if (Streaming())
+               {
+                       stopStreaming ();
+               }
+               
+               if (m_PortAudioStream)
+               {
+                       //close the stream first
+                       std::cout << "API::Device" << m_DeviceName << " Closing device stream" << std::endl;
+                       paErr = Pa_CloseStream (m_PortAudioStream);
+                       if(paErr == paNoError)
+                       {
+                               m_PortAudioStream = NULL;
+                               m_DropsDetected = 0;
+                               m_DropsReported = 0;
+                               m_IgnoreThisDrop = true;
+                               m_BufferSizeChangeRequested = 0;
+                               m_BufferSizeChangeReported = 0;
+                               m_ResetRequested = 0;
+                               m_ResetReported = 0;
+                               m_ResyncRequested = 0;
+                               m_ResyncReported = 0;
+                               PaAsio_SetMessageHook (NULL, NULL);
+
+                               //finaly set device state to "not active"
+                               m_IsActive = false;
+                               m_ConnectionStatus = DeviceDisconnected;
+                               m_lastErr = eNoErr;
+                       }
+                       else
+                       {
+                               //failed, do not update device state
+                               std::cout << "Failed to close pa stream stream " << paErr << std::endl;
+                               DEBUG_MSG( "Failed to open pa stream stream " << paErr );
+                               m_ConnectionStatus = DeviceErrors;
+                               m_lastErr = eAsioFailed;
+                       }
+               }
+       }
+
+       if (callerIsWaiting)
+               SetEvent(m_hDeActivationDone);
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::startStreaming
+//
+//! Sets the devices into "streaming" state. Calls PA's Start stream routines.
+//! This roughly corresponds to calling Start on the lower level interface.
+//! 
+//**********************************************************************************************
+void WCMRPortAudioDevice::startStreaming (bool callerIsWaiting/*=false*/)
+{
+    AUTO_FUNC_DEBUG;
+
+       // proceed if the device is not streaming
+       if (!Streaming () )
+       {
+               PaError paErr = paNoError;
+               m_StopRequested = false;
+               m_SampleCounter = 0;
+
+               std::cout << "API::Device" << m_DeviceName << " Starting device stream" << std::endl;
+               paErr = Pa_StartStream( m_PortAudioStream );
+
+               if(paErr == paNoError)
+               {
+                       // if the stream was started successfully
+                       m_IsStreaming = true;
+               }
+               else
+               {
+                       std::cout << "Failed to start PA stream: " << paErr << std::endl;
+                       DEBUG_MSG( "Failed to start PA stream: " << paErr );
+                       m_lastErr = eGenericErr;
+               }
+       }
+               
+       if (callerIsWaiting)
+               SetEvent(m_hStartStreamingDone);
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::stopStreaming
+//
+//! Sets the devices into "not streaming" state. Calls PA's Stop stream routines.
+//! This roughly corresponds to calling Stop on the lower level interface.
+//! 
+//**********************************************************************************************
+void WCMRPortAudioDevice::stopStreaming (bool callerIsWaiting/*=false*/)
+{
+    AUTO_FUNC_DEBUG;
+
+       // proceed if the device is streaming
+       if (Streaming () )
+       {
+               PaError paErr = paNoError;
+               m_StopRequested = true;
+
+               std::cout << "API::Device " << m_DeviceName << " Stopping device stream" << std::endl;
+               paErr = Pa_StopStream( m_PortAudioStream );
+
+               if(paErr == paNoError)
+               {
+                       // if the stream was stopped successfully
+                       m_IsStreaming = false;
+                       m_pInputData = NULL;
+               }
+               else
+               {
+                       std::cout << "Failed to stop PA stream: " << paErr << std::endl;
+                       DEBUG_MSG( "Failed to stop PA stream " << paErr );
+                       m_lastErr = eGenericErr;
+               }
+       }
+
+       if (callerIsWaiting)
+               SetEvent(m_hStopStreamingDone);
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::resetDevice 
+//
+//! Resets the device, updates device info. Importnat: does PA reinitialization calling
+//! Pa_terminate/Pa_initialize functions.
+//!
+//! \param none
+//! 
+//! \return nothing
+//! 
+//**********************************************************************************************
+void WCMRPortAudioDevice::resetDevice (bool callerIsWaiting /*=false*/ )
+{
+       std::cout << "API::Device" << m_DeviceName << "Reseting device" << std::endl;
+
+       // Keep device sates
+       bool wasStreaming = Streaming();
+       bool wasActive = Active();
+
+       // Notify the Application about reset
+       m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::RequestReset);
+
+       // Reset the device
+       stopStreaming();
+       deactivateDevice();
+
+       // Reinitialize PA
+       Pa_Terminate();
+       Pa_Initialize();
+
+       updateDeviceInfo();
+
+       // Cache device buffer size as it might be changed during reset
+       int oldBufferSize = m_CurrentBufferSize;
+
+       // In ASIO Windows, the buffer size is set from the sound device manufacturer's control panel
+       // Backend should always use preffered buffer size value in this case
+       long minSize, maxSize, preferredSize, granularity;
+       PaError paErr = PaAsio_GetAvailableBufferSizes(m_DeviceID, &minSize, &maxSize, &preferredSize, &granularity);
+
+       if (paErr == paNoError)
+       {
+               m_CurrentBufferSize = preferredSize;
+       }
+       else
+       {
+               // if we can't get device buffer sizes, use the first one among supported
+               if (m_BufferSizes.size() != 0)
+                       m_CurrentBufferSize = m_BufferSizes.front();
+       }
+
+       // Notify the Application about device setting changes
+       if (oldBufferSize != m_CurrentBufferSize)
+       {
+               std::cout << "API::Device" << m_DeviceName << " buffer size changed" << std::endl;
+               int bufferSize = m_CurrentBufferSize;
+               m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged, (void *)&bufferSize);
+       }
+
+       // Activate the device if it was active before
+       if (wasActive)
+               activateDevice();
+
+       // Resume streaming if the device was streaming before
+       if(wasStreaming)
+       {
+               // Notify the Application to prepare for the stream start
+               m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::DeviceStartsStreaming);
+               startStreaming();
+       }
+
+       if (callerIsWaiting)
+               SetEvent(m_hResetDone);
+}
+
+
+#ifdef _WINDOWS
+
+long WCMRPortAudioDevice::StaticASIOMessageHook (void *pRefCon, long selector, long value, void* message, double* opt)
+{
+       if (pRefCon)
+       {
+               return ((WCMRPortAudioDevice*)(pRefCon))->ASIOMessageHook (selector, value, message, opt);
+       }
+       else
+               return -1;
+}
+
+long WCMRPortAudioDevice::ASIOMessageHook (long selector, long WCUNUSEDPARAM(value), void* WCUNUSEDPARAM(message), double* WCUNUSEDPARAM(opt))
+{
+       switch(selector)
+       {
+               case kAsioBufferSizeChange:
+                       m_BufferSizeChangeRequested++;
+                       std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- m_BufferSizeChangeRequested" << std::endl;
+                       SetEvent(m_hBufferSizeChangedEvent);
+                       break;
+
+               case kAsioResetRequest:
+                       m_ResetRequested++;
+                       std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResetRequest" << std::endl;
+                       SetEvent(m_hResetFromDevRequestedEvent);
+                       break;
+
+               case kAsioResyncRequest:
+                       std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioResyncRequest" << std::endl;
+                       m_ResyncRequested++;
+                       break;
+
+               case kAsioLatenciesChanged:
+                       std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioLatenciesChanged" << std::endl;
+                       SetEvent(m_hBufferSizeChangedEvent);
+                       m_BufferSizeChangeRequested++;
+                       break;
+
+        case kAsioOverload:
+                       std::cout << "\t\t\tWCMRPortAudioDevice::ASIOMessageHook -- kAsioOverload" << std::endl;
+            m_DropsDetected++;
+            break;
+       }
+       return 0;
+}
+
+#endif
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::DoIdle 
+//
+//! A place for doing idle time processing. The other derived classes will probably do something
+//!            meaningful.
+//!
+//! \param none
+//! 
+//! \return eNoErr always.
+//! 
+//**********************************************************************************************
+WTErr WCMRPortAudioDevice::DoIdle ()
+{
+       WTErr retVal = eNoErr;
+
+       std::cout << "WCMRPortAudioDevice::DoIdle ()" << std::endl;
+       HANDLE hEvents[] = 
+       {
+               m_hUpdateDeviceInfoRequestedEvent,
+               m_hActivateRequestedEvent,
+               m_hDeActivateRequestedEvent,
+               m_hStartStreamingRequestedEvent,
+               m_hStopStreamingRequestedEvent,
+               m_hBufferSizeChangedEvent,
+               m_hSampleRateChangedEvent,
+               m_hResetRequestedEvent,
+               m_hResetFromDevRequestedEvent,
+               m_hExitIdleThread
+       };
+
+       const size_t hEventsSize = sizeof(hEvents)/sizeof(hEvents[0]);
+       
+       initDevice();
+
+       for(;;)
+       {
+               DWORD result = WaitForMultipleObjects (hEventsSize, hEvents, FALSE, INFINITE);
+               result = result - WAIT_OBJECT_0;
+
+               if ((result < 0) || (result >= hEventsSize)) {
+                       std::cout << "\t\t\t\t\t\t\tWCMRPortAudioDevice::DoIdle () -> (result < 0) || (result >= hEventsSize):" << result << std::endl;
+                       retVal = eGenericErr;
+                       break;
+               }
+
+               if (hEvents[result] == m_hExitIdleThread) {
+                       std::cout << "\t\t\t\t\t\t\tWCMRPortAudioDevice::DoIdle () -> m_hExitIdleThread" << result << std::endl;
+                       retVal = eNoErr;
+                       break;
+               }
+
+               if (hEvents[result] == m_hUpdateDeviceInfoRequestedEvent) {
+                       std::cout << "\t\t\t\t\t\tupdate requested ..." << std::endl;
+                       updateDeviceInfo(true);
+               }
+
+               if (hEvents[result] == m_hActivateRequestedEvent) {
+                       std::cout << "\t\t\t\t\t\tactivation requested ..." << std::endl;
+                       activateDevice(true);
+               }
+
+               if (hEvents[result] == m_hDeActivateRequestedEvent) {
+                       std::cout << "\t\t\t\t\t\tdeactivation requested ..." << std::endl;
+                       deactivateDevice(true);
+               }
+
+               if (hEvents[result] == m_hStartStreamingRequestedEvent) {
+                       std::cout << "\t\t\t\t\t\tStart stream requested ..." << std::endl;
+                       startStreaming(true);
+               }
+
+               if (hEvents[result] == m_hStopStreamingRequestedEvent) {
+                       std::cout << "\t\t\t\t\t\tStop stream requested ..." << std::endl;
+                       stopStreaming(true);
+               }
+
+               if (hEvents[result] == m_hResetRequestedEvent) {
+                       std::cout << "\t\t\t\t\t\treset requested ..." << std::endl;
+                       resetDevice(true);
+               }
+
+               if (hEvents[result] == m_hResetFromDevRequestedEvent) {
+                       std::cout << "\t\t\t\t\t\treset requested from device..." << std::endl;
+                       resetDevice();
+               }
+
+               if (hEvents[result] == m_hBufferSizeChangedEvent) {
+                       std::cout << "\t\t\t\t\t\tbuffer size changed from device..." << std::endl;
+                       m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::BufferSizeChanged);
+               }
+
+               if (hEvents[result] == m_hSampleRateChangedEvent) {
+                       std::cout << "\t\t\t\t\t\tsample rate changed from device..." << std::endl;
+                       m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::SamplingRateChanged);
+               }
+       }
+
+       terminateDevice();
+
+       return retVal;
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::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 WCMRPortAudioDevice::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);
+}
+
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::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 WCMRPortAudioDevice::SetMonitorGain (float newGain)
+{
+    AUTO_FUNC_DEBUG;
+       //This will most likely be overridden, the base class simply
+       //changes the member.
+       
+       m_MonitorGain = newGain;
+       return (eNoErr);
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::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 WCMRPortAudioDevice::ShowConfigPanel (void *pParam)
+{
+    AUTO_FUNC_DEBUG;
+       WTErr retVal = eNoErr;
+       
+       if (Active())
+       {
+#ifdef _WINDOWS
+               if(Pa_GetHostApiInfo(Pa_GetDeviceInfo(m_DeviceID)->hostApi)->type == paASIO)
+               {
+                       // stop and deactivate the device
+                       bool wasStreaming = Streaming();
+                       SetActive(false);
+                       // show control panel for the device
+                       if (PaAsio_ShowControlPanel (m_DeviceID, pParam) != paNoError)
+                               retVal = eGenericErr;
+                       // reset device to pick up changes
+                       ResetDevice();
+                       // restore previous state for the device
+                       SetActive(true);
+                       if (wasStreaming)
+                               SetStreaming(true);
+               }
+#else
+       pParam = pParam;
+#endif //_windows              
+       }
+       
+       return (retVal);
+}
+
+
+//*****************************************************************************************************
+// WCMRPortAudioDevice::TheCallback
+//
+//! The (static) Port Audio Callback function. This is a static member. It calls on the AudioCallback in the 
+//!            WCMRPortAudioDevice to do the real work.
+//!
+//! \param pInputBuffer: pointer to input buffer.
+//! \param pOutputBuffer: pointer to output buffer.
+//! \param framesPerBuffer: number of sample frames per buffer.
+//! \param pTimeInfo: time info for PaStream callback.
+//! \param statusFlags:
+//! \param pUserData: pointer to user data, in our case the WCMRPortAudioDevice object.
+//! 
+//! \return true to stop streaming else returns false.
+//******************************************************************************************************
+int WCMRPortAudioDevice::TheCallback (const void *pInputBuffer, void *pOutputBuffer, unsigned long framesPerBuffer, 
+       const PaStreamCallbackTimeInfo* /*pTimeInfo*/, PaStreamCallbackFlags statusFlags, void *pUserData )
+{
+       WCMRPortAudioDevice *pMyDevice = (WCMRPortAudioDevice *)pUserData;
+       if (pMyDevice)
+               return pMyDevice->AudioCallback ((float *)pInputBuffer, (float *)pOutputBuffer, framesPerBuffer,
+                       (statusFlags & (paInputOverflow | paOutputUnderflow)) != 0);
+       else
+               return (true);
+                       
+}
+
+
+
+//**********************************************************************************************
+// WCMRPortAudioDevice::AudoiCallback 
+//
+//! 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 *pInputBuffer : Points to a buffer with recorded data.
+//! \param *pOutputBuffer : Points to a buffer to receive playback data.
+//! \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.
+//!    \param dropsDetected : True if dropouts were detected in input or output. Can be used to signal the GUI.
+//! 
+//! \return true
+//! 
+//**********************************************************************************************
+int WCMRPortAudioDevice::AudioCallback( const float *pInputBuffer, float *pOutputBuffer, unsigned long framesPerBuffer, bool dropsDetected )
+{
+       UMicroseconds theStartTime;
+
+    // detect drops
+       if (dropsDetected)
+       {
+               if (m_IgnoreThisDrop)
+                       m_IgnoreThisDrop = false; //We'll ignore once, just once!
+               else
+                       m_DropsDetected++;
+       }
+
+       m_pInputData = pInputBuffer;
+
+    // VKamyshniy: Is this a right place to call the client???:
+    struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData =
+    {
+        m_pInputData,
+        pOutputBuffer,
+        framesPerBuffer,
+               m_SampleCounter,
+               theStartTime.MicroSeconds()*1000
+    };
+    
+    m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData );
+
+       //Don't try to  access after this call returns!
+       m_pInputData = NULL;
+
+       m_SampleCounter += framesPerBuffer;     
+
+       return m_StopRequested;
+}
+
+
+
+
+//**********************************************************************************************
+// WCMRPortAudioDeviceManager::WCMRPortAudioDeviceManager
+//
+//! The constructuor, we initialize PA, and build the device list.
+//!
+//! \param *pTheClient : The manager's client object (which receives notifications).
+//! \param interfaceType : The PortAudio interface type to use for this manager - acts as a filter.
+//! \param useMultithreading : Whether to use multi-threading for audio processing. Default is true.
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+WCMRPortAudioDeviceManager::WCMRPortAudioDeviceManager (WCMRAudioDeviceManagerClient *pTheClient, 
+                                                                                                               eAudioDeviceFilter eCurAudioDeviceFilter, bool useMultithreading, bool bNocopy)
+       : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter)
+       , m_NoneDevice(0)
+       , m_UseMultithreading(useMultithreading)
+       , m_bNoCopyAudioBuffer(bNocopy)
+{
+    AUTO_FUNC_DEBUG;
+       std::cout << "API::PortAudioDeviceManager::PA Device manager constructor" << std::endl;
+       
+       //Always create the None device first...
+       m_NoneDevice = new WCMRNativeAudioNoneDevice(this);
+
+       WTErr err = generateDeviceListImpl();
+
+       if (eNoErr != err)
+               throw err;
+
+       timeBeginPeriod (1);
+}
+
+
+//**********************************************************************************************
+// WCMRPortAudioDeviceManager::~WCMRPortAudioDeviceManager
+//
+//! It clears the device list, releasing each of the device.
+//!
+//! \param none
+//! 
+//! \return Nothing.
+//! 
+//**********************************************************************************************
+WCMRPortAudioDeviceManager::~WCMRPortAudioDeviceManager()
+{
+    AUTO_FUNC_DEBUG;
+       
+       std::cout << "API::Destroying PortAudioDeviceManager " << std::endl;
+
+       try
+       {
+               delete m_NoneDevice;
+       }
+       catch (...)
+       {
+               //destructors should absorb exceptions, no harm in logging though!!
+               DEBUG_MSG ("Exception during destructor");
+       }
+
+       timeEndPeriod (1);
+}
+
+
+WCMRAudioDevice* WCMRPortAudioDeviceManager::initNewCurrentDeviceImpl(const std::string & deviceName)
+{
+    destroyCurrentDeviceImpl();
+    
+       std::cout << "API::PortAudioDeviceManager::initNewCurrentDevice " << deviceName << std::endl;
+       if (deviceName == m_NoneDevice->DeviceName() )
+       {
+               m_CurrentDevice = m_NoneDevice;
+               return m_CurrentDevice;
+       }
+
+       DeviceInfo devInfo;
+       WTErr err = GetDeviceInfoByName(deviceName, devInfo);
+
+       if (eNoErr == err)
+       {
+               try
+               {
+                       std::cout << "API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName << std::endl;
+                       TRACE_MSG ("API::PortAudioDeviceManager::Creating PA device: " << devInfo.m_DeviceId << ", Device Name: " << devInfo.m_DeviceName);
+               
+                       m_CurrentDevice = new WCMRPortAudioDevice (this, devInfo.m_DeviceId, m_UseMultithreading, m_bNoCopyAudioBuffer);
+               }
+               catch (...)
+               {
+                       std::cout << "Unabled to create PA Device: " << devInfo.m_DeviceId << std::endl;
+                       DEBUG_MSG ("Unabled to create PA Device: " << devInfo.m_DeviceId);
+               }
+       }
+
+       return m_CurrentDevice;
+}
+
+
+void WCMRPortAudioDeviceManager::destroyCurrentDeviceImpl()
+{
+       if (m_CurrentDevice != m_NoneDevice)
+               delete m_CurrentDevice;
+
+       m_CurrentDevice = 0;
+}
+
+
+WTErr WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates(DeviceID deviceId, std::vector<int>& sampleRates)
+{
+       sampleRates.clear();
+       const PaDeviceInfo *pPaDeviceInfo = Pa_GetDeviceInfo(deviceId);
+
+       //now find supported sample rates
+       //following parameters are needed for sample rates validation
+       PaStreamParameters inputParameters, outputParameters;
+       PaStreamParameters *pInS = NULL, *pOutS = NULL;
+
+       inputParameters.device = deviceId;
+       inputParameters.channelCount = std::min<int>(2, pPaDeviceInfo->maxInputChannels);
+       inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
+       inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+       inputParameters.hostApiSpecificStreamInfo = 0;
+
+       if (inputParameters.channelCount)
+               pInS = &inputParameters;
+
+       outputParameters.device = deviceId;
+       outputParameters.channelCount = std::min<int>(2, pPaDeviceInfo->maxOutputChannels);
+       outputParameters.sampleFormat = paFloat32;
+       outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+       outputParameters.hostApiSpecificStreamInfo = 0;
+
+       if (outputParameters.channelCount)
+               pOutS = &outputParameters;
+
+       for(int sr=0; gAllSampleRates[sr] > 0; sr++)
+       {
+               if( paFormatIsSupported == Pa_IsFormatSupported(pInS, pOutS, gAllSampleRates[sr]) )
+               {
+                       sampleRates.push_back ((int)gAllSampleRates[sr]);
+               }
+       }
+}
+
+
+WTErr WCMRPortAudioDeviceManager::generateDeviceListImpl()
+{
+       std::cout << "API::PortAudioDeviceManager::Generating device list" << std::endl;
+       
+       WTErr retVal = eNoErr;
+
+       //Initialize PortAudio and ASIO first
+       PaError paErr = Pa_Initialize();
+
+       if (paErr != paNoError)
+       {
+               //ToDo: throw an exception here!
+               retVal = eSomeThingNotInitailzed;
+               return retVal;
+       }
+
+       // lock DeviceInfoVec firts
+       wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
+
+       if (m_NoneDevice)
+       {
+               DeviceInfo *pDevInfo = new DeviceInfo(NONE_DEVICE_ID, m_NoneDevice->DeviceName() );
+               pDevInfo->m_AvailableSampleRates = m_NoneDevice->SamplingRates();
+               m_DeviceInfoVec.push_back(pDevInfo);
+       }
+
+       //Get device count...
+       int numDevices = Pa_GetDeviceCount();
+
+       //for each device,
+       for (int thisDeviceID = 0; thisDeviceID < numDevices; thisDeviceID++)
+       {
+               //if it's of the required type...
+               const PaDeviceInfo *pPaDeviceInfo = Pa_GetDeviceInfo(thisDeviceID);
+               
+               if (Pa_GetHostApiInfo(pPaDeviceInfo->hostApi)->type == paASIO)
+               {
+                       //build a device object...
+                       try
+                       {
+                               std::cout << "API::PortAudioDeviceManager::DeviceID: " << thisDeviceID << ", Device Name: " << pPaDeviceInfo->name << std::endl;
+                               TRACE_MSG ("PA DeviceID: " << thisDeviceID << ", Device Name: " << pPaDeviceInfo->name);
+
+                               DeviceInfo *pDevInfo = new DeviceInfo(thisDeviceID, pPaDeviceInfo->name);
+                               if (pDevInfo)
+                               {
+                                       std::vector<int> availableSampleRates;
+                                       WTErr wErr = WCMRPortAudioDeviceManager::getDeviceAvailableSampleRates(thisDeviceID, availableSampleRates);
+
+                                       if (wErr != eNoErr)
+                                       {
+                                               DEBUG_MSG ("Failed to get device available sample rates. Device ID: " << m_DeviceID);
+                                               delete pDevInfo;
+                                               continue; //proceed to the next device
+                                       }
+
+                                       pDevInfo->m_AvailableSampleRates = availableSampleRates;
+                                       pDevInfo->m_MaxInputChannels = pPaDeviceInfo->maxInputChannels;
+                                       pDevInfo->m_MaxOutputChannels = pPaDeviceInfo->maxOutputChannels;
+
+                                       //Now check if this device is acceptable according to current input/output settings
+                                       bool bRejectDevice = false;
+                                       switch(m_eAudioDeviceFilter)
+                                       {
+                                               case eInputOnlyDevices:
+                                                       if (pDevInfo->m_MaxInputChannels != 0)
+                                                       {
+                                                               m_DeviceInfoVec.push_back(pDevInfo);
+                                                       }
+                                                       else
+                                                       {
+                                                               // Delete unnecesarry device
+                                                               bRejectDevice = true;
+                                                       }
+                                                       break;
+                                               case eOutputOnlyDevices:
+                                                       if (pDevInfo->m_MaxOutputChannels != 0)
+                                                       {
+                                                               m_DeviceInfoVec.push_back(pDevInfo);
+                                                       }
+                                                       else
+                                                       {
+                                                               // Delete unnecesarry device
+                                                               bRejectDevice = true;
+                                                       }
+                                                       break;
+                                               case eFullDuplexDevices:
+                                                       if (pDevInfo->m_MaxInputChannels != 0 && pDevInfo->m_MaxOutputChannels != 0)
+                                                       {
+                                                               m_DeviceInfoVec.push_back(pDevInfo);
+                                                       }
+                                                       else
+                                                       {
+                                                               // Delete unnecesarry device
+                                                               bRejectDevice = true;
+                                                       }
+                                                       break;
+                                               case eAllDevices:
+                                               default:
+                                                       m_DeviceInfoVec.push_back(pDevInfo);
+                                                       break;
+                                       }
+                
+                                       if(bRejectDevice)
+                                       {
+                                               TRACE_MSG ("API::PortAudioDeviceManager::Device " << pDevInfo->m_DeviceName << "Rejected. \
+                                                                       In Channels = " << pDevInfo->m_MaxInputChannels << "Out Channels = " <<pDevInfo->m_MaxOutputChannels );
+                                               delete pDevInfo;
+                                       }
+                               }
+                       }
+                       catch (...)
+                       {
+                               std::cout << "API::PortAudioDeviceManager::Unabled to create PA Device: " << std::endl;
+                               DEBUG_MSG ("Unabled to create PA Device: " << thisDeviceID);
+                       }
+               }
+       }
+
+       //If no devices were found, that's not a good thing!
+       if (m_DeviceInfoVec.empty() )
+       {
+               std::cout << "API::PortAudioDeviceManager::No matching PortAudio devices were found, total PA devices = " << numDevices << std::endl;
+               DEBUG_MSG ("No matching PortAudio devices were found, total PA devices = " << numDevices);
+       }
+
+       //we don't need PA initialized right now
+       Pa_Terminate();
+
+       return retVal;
+}
+
+
+WTErr WCMRPortAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& buffers) const
+{
+       WTErr retVal = eNoErr;
+       std::cout << "API::PortAudioDeviceManager::GetBufferSizes: getting buffer size for device: "<< deviceName << std::endl;
+       //first check if the request has been made for None device
+       if (deviceName == m_NoneDevice->DeviceName() )
+       {
+               buffers = m_NoneDevice->BufferSizes();
+               return retVal;
+       }
+
+       //if we have current device initialized and it's PA device, reset it
+       //this procedure will reset PA corrently and update info for all PA devices as well
+       
+       bool paLocalInit = false;
+       WCMRPortAudioDevice* portaudioDevice = dynamic_cast<WCMRPortAudioDevice*>(m_CurrentDevice);
+       if (portaudioDevice)
+       {
+               portaudioDevice->ResetDevice();
+       }
+       else
+       {
+               //initialize PA to get buffers for the device
+               Pa_Initialize();
+               paLocalInit = true;
+       }
+
+       DeviceInfo devInfo; 
+       retVal = GetDeviceInfoByName(deviceName, devInfo);
+
+       if (eNoErr == retVal)
+       {
+               //make PA request to get actual device buffer sizes
+               long minSize, maxSize, preferredSize, granularity;
+               PaError paErr = PaAsio_GetAvailableBufferSizes(devInfo.m_DeviceId, &minSize, &maxSize, &preferredSize, &granularity);
+
+               //for Windows ASIO devices we always use prefferes buffer size ONLY
+               if (paNoError == paErr )
+               {
+                       buffers.push_back(preferredSize);
+               }
+               else
+               {
+                       retVal = eAsioFailed;
+                       std::cout << "API::PortAudioDeviceManager::GetBufferSizes: error: " << paErr << " getting buffer size fo device: "<< deviceName << std::endl;
+               }
+       }
+       else
+       {
+               std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl;
+       }
+
+       //deinitialize PA now
+       if (paLocalInit)
+               Pa_Terminate();
+
+       return retVal;
+}
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.h b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.h
new file mode 100644 (file)
index 0000000..acbed16
--- /dev/null
@@ -0,0 +1,160 @@
+//----------------------------------------------------------------------------------
+//
+// Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
+//
+//! \file      WCMRPortAudioDeviceManager.h
+//!
+//! WCMRPortAudioDeviceManager and related class declarations
+//!
+//---------------------------------------------------------------------------------*/
+#ifndef __WCMRPortAudioDeviceManager_h_
+       #define __WCMRPortAudioDeviceManager_h_
+
+#include "WCMRAudioDeviceManager.h"
+#include "WCMRNativeAudio.h"
+#include "portaudio.h"
+
+//forward decl.
+class WCMRPortAudioDeviceManager;
+
+//! Manages a port audio device, providing information
+//! about the device, and managing audio callbacks.
+class WCMRPortAudioDevice : public WCMRNativeAudioDevice
+{
+public:
+
+       WCMRPortAudioDevice (WCMRPortAudioDeviceManager *pManager, unsigned int  deviceID, bool useMultiThreading = true, bool bNoCopy = false);///<Constructor
+       virtual ~WCMRPortAudioDevice ();///<Destructor
+
+       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 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 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 (const float *pInputBuffer, float *pOutputBuffer, unsigned long framesPerBuffe, bool dropsDetectedr);
+
+       virtual WTErr UpdateDeviceInfo ();
+
+       virtual WTErr ResetDevice();
+
+#ifdef _WINDOWS
+       static long StaticASIOMessageHook (void *pRefCon, long selector, long value, void* message, double* opt);
+       long ASIOMessageHook (long selector, long value, void* message, double* opt);
+#endif //_WINDOWS
+       
+protected:
+       static DWORD WINAPI __DoIdle__(LPVOID lpThreadParameter);
+
+       // Methods which are executed by device processing thread
+       WTErr DoIdle();///<Do Idle Processing
+       void initDevice();
+       void terminateDevice();
+       void updateDeviceInfo(bool callerIsWaiting = false);
+       void activateDevice(bool callerIsWaiting = false);
+       void deactivateDevice(bool callerIsWaiting = false);
+       void startStreaming(bool callerIsWaiting = false);
+       void stopStreaming(bool callerIsWaiting = false);
+       void resetDevice (bool callerIsWaiting = false);///<Reset device - close and reopen stream, update device information!
+
+       PaError testStateValidness(int sampleRate, int bufferSize);
+       ///////////////////////////////////////////////////////////
+       
+       static int TheCallback (const void *pInputBuffer, void *pOutputBuffer, unsigned long framesPerBuffer, 
+                                                       const PaStreamCallbackTimeInfo* /*pTimeInfo*/, PaStreamCallbackFlags /*statusFlags*/, void *pUserData );
+
+       unsigned int m_DeviceID; ///< The PA device id
+       PaStream* m_PortAudioStream; ///< Port audio stream, when the device is active!
+       bool m_StopRequested; ///< should be set to true when want to stop, set to false otherwise.
+       const 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;
+
+       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
+
+       int m_BufferSizeChangeRequested;
+       int m_BufferSizeChangeReported;
+       int m_ResetRequested;
+       int m_ResetReported;
+       int m_ResyncRequested;
+       int m_ResyncReported;
+
+       HANDLE m_hDeviceProcessingThread;
+       DWORD m_DeviceProcessingThreadID;
+
+       ///< Backend request events
+       HANDLE m_hResetRequestedEvent;
+       HANDLE m_hResetDone;
+
+       HANDLE m_hUpdateDeviceInfoRequestedEvent;
+       HANDLE m_hUpdateDeviceInfoDone;
+
+       HANDLE m_hActivateRequestedEvent;
+       HANDLE m_hActivationDone;
+
+       HANDLE m_hDeActivateRequestedEvent;
+       HANDLE m_hDeActivationDone;
+
+       HANDLE m_hStartStreamingRequestedEvent;
+       HANDLE m_hStartStreamingDone;
+
+       HANDLE m_hStopStreamingRequestedEvent;
+       HANDLE m_hStopStreamingDone;
+       /////////////////////////
+
+       ///< Device request events
+       HANDLE m_hResetFromDevRequestedEvent;
+       HANDLE m_hBufferSizeChangedEvent;
+       HANDLE m_hSampleRateChangedEvent;
+       /////////////////////////////
+
+       ///< Sync events
+       HANDLE m_hDeviceInitialized;
+       HANDLE m_hExitIdleThread;
+
+       //Should be set if the device connection status is "DeviceErrors"
+       WTErr m_lastErr;
+};
+
+//! WCMRPortAudioDeviceManager
+/*! The PortAudio Device Manager class */
+class WCMRPortAudioDeviceManager : public WCMRAudioDeviceManager
+{
+public:
+       WCMRPortAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter,
+                                                               bool useMultithreading = true, bool bNocopy = false); ///< constructor
+       
+       virtual ~WCMRPortAudioDeviceManager(void); ///< destructor
+
+protected:
+
+       virtual WCMRAudioDevice*        initNewCurrentDeviceImpl(const std::string & deviceName);
+       virtual void                            destroyCurrentDeviceImpl();
+       virtual WTErr                           generateDeviceListImpl(); // use this in derived class to fill device list
+       virtual WTErr                           updateDeviceListImpl() {return eNoErr; } // not supported
+       virtual WTErr                           getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& buffers) const;
+
+       bool m_UseMultithreading; ///< Flag indicates whether to use multi-threading for audio processing.
+    bool m_bNoCopyAudioBuffer;
+
+private:
+       // helper functions for this class only
+    WTErr getDeviceAvailableSampleRates(DeviceID deviceId, std::vector<int>& sampleRates);
+
+       WCMRAudioDevice*                        m_NoneDevice;
+};
+
+#endif //#ifndef __WCMRPortAudioDeviceManager_h_
index cd48169bf2420bc13e55dd6d969e3413f9642965..79b530a16bbba015390368ffd813b4e447425fb8 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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__
 
index e3de7155087ab819ffc5bdc16b86d2b843b08bd4..a644b61c92cd6339414ab06909cdc3d80687b41d 100644 (file)
@@ -1,87 +1,69 @@
-/*
-    Copyright (C) 2013 Waves Audio Ltd.
+#ifdef _WINDOWS
+    #include "IncludeWindows.h"
+#endif
+#if defined(__linux__) || defined(__MACOS__)
+       #include <sys/time.h>
+#endif
+
+#include "UMicroseconds.h"
+
+namespace wvNS { 
+UMicroseconds& UMicroseconds::ReadTime()
+{
+#ifdef _WINDOWS
+       LARGE_INTEGER Frequency, Count ;
 
-    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.
+       QueryPerformanceFrequency(&Frequency) ;
+       QueryPerformanceCounter(&Count);
+       theTime = uint64_t((Count.QuadPart * 1000000.0 / Frequency.QuadPart));
+#endif
 
-    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.
+#if defined(__linux__) || defined(__MACOS__)
+//     Mac code replaced by posix calls, to reduce Carbon dependency. 
+       timeval buf;
 
-    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.
+       gettimeofday(&buf,NULL);
 
+       // micro sec
+       theTime = uint64_t(buf.tv_sec) * 1000*1000 + buf.tv_usec;
+#endif
+
+       return *this;
+}
+/*
+ Removed in favor of the posix implementation. 
+#ifdef __MACOS__
+       uint32_t UMicroseconds::hi() {return reinterpret_cast<UnsignedWide*>(&theTime)->hi;}
+       uint32_t UMicroseconds::lo() {return reinterpret_cast<UnsignedWide*>(&theTime)->lo;}
+#endif
 */
-#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
+void UMicrosecondsAccumulator::Start()
+{
+       m_start_time.ReadTime();
+}
+
+void UMicrosecondsAccumulator::Stop()
+{
+       UMicroseconds stop_time;
+       
+       m_accumulator += stop_time.GetNativeTime() - m_start_time.GetNativeTime();
+}
+
+void UMicrosecondsAccumulator::Clear()
+{
+       m_start_time = 0;
+       m_accumulator = 0;
+}
+
+UMicroseconds UMicrosecondsAccumulator::GetAccumulatedTime() const
+{
+       return m_accumulator;
+}
+
+UMicrosecondsAccumulator& UMicrosecondsAccumulator::operator+=(const UMicrosecondsAccumulator& inaccum_to_add)
+{
+       m_accumulator += inaccum_to_add.GetAccumulatedTime();
+       return *this;
+}
+       
+} // namespace wvNS { 
index 64d1f8824de9abf4c5b75fa01de6d508214693c6..e50a256cced38973aac30a9a16299d9390fe3cce 100644 (file)
-/*
-    Copyright (C) 2013 Waves Audio Ltd.
+#ifndef __UMicroseconds_h__
+       #define __UMicroseconds_h__
+       
+/* Copy to include
+#include "UMicroseconds.h"
+*/
 
-    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 "BasicTypes/WUDefines.h"
+#include "BasicTypes/WUTypes.h"
 
-*/
-#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
+namespace wvNS { 
+// a wraper for Microseconds function from Timer.h
+class DllExport UMicroseconds
+{
+public:
+
+#ifdef _WINDOWS
+       typedef int64_t TimeKeeper;
+#endif
+#ifdef __MACOS__
+       typedef uint64_t TimeKeeper;
+#endif
+#ifdef __linux__
+       typedef uint64_t TimeKeeper;
+#endif
+
+private:
+       TimeKeeper theTime;
+
+public:
+
+       UMicroseconds()
+       {
+               ReadTime();
+       }
+
+       UMicroseconds(const TimeKeeper in_initVal) : theTime(in_initVal) {}
+
+       UMicroseconds(const UMicroseconds& inUM) : theTime(inUM.theTime) {}
+       UMicroseconds& operator=(const UMicroseconds& inUM) {theTime = inUM.theTime;  return *this;}
+       UMicroseconds& operator+=(const TimeKeeper in_timeToAdd)  {theTime += in_timeToAdd;  return *this;}
+
+       UMicroseconds& ReadTime();
+  
+       TimeKeeper GetNativeTime() const {return theTime;}
+       operator uint64_t () {return static_cast<uint64_t>(theTime);}
+       operator double () const {return static_cast<const double>(theTime);}
+
+       double Seconds() const {return static_cast<double>(theTime) / double(1000000);}
+       double MilliSeconds() const {return static_cast<double>(theTime) / double(1000);}
+       double MicroSeconds() const {return static_cast<double>(theTime);}
+
+#ifdef __MACOS__
+       uint32_t hi();
+       uint32_t lo();
+#endif
+};
+
+inline UMicroseconds operator-(const UMicroseconds& in_one, const UMicroseconds& in_two)
+{
+       UMicroseconds retVal(in_one.GetNativeTime() - in_two.GetNativeTime());
+       return retVal;
+}
+
+class UMicrosecondsAccumulator
+{
+public:
+       UMicrosecondsAccumulator() : m_start_time(0), m_accumulator(0) {}
+       
+       void Start();
+       void Stop();
+       void Clear();
+       
+       UMicroseconds GetAccumulatedTime() const;
+       
+       UMicrosecondsAccumulator& operator+=(const UMicrosecondsAccumulator&);
+       
+protected:
+       UMicroseconds m_start_time;
+       UMicroseconds m_accumulator;
+};
+
+inline UMicroseconds operator-(const UMicrosecondsAccumulator& in_one, const UMicrosecondsAccumulator& in_two)
+{
+       UMicroseconds retVal(in_one.GetAccumulatedTime() - in_two.GetAccumulatedTime());
+       return retVal;
+}
+
+//=========================================================================================//
+inline void MicrosecondDelay(double amt)
+//=========================================================================================//
+{
+       UMicroseconds than;
+       UMicroseconds now;
+
+       do
+       {
+               now.ReadTime();
+       }       while ((now.MicroSeconds() - than.MicroSeconds()) < amt);
+}
+       
+} // namespace wvNS { 
+#endif //#ifndef __UMicroseconds_h__
index 4c7264b1d546eb439527050757f574d482249b70..a14d8584d0eb2882d741847be829258b6c8fdc6b 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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__
 
index 11bca170874953b3ffe52f389d6d46f34523a2f8..f0080e40196e123c41e99f258fedd8cf6303d6bf 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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__
 
@@ -53,6 +35,7 @@ const WTErr eAppTerminateFailed                   = -23; //!< failed to terminate an appl
 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
+const WTErr eAsioFailed                                                = -27;
 
 // File Manager errors
 const WTErr eFMNoSuchVolume                                    = -1001; 
index 72de3388bfd93308dcafaaacd48048c4384d5aad..30976224c177c171f13b5b4daa988b842380c456 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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__
        
index 34c4a41e20a0cd9b2e6e92c52c90155976c685ba..8353a758c8f719c1344aed5c60b413caaa490749 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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.
index 791978958cb820d5902f2634b0e39b26226f62d4..de9b20c2fa176b085798acde023dccac10b15c6b 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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
 
index 62fc04007b36c7267494228cdd5987d94e72e215..123c41678c87d0e7cb73981bff5c22ea5c708434 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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
index c97808b0594ee28186fca73be8d1f44d393b0588..e95117482cb0bde12422cf344c0d08abec6c1bef 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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_
 
index 470ce77c62e6ee41c854cefb4cf452f39b89bb49..1e1b95d8ec80d2c140d0c250d3e09836d46c0cdf 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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__
 
index 6c6a0b9dec7243368f403587b649b18e3b6db738..9078d7666d57bfa402d12b474724d4adf920445c 100644 (file)
@@ -1,22 +1,5 @@
-/*
-    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.
-
-*/
 ///////////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2011 Waves Audio Ltd. All rights reserved.
 // \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
 ///////////////////////////////////////////////////////////////////////////////////////////////////////
index a9336966388ecc0cd610c913b1ad2cd229108a2b..494eb8f6b9d459fb13a6711f4b8afd3d24069819 100644 (file)
@@ -1,21 +1,3 @@
-/*
-    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__
 
old mode 100644 (file)
new mode 100755 (executable)
index 814f16b..37d29ac
@@ -19,14 +19,18 @@ def options(opt):
     autowaf.set_options(opt)
 
 def configure(conf):
+    if conf.options.dist_target == 'mingw':
+        autowaf.check_pkg(conf, 'portaudio-2.0', uselib_store='PORTAUDIO',
+                          atleast_version='19')
     autowaf.configure(conf)
     
 def build(bld):
-    obj = bld(features = 'c cxx cxxshlib')
-    if bld.env['build_target'] == 'mountain_lion':
-        obj.framework = 'CoreMidi'
+    
+    if bld.env['build_target'] == 'mingw':
+       obj = bld(features = 'cxx cxxshlib')
     else:
-        obj.framework = 'CoreMIDI'
+       obj = bld(features = 'cxx cxxshlib', framework = ["CoreMidi"])
+       
     obj.source = [
             'waves_audiobackend.cc',
             'waves_audiobackend.latency.cc',
@@ -41,34 +45,60 @@ def build(bld):
             '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'
+           'portmidi/src/pm_common/pmutil.c',
+           'portmidi/src/pm_common/portmidi.c'
             ]
+    
+    if bld.env['build_target'] == 'mingw':
+       platform_dependent = [
+                       'wavesapi/miscutils/UMicroseconds.cpp',
+                       'wavesapi/devicemanager/WCMRPortAudioDeviceManager.cpp',
+                       'portmidi/src/pm_win/pmwin.c',
+                       'portmidi/src/pm_win/pmwinmm.c',
+                       'portmidi/src/porttime/ptwinmm.c'
+                       ]
+    else:
+       platform_dependent = [
+           'wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp',
+           '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.source.extend(platform_dependent)
+    
     obj.includes = ['.',
-           'wavesapi',
-           'wavesapi/refmanager',
-           'wavesapi/wavespublicapi',
-           'wavesapi/devicemanager',
-           'wavesapi/miscutils',
-           'portmidi',
-           'portmidi/src/pm_common'
-            ]
+          'wavesapi',
+          'wavesapi/refmanager',
+          'wavesapi/wavespublicapi',
+          'wavesapi/devicemanager',
+          'wavesapi/miscutils',
+          'wavesapi/threads',
+          'portmidi',
+          'portmidi/src/pm_common'
+           ]
+    
     obj.cxxflags = [ '-fPIC' ]
     obj.cflags = [ '-fPIC', '-fms-extensions' ]
     obj.name     = 'waves_audiobackend'
     obj.target   = 'waves_audiobackend'
-    obj.use      = [ 'libardour', 'libpbd' ]
+    obj.use      = 'libardour libpbd'
+    if bld.env['build_target'] == 'mingw':
+           obj.uselib   = ['PORTAUDIO']
     obj.vnum     = WAVESAUDIOBACKEND_VERSION
-    obj.install_path  = os.path.join(bld.env['LIBDIR'], 'backends')
-    obj.defines = ['PACKAGE="' + I18N_PACKAGE + '"',
-            '__MACOS__',
-            'ARDOURBACKEND_DLL_EXPORTS'
-            ]
+    obj.install_path  = os.path.join(bld.env['LIBDIR'], 'ardour3', 'backends')
+    
+    if bld.env['build_target']== 'mingw':
+       obj.defines = ['PACKAGE="' + I18N_PACKAGE + '"',
+               '_WINDOWS',
+               'ARDOURBACKEND_DLL_EXPORTS'
+               ]
+    else:
+       obj.defines = ['PACKAGE="' + I18N_PACKAGE + '"',
+               '__MACOS__',
+               'ARDOURBACKEND_DLL_EXPORTS'
+               ]