summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2014-04-29 16:30:56 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2014-04-29 16:30:56 -0400
commit8a6762f189680a7ae6d2060aab97be0c43ae227a (patch)
tree033f428dd7841268dbf274c8cff97bcb5649cabb /libs
parente6cb3e8bb29c5de35354f01c215de136a6350d64 (diff)
Revert "update wavesaudio backend, now supports Windows (ASIO) as well as OS X (CoreAudio)"
This reverts commit f374ce69a6f28eb3e7774bfcdb5e07b61b06c3bd. The code does not compile on OS X, and includes changes to ARDOUR::AudioEngine that have not landed in git.
Diffstat (limited to 'libs')
-rw-r--r--libs/backends/wavesaudio/portmidi/pmutil.h254
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_common/pminternal.h356
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/Makefile.osx129
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/README_MAC.txt163
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.pbxproj594
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/xcuserdata/VKamyshniy.xcuserdatad/UserInterfaceState.xcuserstatebin5803 -> 0 bytes
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Assemble Application.xcscheme86
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Compile Java.xcscheme59
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/CopyJavaSources.xcscheme59
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/JPortMidiHeaders.xcscheme59
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/PmDefaults.xcscheme59
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/xcschememanagement.plist62
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/Assemble Application.xcscheme86
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/Compile Java.xcscheme59
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/CopyJavaSources.xcscheme59
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/JPortMidiHeaders.xcscheme59
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/PmDefaults.xcscheme59
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/xcschememanagement.plist62
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/build.xml87
-rwxr-xr-xlibs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/find-classrefs.sh31
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf14
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings3
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Info.plist40
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Manifest1
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.c118
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.h6
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/pmmacosxcm.h12
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_mac/readbinaryplist.c2230
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_win/pmwin.c286
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.c2928
-rw-r--r--libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.h10
-rw-r--r--libs/backends/wavesaudio/portmidi/src/porttime/ptmacosx_mach.c262
-rw-r--r--libs/backends/wavesaudio/portmidi/src/porttime/ptwinmm.c70
-rw-r--r--libs/backends/wavesaudio/waves_audiobackend.cc2559
-rw-r--r--libs/backends/wavesaudio/waves_audiobackend.h20
-rw-r--r--libs/backends/wavesaudio/waves_audiobackend.latency.cc180
-rw-r--r--libs/backends/wavesaudio/waves_audiobackend.midi.cc707
-rw-r--r--libs/backends/wavesaudio/waves_audiobackend.port_engine.cc1308
-rw-r--r--libs/backends/wavesaudio/waves_audioport.cc124
-rw-r--r--libs/backends/wavesaudio/waves_audioport.h116
-rw-r--r--libs/backends/wavesaudio/waves_dataport.cc284
-rw-r--r--libs/backends/wavesaudio/waves_dataport.h230
-rw-r--r--libs/backends/wavesaudio/waves_midi_buffer.cc99
-rw-r--r--libs/backends/wavesaudio/waves_midi_buffer.h95
-rw-r--r--libs/backends/wavesaudio/waves_midi_device.cc536
-rw-r--r--libs/backends/wavesaudio/waves_midi_device.h2
-rw-r--r--libs/backends/wavesaudio/waves_midi_device_manager.cc2
-rw-r--r--libs/backends/wavesaudio/waves_midi_device_manager.h2
-rw-r--r--libs/backends/wavesaudio/waves_midi_event.cc3
-rw-r--r--libs/backends/wavesaudio/waves_midi_event.h150
-rw-r--r--libs/backends/wavesaudio/waves_midiport.cc122
-rw-r--r--libs/backends/wavesaudio/waves_midiport.h128
-rw-r--r--libs/backends/wavesaudio/wavesapi/BasicTypes/WCFourCC.h18
-rw-r--r--libs/backends/wavesaudio/wavesapi/BasicTypes/WTByteOrder.h18
-rw-r--r--libs/backends/wavesaudio/wavesapi/BasicTypes/WUComPtr.h18
-rw-r--r--libs/backends/wavesaudio/wavesapi/BasicTypes/WUDefines.h18
-rw-r--r--libs/backends/wavesaudio/wavesapi/BasicTypes/WUMathConsts.h18
-rw-r--r--libs/backends/wavesaudio/wavesapi/BasicTypes/WUTypes.h18
-rw-r--r--libs/backends/wavesaudio/wavesapi/devicemanager/IncludeWindows.h72
-rw-r--r--libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.cpp189
-rw-r--r--libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.h130
-rw-r--r--libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp679
-rw-r--r--libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h67
-rw-r--r--libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.cpp28
-rw-r--r--libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.h36
-rw-r--r--libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.cpp1697
-rw-r--r--libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.h160
-rw-r--r--libs/backends/wavesaudio/wavesapi/miscutils/MinMaxUtilities.h18
-rw-r--r--libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.cpp146
-rw-r--r--libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.h220
-rw-r--r--libs/backends/wavesaudio/wavesapi/miscutils/WCFixedString.h18
-rw-r--r--libs/backends/wavesaudio/wavesapi/miscutils/WUErrors.h19
-rw-r--r--libs/backends/wavesaudio/wavesapi/miscutils/safe_delete.h18
-rw-r--r--libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.cpp18
-rw-r--r--libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.h18
-rw-r--r--libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.cpp18
-rw-r--r--libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.h18
-rw-r--r--libs/backends/wavesaudio/wavesapi/wavespublicapi/1.0/WavesPublicAPI_Defines.h18
-rw-r--r--libs/backends/wavesaudio/wavesapi/wavespublicapi/WTErr.h19
-rw-r--r--libs/backends/wavesaudio/wavesapi/wavespublicapi/wstdint.h18
-rw-r--r--[-rwxr-xr-x]libs/backends/wavesaudio/wscript83
82 files changed, 7612 insertions, 11239 deletions
diff --git a/libs/backends/wavesaudio/portmidi/pmutil.h b/libs/backends/wavesaudio/portmidi/pmutil.h
index ef5ee4bf84..40dabbff0e 100644
--- a/libs/backends/wavesaudio/portmidi/pmutil.h
+++ b/libs/backends/wavesaudio/portmidi/pmutil.h
@@ -1,127 +1,127 @@
-/* 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 */
+/* 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 */
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_common/pminternal.h b/libs/backends/wavesaudio/portmidi/src/pm_common/pminternal.h
index 6b6242026d..f7c62705b7 100644
--- a/libs/backends/wavesaudio/portmidi/src/pm_common/pminternal.h
+++ b/libs/backends/wavesaudio/portmidi/src/pm_common/pminternal.h
@@ -1,178 +1,178 @@
-/* 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
-
+/* 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
+
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/Makefile.osx b/libs/backends/wavesaudio/portmidi/src/pm_mac/Makefile.osx
deleted file mode 100644
index 8c6862e28f..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/Makefile.osx
+++ /dev/null
@@ -1,129 +0,0 @@
-# MAKEFILE FOR PORTMIDI
-
-# Roger B. Dannenberg
-# Sep 2009
-
-# NOTE: you can use
-# make -f pm_osx/Makefile.osx configuration=Release
-# to override the default Debug configuration
-configuration=Release
-
-PF=/usr/local
-
-# For debugging, define PM_CHECK_ERRORS
-ifeq ($(configuration),Release)
- CONFIG = Release
-else
- CONFIG = Debug
-endif
-
-current: all
-
-all: $(CONFIG)/CMakeCache.txt
- cd $(CONFIG); make
-
-$(CONFIG)/CMakeCache.txt:
- rm -f CMakeCache.txt
- mkdir -p $(CONFIG)
- cd $(CONFIG); cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=$(CONFIG)
-
-
-**** For instructions: make -f pm_mac\Makefile.osx help ****\n'
-
-help:
- echo $$'\n\n\
-This is help for portmidi/pm_mac/Makefile.osx\n\n\
-Installation path for dylib is $(PF)\n\
-To build Release version libraries and test applications,\n \
-make -f pm_mac/Makefile.osx\n\
-To build Debug version libraries and test applications,\n \
-make -f pm_mac/Makefile.osx configuration=Debug\n\
-To install universal dynamic library,\n \
-sudo make -f pm_mac/Makefile.osx install\n\
-To install universal dynamic library with xcode,\n \
-make -f pm_mac/Makefile.osx install-with-xcode\n\
-To make PmDefaults Java application,\n \
-make -f pm_mac/Makefile.osx pmdefaults\n\n \
-configuration = $(configuration)\n'
-
-
-clean:
- rm -f *.o *~ core* */*.o */*/*.o */*~ */core* pm_test/*/pm_dll.dll
- rm -f *.opt *.ncb *.plg pm_win/Debug/pm_dll.lib pm_win/Release/pm_dll.lib
- rm -f pm_test/*.opt pm_test/*.ncb
- rm -f pm_java/pmjni/*.o pm_java/pmjni/*~ pm_java/*.h
- rm -rf Release/CMakeFiles Debug/CMakeFiles
- rm -rf pm_mac/pmdefaults/lib pm_mac/pmdefaults/src
-
-cleaner: clean
- rm -rf pm_mac/build
- rm -rf pm_mac/Debug pm_mac/Release pm_test/Debug pm_test/Release
- rm -f Debug/*.dylib Release/*.dylib
- rm -f pm_java/pmjni/Debug/*.jnilib
- rm -f pm_java/pmjni/Release/*.jnilib
-
-cleanest: cleaner
- rm -f Debug/libportmidi_s.a Release/libportmidi_s.a
- rm -f pm_test/Debug/test pm_test/Debug/sysex pm_test/Debug/midithread
- rm -f pm_test/Debug/latency pm_test/Debug/midithru
- rm -f pm_test/Debug/qtest pm_test/Debug/mm
- rm -f pm_test/Release/test pm_test/Release/sysex pm_test/Release/midithread
- rm -f pm_test/Release/latency pm_test/Release/midithru
- rm -f pm_test/Release/qtest pm_test/Release/mm
- rm -f pm_java/*/*.class
- rm -f pm_java/pmjni/jportmidi_JPortMidiApi_PortMidiStream.h
-
-backup: cleanest
- cd ..; zip -r portmidi.zip portmidi
-
-install: porttime/porttime.h pm_common/portmidi.h \
- $(CONFIG)/libportmidi.dylib
- install porttime/porttime.h $(PF)/include/
- install pm_common/portmidi.h $(PF)/include
- install $(CONFIG)/libportmidi.dylib $(PF)/lib/
-
-# note - this uses xcode to build and install portmidi universal binaries
-install-with-xcode:
- sudo xcodebuild -project pm_mac/pm_mac.xcodeproj \
- -configuration Release install DSTROOT=/
-
-##### build pmdefault ######
-
-pm_java/pmjni/jportmidi_JPortMidiApi.h: pm_java/jportmidi/JPortMidiApi.class
- cd pm_java; javah jportmidi.JPortMidiApi
- mv pm_java/jportmidi_JportMidiApi.h pm_java/pmjni
-
-JAVASRC = pmdefaults/PmDefaultsFrame.java \
- pmdefaults/PmDefaults.java \
- jportmidi/JPortMidiApi.java jportmidi/JPortMidi.java \
- jportmidi/JPortMidiException.java
-
-# this compiles ALL of the java code
-pm_java/jportmidi/JPortMidiApi.class: $(JAVASRC:%=pm_java/%)
- cd pm_java; javac $(JAVASRC)
-
-$(CONFIG)/libpmjni.dylib:
- mkdir -p $(CONFIG)
- cd $(CONFIG); make -f ../pm_mac/$(MAKEFILE)
-
-pmdefaults: $(CONFIG)/libpmjni.dylib pm_java/jportmidi/JPortMidiApi.class
-ifeq ($(CONFIG),Debug)
- echo "Error: you cannot build pmdefaults in a Debug configuration \n\
- You should use configuration=Release in the Makefile command line. "
- @exit 2
-endif
- xcodebuild -project pm_mac/pm_mac.xcodeproj \
- -configuration Release -target PmDefaults
- echo "pmdefaults java application is made"
-
-###### test plist reader #######
-PLHDR = pm_mac/readbinaryplist.h
-PLSRC = pm_mac/plisttest.c pm_mac/readbinaryplist.c
-pm_mac/plisttest: $(PLHDR) $(PLSRC)
- cc $(VFLAGS) -Ipm_mac \
- -I/Developer/Headers/FlatCarbon \
- -I/System/Library/Frameworks/CoreFoundation.framework/Headers \
- -I/System/Library/Frameworks/CoreServices.framework/Headers \
- $(PLSRC) -o pm_mac/$(CONFIG)/plisttest \
- -framework CoreFoundation -framework CoreServices
-
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/README_MAC.txt b/libs/backends/wavesaudio/portmidi/src/pm_mac/README_MAC.txt
deleted file mode 100644
index 1650dccecc..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/README_MAC.txt
+++ /dev/null
@@ -1,163 +0,0 @@
-README_MAC.txt for PortMidi
-Roger Dannenberg
-20 nov 2009
-revised 20 Sep 2010 for Xcode 3.2.4 and CMake 8.2-2
-
-To build PortMidi for Mac OS X, you must install Xcode and
-CMake.
-
-CMake can build either command-line Makefiles or Xcode projects.
-These approaches are described in separate sections below.
-
-==== CLEANING UP ====
-(Skip this for now, but later you might want start from a clean
-slate.)
-
-Start in the portmedia/portmidi directory.
-
-make -f pm_mac/Makefile.osx clean
-
-will remove .o, CMakeFiles, and other intermediate files.
-
-Using "cleaner" instead of "clean" will also remove jni-related
-intermediate files.
-
-Using "cleanest" instead of "clean" or "cleaner" will also remove
-application binaries and the portmidi libraries. (It will not
-uninstall anything, however.)
-
-==== USING CMAKE (AND COMMAND LINE TOOLS) ====
-
-Start in the portmedia/portmidi directory.
-
-make -f pm_mac/Makefile.osx
-
-(Begin note: make will invoke cmake to build a Makefile and then make to
-build portmidi. This extra level allows you to correctly build
-both Release and Debug versions. Release is the default, so to get
-the Debug version, use:
-
-make -f pm_mac/Makefile.osx configuration=Debug
-)
-
-Release version executables and libraries are now in
- portmedia/portmidi/Release
-
-Debug version executables and libraries are created in
- portmedia/portmidi/Debug
-The Debug versions are compiled with PM_CHECK_ERRORS which
-prints an error message and aborts when an error code is returned
-by PortMidi functions. This is useful for small command line
-applications. Otherwise, you should check and handle error returns
-in your program.
-
-You can install portmidi as follows:
-
-cd Release; sudo make install
-
-This will install /usr/local/include/{portmidi.h, porttime.h}
-and /usr/local/lib/{libportmidi.dylib, libportmidi_s.a, libpmjni.dylib}
-
-You should now make the pmdefaults.app:
-
-make -f pm_mac/Makefile.osx pmdefaults
-
-NOTE: pmdefaults.app will be in pm_mac/Release/.
-
-Please copy pmdefaults.app to your Applications folder or wherever
-you would normally expect to find it.
-
-==== USING CMAKE TO BUILD Xcode PROJECT ====
-
-Before you can use Xcode, you need a portmidi.xcodeproj file.
-CMake builds a location-dependent Xcode project, so unfortunately
-it is not easy to provide an Xcode project that is ready to use.
-Therefore, you should make your own. Once you have it, you can
-use it almost like any other Xcode project, and you will not have
-to go back to CMake.
-
-(1) Install CMake if you do not have it already.
-
-(2) Open portmedia/portmidi/CMakeLists.txt with CMake
-
-(3) Use Configure and Generate buttons
-
-(4) This creates portmedia/portmidi/portmidi.xcodeproj.
-
-Note: You will also use pm_mac/pm_mac.xcodeproj, which
-is not generated by CMake.
-
-(5) Open portmidi/portmidi.xcodeproj with Xcode and
-build what you need. The simplest thing is to build the
-ALL_BUILD target. The default will be to build the Debug
-version, but you may want to change this to Release.
-
-NOTE: ALL_BUILD may report errors. Try simply building again
-or rebuilding specific targets that fail until they build
-without errors. There appears to be a race condition or
-missing dependencies in the build system.
-
-The Debug version is compiled with PM_CHECK_ERRORS, and the
-Release version is not. PM_CHECK_ERRORS will print an error
-message and exit your program if any error is returned from
-a call into PortMidi.
-
-CMake (currently) also creates MinSizRel and RelWithDebInfo
-versions, but only because I cannot figure out how to disable
-them.
-
-You will probably want the application PmDefaults, which sets
-default MIDI In and Out devices for PortMidi. You may also
-want to build a Java application using PortMidi. Since I have
-not figured out how to use CMake to make an OS X Java application,
-use pm_mac/pm_mac.xcodeproj as follows:
-
-(6) open pm_mac/pm_mac.xcodeproj
-
-(7) pm_java/pmjni/portmidi_JportmidiApi.h is needed
-by libpmjni.jnilib, the Java native interface library. Since
-portmidi_JportmidiApi.h is included with PortMidi, you can skip
-to step 8, but if you really want to rebuild everything from
-scratch, build the JPortMidiHeaders project first, and continue
-with step 8:
-
-(8) If you did not build libpmjni.dylib using portmidi.xcodeproj,
-do it now. (It depends on portmidi_JportmidiApi.h, and the
-PmDefaults project depends on libpmjni.dylib.)
-
-(9) Returning to pm_mac.xcodeproj, build the PmDefaults program.
-
-(10) If you wish, copy pm_mac/build/Deployment/PmDefaults.app to
-your applications folder.
-
-(11) If you want to install libportmidi.dylib, first make it with
-Xcode, then
- sudo make -f pm_mac/Makefile.osx install
-This command will install /usr/local/include/{porttime.h, portmidi.h}
-and /usr/local/lib/libportmidi.dylib
-Note that the "install" function of xcode creates portmidi/Release
-and does not install the library to /usr/local/lib, so please use
-the command line installer.
-
-
-CHANGELOG
-
-20-Sep-2010 Roger B. Dannenberg
- Adapted to Xcode 3.2.4
-20-Nov-2009 Roger B. Dannenberg
- Added some install instructions
-26-Sep-2009 Roger B. Dannenberg
- More changes for using CMake, Makefiles, XCode
-20-Sep-2009 Roger B. Dannenberg
- Modifications for using CMake
-14-Sep-2009 Roger B. Dannenberg
- Modifications for using CMake
-17-Jan-2007 Roger B. Dannenberg
- Explicit instructions for Xcode
-15-Jan-2007 Roger B. Dannenberg
- Changed instructions because of changes to Makefile.osx
-07-Oct-2006 Roger B. Dannenberg
- Added directions for xcodebuild
-29-aug-2006 Roger B. Dannenberg
- Updated this documentation.
-
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.pbxproj b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.pbxproj
deleted file mode 100644
index 0d06e565ea..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,594 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 44;
- objects = {
-
-/* Begin PBXAggregateTarget section */
- 3D634CAB1247805C0020F829 /* JPortMidiHeaders */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = 3D634CAE1247807A0020F829 /* Build configuration list for PBXAggregateTarget "JPortMidiHeaders" */;
- buildPhases = (
- 3D634CAA1247805C0020F829 /* ShellScript */,
- );
- dependencies = (
- 3D634CB0124781580020F829 /* PBXTargetDependency */,
- );
- name = JPortMidiHeaders;
- productName = JPortMidiHeaders;
- };
- 3DE2142D124662AA0033C839 /* CopyJavaSources */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = 3DE21434124662FF0033C839 /* Build configuration list for PBXAggregateTarget "CopyJavaSources" */;
- buildPhases = (
- 3DE2142C124662AA0033C839 /* CopyFiles */,
- );
- comments = "The reason for copying files here is that the Compile Java target looks in a particular place for sources. It would be much better to simply have Compile Java look in the original location for all sources, but I don't know how to do that. -RBD\n";
- dependencies = (
- );
- name = CopyJavaSources;
- productName = CopyJavaSources;
- };
- 89D0F1C90F3B704E007831A7 /* PmDefaults */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = 89D0F1D20F3B7080007831A7 /* Build configuration list for PBXAggregateTarget "PmDefaults" */;
- buildPhases = (
- );
- dependencies = (
- 89D0F1D10F3B7062007831A7 /* PBXTargetDependency */,
- 89D0F1CD0F3B7062007831A7 /* PBXTargetDependency */,
- 3DE21431124662C50033C839 /* PBXTargetDependency */,
- );
- name = PmDefaults;
- productName = pmdefaults;
- };
-/* End PBXAggregateTarget section */
-
-/* Begin PBXBuildFile section */
- 3DE2137F124653FB0033C839 /* portmusic_logo.png in Resources */ = {isa = PBXBuildFile; fileRef = 3DE2137E124653FB0033C839 /* portmusic_logo.png */; };
- 3DE21435124663860033C839 /* PmDefaultsFrame.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE2137D124653CB0033C839 /* PmDefaultsFrame.java */; };
- 3DE214361246638A0033C839 /* PmDefaults.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE2137B1246538B0033C839 /* PmDefaults.java */; };
- 3DE214371246638F0033C839 /* JPortMidiException.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE21382124654DE0033C839 /* JPortMidiException.java */; };
- 3DE214381246638F0033C839 /* JPortMidiApi.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE21381124654CF0033C839 /* JPortMidiApi.java */; };
- 3DE214391246638F0033C839 /* JPortMidi.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE21380124654BC0033C839 /* JPortMidi.java */; };
- 3DE216131246AC0E0033C839 /* libpmjni.dylib in Copy Java Resources */ = {isa = PBXBuildFile; fileRef = 3DE216101246ABE30033C839 /* libpmjni.dylib */; };
- 3DE216951246D57A0033C839 /* pmdefaults.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3DE216901246C6410033C839 /* pmdefaults.icns */; };
- 89C3F2920F5250A300B0048E /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 89C3F2900F5250A300B0048E /* Credits.rtf */; };
- 89D0F0240F392F20007831A7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 89D0F0210F392F20007831A7 /* InfoPlist.strings */; };
- 89D0F0410F39306C007831A7 /* JavaApplicationStub in Copy Executable */ = {isa = PBXBuildFile; fileRef = 89D0F03E0F39304A007831A7 /* JavaApplicationStub */; };
- 89D0F16A0F3A124E007831A7 /* pmdefaults.jar in Copy Java Resources */ = {isa = PBXBuildFile; fileRef = 89D0F15D0F3A0FF7007831A7 /* pmdefaults.jar */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXContainerItemProxy section */
- 3D634CAF124781580020F829 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 89D0F1C90F3B704E007831A7;
- remoteInfo = PmDefaults;
- };
- 3DE21430124662C50033C839 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 3DE2142D124662AA0033C839;
- remoteInfo = CopyJavaSources;
- };
- 3DE2145D124666900033C839 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 3DE2142D124662AA0033C839;
- remoteInfo = CopyJavaSources;
- };
- 89D0F1CC0F3B7062007831A7 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 8D1107260486CEB800E47090;
- remoteInfo = "Assemble Application";
- };
- 89D0F1D00F3B7062007831A7 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 89D0F0480F393A6F007831A7;
- remoteInfo = "Compile Java";
- };
-/* End PBXContainerItemProxy section */
-
-/* Begin PBXCopyFilesBuildPhase section */
- 3DE2142C124662AA0033C839 /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "${PROJECT_DIR}/pmdefaults/src/java";
- dstSubfolderSpec = 0;
- files = (
- 3DE21435124663860033C839 /* PmDefaultsFrame.java in CopyFiles */,
- 3DE214361246638A0033C839 /* PmDefaults.java in CopyFiles */,
- 3DE214371246638F0033C839 /* JPortMidiException.java in CopyFiles */,
- 3DE214381246638F0033C839 /* JPortMidiApi.java in CopyFiles */,
- 3DE214391246638F0033C839 /* JPortMidi.java in CopyFiles */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 89D0F0440F393070007831A7 /* Copy Executable */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "";
- dstSubfolderSpec = 6;
- files = (
- 89D0F0410F39306C007831A7 /* JavaApplicationStub in Copy Executable */,
- );
- name = "Copy Executable";
- runOnlyForDeploymentPostprocessing = 0;
- };
- 89D0F11F0F394189007831A7 /* Copy Java Resources */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "";
- dstSubfolderSpec = 15;
- files = (
- 89D0F16A0F3A124E007831A7 /* pmdefaults.jar in Copy Java Resources */,
- 3DE216131246AC0E0033C839 /* libpmjni.dylib in Copy Java Resources */,
- );
- name = "Copy Java Resources";
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXCopyFilesBuildPhase section */
-
-/* Begin PBXFileReference section */
- 3DE2137B1246538B0033C839 /* PmDefaults.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = PmDefaults.java; path = ../pm_java/pmdefaults/PmDefaults.java; sourceTree = SOURCE_ROOT; };
- 3DE2137D124653CB0033C839 /* PmDefaultsFrame.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = PmDefaultsFrame.java; path = ../pm_java/pmdefaults/PmDefaultsFrame.java; sourceTree = SOURCE_ROOT; };
- 3DE2137E124653FB0033C839 /* portmusic_logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = portmusic_logo.png; path = ../pm_java/pmdefaults/portmusic_logo.png; sourceTree = SOURCE_ROOT; };
- 3DE21380124654BC0033C839 /* JPortMidi.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = JPortMidi.java; path = ../pm_java/jportmidi/JPortMidi.java; sourceTree = SOURCE_ROOT; };
- 3DE21381124654CF0033C839 /* JPortMidiApi.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = JPortMidiApi.java; path = ../pm_java/jportmidi/JPortMidiApi.java; sourceTree = SOURCE_ROOT; };
- 3DE21382124654DE0033C839 /* JPortMidiException.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = JPortMidiException.java; path = ../pm_java/jportmidi/JPortMidiException.java; sourceTree = SOURCE_ROOT; };
- 3DE213841246555A0033C839 /* CoreMIDI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = /System/Library/Frameworks/CoreMIDI.framework; sourceTree = "<absolute>"; };
- 3DE21390124655760033C839 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
- 3DE213BE1246557F0033C839 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = "<absolute>"; };
- 3DE216101246ABE30033C839 /* libpmjni.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpmjni.dylib; path = ../Release/libpmjni.dylib; sourceTree = SOURCE_ROOT; };
- 3DE216901246C6410033C839 /* pmdefaults.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = pmdefaults.icns; path = ../pm_java/pmdefaults/pmdefaults.icns; sourceTree = SOURCE_ROOT; };
- 89C3F2910F5250A300B0048E /* English */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = English; path = English.lproj/Credits.rtf; sourceTree = "<group>"; };
- 89D0F0220F392F20007831A7 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
- 89D0F0230F392F20007831A7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
- 89D0F03E0F39304A007831A7 /* JavaApplicationStub */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = JavaApplicationStub; path = /System/Library/Frameworks/JavaVM.framework/Versions/A/Resources/MacOS/JavaApplicationStub; sourceTree = "<absolute>"; };
- 89D0F0840F394066007831A7 /* JavaNativeFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaNativeFoundation.framework; path = /System/Library/Frameworks/JavaVM.framework/Versions/A/Frameworks/JavaNativeFoundation.framework; sourceTree = "<absolute>"; };
- 89D0F1390F3948A9007831A7 /* pmdefaults/make */ = {isa = PBXFileReference; lastKnownFileType = folder; path = pmdefaults/make; sourceTree = "<group>"; };
- 89D0F15D0F3A0FF7007831A7 /* pmdefaults.jar */ = {isa = PBXFileReference; lastKnownFileType = archive.jar; name = pmdefaults.jar; path = build/Release/pmdefaults.jar; sourceTree = SOURCE_ROOT; };
- 89D0F1860F3A2442007831A7 /* JavaVM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaVM.framework; path = /System/Library/Frameworks/JavaVM.framework; sourceTree = "<absolute>"; };
- 8D1107320486CEB800E47090 /* PmDefaults.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PmDefaults.app; sourceTree = BUILT_PRODUCTS_DIR; };
-/* End PBXFileReference section */
-
-/* Begin PBXGroup section */
- 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
- isa = PBXGroup;
- children = (
- 3DE213841246555A0033C839 /* CoreMIDI.framework */,
- 3DE21390124655760033C839 /* CoreFoundation.framework */,
- 3DE213BE1246557F0033C839 /* CoreAudio.framework */,
- 89D0F1860F3A2442007831A7 /* JavaVM.framework */,
- 89D0F0840F394066007831A7 /* JavaNativeFoundation.framework */,
- );
- name = "Linked Frameworks";
- sourceTree = "<group>";
- };
- 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
- isa = PBXGroup;
- children = (
- );
- name = "Other Frameworks";
- sourceTree = "<group>";
- };
- 19C28FACFE9D520D11CA2CBB /* Products */ = {
- isa = PBXGroup;
- children = (
- 89D0F15D0F3A0FF7007831A7 /* pmdefaults.jar */,
- 8D1107320486CEB800E47090 /* PmDefaults.app */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 29B97314FDCFA39411CA2CEA /* pmdefaults */ = {
- isa = PBXGroup;
- children = (
- 3DE216101246ABE30033C839 /* libpmjni.dylib */,
- 89D0F0260F392F48007831A7 /* Source */,
- 89D0F0200F392F20007831A7 /* Resources */,
- 89D0F1390F3948A9007831A7 /* pmdefaults/make */,
- 29B97323FDCFA39411CA2CEA /* Frameworks */,
- 19C28FACFE9D520D11CA2CBB /* Products */,
- );
- name = pmdefaults;
- sourceTree = "<group>";
- };
- 29B97323FDCFA39411CA2CEA /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
- 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
- );
- name = Frameworks;
- sourceTree = "<group>";
- };
- 3DE2136A124652E20033C839 /* pm_java */ = {
- isa = PBXGroup;
- children = (
- 3DE21379124653150033C839 /* pmdefaults */,
- 3DE2137A1246531D0033C839 /* jportmidi */,
- );
- name = pm_java;
- path = ..;
- sourceTree = "<group>";
- };
- 3DE21379124653150033C839 /* pmdefaults */ = {
- isa = PBXGroup;
- children = (
- 3DE2137D124653CB0033C839 /* PmDefaultsFrame.java */,
- 3DE2137B1246538B0033C839 /* PmDefaults.java */,
- );
- name = pmdefaults;
- sourceTree = "<group>";
- };
- 3DE2137A1246531D0033C839 /* jportmidi */ = {
- isa = PBXGroup;
- children = (
- 3DE21382124654DE0033C839 /* JPortMidiException.java */,
- 3DE21381124654CF0033C839 /* JPortMidiApi.java */,
- 3DE21380124654BC0033C839 /* JPortMidi.java */,
- );
- name = jportmidi;
- sourceTree = "<group>";
- };
- 89D0F0200F392F20007831A7 /* Resources */ = {
- isa = PBXGroup;
- children = (
- 3DE216901246C6410033C839 /* pmdefaults.icns */,
- 3DE2137E124653FB0033C839 /* portmusic_logo.png */,
- 89C3F2900F5250A300B0048E /* Credits.rtf */,
- 89D0F0230F392F20007831A7 /* Info.plist */,
- 89D0F0210F392F20007831A7 /* InfoPlist.strings */,
- 89D0F03E0F39304A007831A7 /* JavaApplicationStub */,
- );
- name = Resources;
- path = pmdefaults/resources;
- sourceTree = "<group>";
- };
- 89D0F0260F392F48007831A7 /* Source */ = {
- isa = PBXGroup;
- children = (
- 3DE2136A124652E20033C839 /* pm_java */,
- );
- name = Source;
- path = pmdefaults/src;
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXLegacyTarget section */
- 89D0F0480F393A6F007831A7 /* Compile Java */ = {
- isa = PBXLegacyTarget;
- buildArgumentsString = "-e -f \"${SRCROOT}/make/build.xml\" -debug \"$ACTION\"";
- buildConfigurationList = 89D0F04B0F393AB7007831A7 /* Build configuration list for PBXLegacyTarget "Compile Java" */;
- buildPhases = (
- );
- buildToolPath = /usr/bin/ant;
- buildWorkingDirectory = "";
- dependencies = (
- 3DE2145E124666900033C839 /* PBXTargetDependency */,
- );
- name = "Compile Java";
- passBuildSettingsInEnvironment = 1;
- productName = "Compile Java";
- };
-/* End PBXLegacyTarget section */
-
-/* Begin PBXNativeTarget section */
- 8D1107260486CEB800E47090 /* Assemble Application */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Assemble Application" */;
- buildPhases = (
- 89D0F0440F393070007831A7 /* Copy Executable */,
- 89D0F11F0F394189007831A7 /* Copy Java Resources */,
- 8D1107290486CEB800E47090 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "Assemble Application";
- productInstallPath = "$(HOME)/Applications";
- productName = pmdefaults;
- productReference = 8D1107320486CEB800E47090 /* PmDefaults.app */;
- productType = "com.apple.product-type.application";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 29B97313FDCFA39411CA2CEA /* Project object */ = {
- isa = PBXProject;
- buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "pm_mac" */;
- compatibilityVersion = "Xcode 3.0";
- developmentRegion = English;
- hasScannedForEncodings = 1;
- knownRegions = (
- English,
- Japanese,
- French,
- German,
- );
- mainGroup = 29B97314FDCFA39411CA2CEA /* pmdefaults */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 3D634CAB1247805C0020F829 /* JPortMidiHeaders */,
- 89D0F1C90F3B704E007831A7 /* PmDefaults */,
- 3DE2142D124662AA0033C839 /* CopyJavaSources */,
- 89D0F0480F393A6F007831A7 /* Compile Java */,
- 8D1107260486CEB800E47090 /* Assemble Application */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- 8D1107290486CEB800E47090 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 3DE216951246D57A0033C839 /* pmdefaults.icns in Resources */,
- 89D0F0240F392F20007831A7 /* InfoPlist.strings in Resources */,
- 89C3F2920F5250A300B0048E /* Credits.rtf in Resources */,
- 3DE2137F124653FB0033C839 /* portmusic_logo.png in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXShellScriptBuildPhase section */
- 3D634CAA1247805C0020F829 /* ShellScript */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputPaths = (
- );
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "echo BUILT_PRODUCTS_DIR is ${BUILT_PRODUCTS_DIR}\njavah -classpath \"${BUILT_PRODUCTS_DIR}/pmdefaults.jar\" -force -o \"${BUILT_PRODUCTS_DIR}/jportmidi_JportMidiApi.h\" \"jportmidi.JPortMidiApi\"\nmv \"${BUILT_PRODUCTS_DIR}/jportmidi_JportMidiApi.h\" ../pm_java/pmjni/\necho \"Created ../pm_java/pmjni/jportmidi_JportMidiApi.h\"\n";
- };
-/* End PBXShellScriptBuildPhase section */
-
-/* Begin PBXTargetDependency section */
- 3D634CB0124781580020F829 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 89D0F1C90F3B704E007831A7 /* PmDefaults */;
- targetProxy = 3D634CAF124781580020F829 /* PBXContainerItemProxy */;
- };
- 3DE21431124662C50033C839 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 3DE2142D124662AA0033C839 /* CopyJavaSources */;
- targetProxy = 3DE21430124662C50033C839 /* PBXContainerItemProxy */;
- };
- 3DE2145E124666900033C839 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 3DE2142D124662AA0033C839 /* CopyJavaSources */;
- targetProxy = 3DE2145D124666900033C839 /* PBXContainerItemProxy */;
- };
- 89D0F1CD0F3B7062007831A7 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 8D1107260486CEB800E47090 /* Assemble Application */;
- targetProxy = 89D0F1CC0F3B7062007831A7 /* PBXContainerItemProxy */;
- };
- 89D0F1D10F3B7062007831A7 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 89D0F0480F393A6F007831A7 /* Compile Java */;
- targetProxy = 89D0F1D00F3B7062007831A7 /* PBXContainerItemProxy */;
- };
-/* End PBXTargetDependency section */
-
-/* Begin PBXVariantGroup section */
- 89C3F2900F5250A300B0048E /* Credits.rtf */ = {
- isa = PBXVariantGroup;
- children = (
- 89C3F2910F5250A300B0048E /* English */,
- );
- name = Credits.rtf;
- sourceTree = "<group>";
- };
- 89D0F0210F392F20007831A7 /* InfoPlist.strings */ = {
- isa = PBXVariantGroup;
- children = (
- 89D0F0220F392F20007831A7 /* English */,
- );
- name = InfoPlist.strings;
- sourceTree = "<group>";
- };
-/* End PBXVariantGroup section */
-
-/* Begin XCBuildConfiguration section */
- 3D634CAC1247805C0020F829 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_OPTIMIZATION_LEVEL = 0;
- PRODUCT_NAME = JPortMidiHeaders;
- };
- name = Debug;
- };
- 3D634CAD1247805C0020F829 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = YES;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- GCC_ENABLE_FIX_AND_CONTINUE = NO;
- PRODUCT_NAME = JPortMidiHeaders;
- ZERO_LINK = NO;
- };
- name = Release;
- };
- 3DE2142E124662AB0033C839 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_OPTIMIZATION_LEVEL = 0;
- PRODUCT_NAME = CopyJavaSources;
- };
- name = Debug;
- };
- 3DE2142F124662AB0033C839 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = YES;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- GCC_ENABLE_FIX_AND_CONTINUE = NO;
- PRODUCT_NAME = CopyJavaSources;
- ZERO_LINK = NO;
- };
- name = Release;
- };
- 89D0F0490F393A6F007831A7 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = pmdefaults;
- SRCROOT = ./pmdefaults;
- };
- name = Debug;
- };
- 89D0F04A0F393A6F007831A7 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = pmdefaults;
- SRCROOT = ./pmdefaults;
- };
- name = Release;
- };
- 89D0F1CA0F3B704F007831A7 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = pmdefaults;
- };
- name = Debug;
- };
- 89D0F1CB0F3B704F007831A7 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = pmdefaults;
- };
- name = Release;
- };
- C01FCF4B08A954540054247B /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)";
- COPY_PHASE_STRIP = NO;
- INFOPLIST_FILE = pmdefaults/resources/Info.plist;
- INSTALL_PATH = "$(HOME)/Applications";
- PRODUCT_NAME = pmdefaults;
- WRAPPER_EXTENSION = app;
- };
- name = Debug;
- };
- C01FCF4C08A954540054247B /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)";
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- INFOPLIST_FILE = pmdefaults/resources/Info.plist;
- INSTALL_PATH = "$(HOME)/Applications";
- PRODUCT_NAME = PmDefaults;
- WRAPPER_EXTENSION = app;
- };
- name = Release;
- };
- C01FCF4F08A954540054247B /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)";
- ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc";
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- PREBINDING = NO;
- };
- name = Debug;
- };
- C01FCF5008A954540054247B /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)";
- ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc";
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- PREBINDING = NO;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 3D634CAE1247807A0020F829 /* Build configuration list for PBXAggregateTarget "JPortMidiHeaders" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 3D634CAC1247805C0020F829 /* Debug */,
- 3D634CAD1247805C0020F829 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 3DE21434124662FF0033C839 /* Build configuration list for PBXAggregateTarget "CopyJavaSources" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 3DE2142E124662AB0033C839 /* Debug */,
- 3DE2142F124662AB0033C839 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 89D0F04B0F393AB7007831A7 /* Build configuration list for PBXLegacyTarget "Compile Java" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 89D0F0490F393A6F007831A7 /* Debug */,
- 89D0F04A0F393A6F007831A7 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 89D0F1D20F3B7080007831A7 /* Build configuration list for PBXAggregateTarget "PmDefaults" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 89D0F1CA0F3B704F007831A7 /* Debug */,
- 89D0F1CB0F3B704F007831A7 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Assemble Application" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- C01FCF4B08A954540054247B /* Debug */,
- C01FCF4C08A954540054247B /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- C01FCF4E08A954540054247B /* Build configuration list for PBXProject "pm_mac" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- C01FCF4F08A954540054247B /* Debug */,
- C01FCF5008A954540054247B /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
-}
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 570e6faa82..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
- version = "1.0">
- <FileRef
- location = "self:pm_mac.xcodeproj">
- </FileRef>
-</Workspace>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/xcuserdata/VKamyshniy.xcuserdatad/UserInterfaceState.xcuserstate b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/xcuserdata/VKamyshniy.xcuserdatad/UserInterfaceState.xcuserstate
deleted file mode 100644
index 104c0fe910..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/xcuserdata/VKamyshniy.xcuserdatad/UserInterfaceState.xcuserstate
+++ /dev/null
Binary files differ
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Assemble Application.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Assemble Application.xcscheme
deleted file mode 100644
index b2051a67b0..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Assemble Application.xcscheme
+++ /dev/null
@@ -1,86 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0460"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "8D1107260486CEB800E47090"
- BuildableName = "PmDefaults.app"
- BlueprintName = "Assemble Application"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES"
- buildConfiguration = "Debug">
- <Testables>
- </Testables>
- <MacroExpansion>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "8D1107260486CEB800E47090"
- BuildableName = "PmDefaults.app"
- BlueprintName = "Assemble Application"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </MacroExpansion>
- </TestAction>
- <LaunchAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Debug"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- allowLocationSimulation = "YES">
- <BuildableProductRunnable>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "8D1107260486CEB800E47090"
- BuildableName = "PmDefaults.app"
- BlueprintName = "Assemble Application"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Release"
- debugDocumentVersioning = "YES">
- <BuildableProductRunnable>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "8D1107260486CEB800E47090"
- BuildableName = "PmDefaults.app"
- BlueprintName = "Assemble Application"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Compile Java.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Compile Java.xcscheme
deleted file mode 100644
index 415b487914..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Compile Java.xcscheme
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0460"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "89D0F0480F393A6F007831A7"
- BuildableName = "Compile Java"
- BlueprintName = "Compile Java"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES"
- buildConfiguration = "Debug">
- <Testables>
- </Testables>
- </TestAction>
- <LaunchAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Debug"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- allowLocationSimulation = "YES">
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Release"
- debugDocumentVersioning = "YES">
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/CopyJavaSources.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/CopyJavaSources.xcscheme
deleted file mode 100644
index ad37276ccc..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/CopyJavaSources.xcscheme
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0460"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "3DE2142D124662AA0033C839"
- BuildableName = "CopyJavaSources"
- BlueprintName = "CopyJavaSources"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES"
- buildConfiguration = "Debug">
- <Testables>
- </Testables>
- </TestAction>
- <LaunchAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Debug"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- allowLocationSimulation = "YES">
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Release"
- debugDocumentVersioning = "YES">
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/JPortMidiHeaders.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/JPortMidiHeaders.xcscheme
deleted file mode 100644
index de0f0bcef7..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/JPortMidiHeaders.xcscheme
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0460"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "3D634CAB1247805C0020F829"
- BuildableName = "JPortMidiHeaders"
- BlueprintName = "JPortMidiHeaders"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES"
- buildConfiguration = "Debug">
- <Testables>
- </Testables>
- </TestAction>
- <LaunchAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Debug"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- allowLocationSimulation = "YES">
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Release"
- debugDocumentVersioning = "YES">
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/PmDefaults.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/PmDefaults.xcscheme
deleted file mode 100644
index 23d63e9bac..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/PmDefaults.xcscheme
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0460"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "89D0F1C90F3B704E007831A7"
- BuildableName = "PmDefaults"
- BlueprintName = "PmDefaults"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES"
- buildConfiguration = "Debug">
- <Testables>
- </Testables>
- </TestAction>
- <LaunchAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Debug"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- allowLocationSimulation = "YES">
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Release"
- debugDocumentVersioning = "YES">
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/xcschememanagement.plist b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/xcschememanagement.plist
deleted file mode 100644
index a57f870bb5..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/xcschememanagement.plist
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>SchemeUserState</key>
- <dict>
- <key>Assemble Application.xcscheme</key>
- <dict>
- <key>orderHint</key>
- <integer>4</integer>
- </dict>
- <key>Compile Java.xcscheme</key>
- <dict>
- <key>orderHint</key>
- <integer>3</integer>
- </dict>
- <key>CopyJavaSources.xcscheme</key>
- <dict>
- <key>orderHint</key>
- <integer>2</integer>
- </dict>
- <key>JPortMidiHeaders.xcscheme</key>
- <dict>
- <key>orderHint</key>
- <integer>0</integer>
- </dict>
- <key>PmDefaults.xcscheme</key>
- <dict>
- <key>orderHint</key>
- <integer>1</integer>
- </dict>
- </dict>
- <key>SuppressBuildableAutocreation</key>
- <dict>
- <key>3D634CAB1247805C0020F829</key>
- <dict>
- <key>primary</key>
- <true/>
- </dict>
- <key>3DE2142D124662AA0033C839</key>
- <dict>
- <key>primary</key>
- <true/>
- </dict>
- <key>89D0F0480F393A6F007831A7</key>
- <dict>
- <key>primary</key>
- <true/>
- </dict>
- <key>89D0F1C90F3B704E007831A7</key>
- <dict>
- <key>primary</key>
- <true/>
- </dict>
- <key>8D1107260486CEB800E47090</key>
- <dict>
- <key>primary</key>
- <true/>
- </dict>
- </dict>
-</dict>
-</plist>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/Assemble Application.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/Assemble Application.xcscheme
deleted file mode 100644
index b2051a67b0..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/Assemble Application.xcscheme
+++ /dev/null
@@ -1,86 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0460"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "8D1107260486CEB800E47090"
- BuildableName = "PmDefaults.app"
- BlueprintName = "Assemble Application"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES"
- buildConfiguration = "Debug">
- <Testables>
- </Testables>
- <MacroExpansion>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "8D1107260486CEB800E47090"
- BuildableName = "PmDefaults.app"
- BlueprintName = "Assemble Application"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </MacroExpansion>
- </TestAction>
- <LaunchAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Debug"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- allowLocationSimulation = "YES">
- <BuildableProductRunnable>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "8D1107260486CEB800E47090"
- BuildableName = "PmDefaults.app"
- BlueprintName = "Assemble Application"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Release"
- debugDocumentVersioning = "YES">
- <BuildableProductRunnable>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "8D1107260486CEB800E47090"
- BuildableName = "PmDefaults.app"
- BlueprintName = "Assemble Application"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/Compile Java.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/Compile Java.xcscheme
deleted file mode 100644
index 415b487914..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/Compile Java.xcscheme
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0460"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "89D0F0480F393A6F007831A7"
- BuildableName = "Compile Java"
- BlueprintName = "Compile Java"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES"
- buildConfiguration = "Debug">
- <Testables>
- </Testables>
- </TestAction>
- <LaunchAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Debug"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- allowLocationSimulation = "YES">
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Release"
- debugDocumentVersioning = "YES">
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/CopyJavaSources.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/CopyJavaSources.xcscheme
deleted file mode 100644
index ad37276ccc..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/CopyJavaSources.xcscheme
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0460"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "3DE2142D124662AA0033C839"
- BuildableName = "CopyJavaSources"
- BlueprintName = "CopyJavaSources"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES"
- buildConfiguration = "Debug">
- <Testables>
- </Testables>
- </TestAction>
- <LaunchAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Debug"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- allowLocationSimulation = "YES">
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Release"
- debugDocumentVersioning = "YES">
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/JPortMidiHeaders.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/JPortMidiHeaders.xcscheme
deleted file mode 100644
index de0f0bcef7..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/JPortMidiHeaders.xcscheme
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0460"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "3D634CAB1247805C0020F829"
- BuildableName = "JPortMidiHeaders"
- BlueprintName = "JPortMidiHeaders"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES"
- buildConfiguration = "Debug">
- <Testables>
- </Testables>
- </TestAction>
- <LaunchAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Debug"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- allowLocationSimulation = "YES">
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Release"
- debugDocumentVersioning = "YES">
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/PmDefaults.xcscheme b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/PmDefaults.xcscheme
deleted file mode 100644
index 23d63e9bac..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/PmDefaults.xcscheme
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0460"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "89D0F1C90F3B704E007831A7"
- BuildableName = "PmDefaults"
- BlueprintName = "PmDefaults"
- ReferencedContainer = "container:pm_mac.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES"
- buildConfiguration = "Debug">
- <Testables>
- </Testables>
- </TestAction>
- <LaunchAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Debug"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- allowLocationSimulation = "YES">
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Release"
- debugDocumentVersioning = "YES">
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/xcschememanagement.plist b/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/xcschememanagement.plist
deleted file mode 100644
index 4c011dee54..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/xcschememanagement.plist
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>SchemeUserState</key>
- <dict>
- <key>Assemble Application.xcscheme</key>
- <dict>
- <key>orderHint</key>
- <integer>5</integer>
- </dict>
- <key>Compile Java.xcscheme</key>
- <dict>
- <key>orderHint</key>
- <integer>4</integer>
- </dict>
- <key>CopyJavaSources.xcscheme</key>
- <dict>
- <key>orderHint</key>
- <integer>3</integer>
- </dict>
- <key>JPortMidiHeaders.xcscheme</key>
- <dict>
- <key>orderHint</key>
- <integer>1</integer>
- </dict>
- <key>PmDefaults.xcscheme</key>
- <dict>
- <key>orderHint</key>
- <integer>2</integer>
- </dict>
- </dict>
- <key>SuppressBuildableAutocreation</key>
- <dict>
- <key>3D634CAB1247805C0020F829</key>
- <dict>
- <key>primary</key>
- <true/>
- </dict>
- <key>3DE2142D124662AA0033C839</key>
- <dict>
- <key>primary</key>
- <true/>
- </dict>
- <key>89D0F0480F393A6F007831A7</key>
- <dict>
- <key>primary</key>
- <true/>
- </dict>
- <key>89D0F1C90F3B704E007831A7</key>
- <dict>
- <key>primary</key>
- <true/>
- </dict>
- <key>8D1107260486CEB800E47090</key>
- <dict>
- <key>primary</key>
- <true/>
- </dict>
- </dict>
-</dict>
-</plist>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/build.xml b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/build.xml
deleted file mode 100644
index bd08c68208..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/build.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="pmdefaults" default="jar" basedir="..">
-
- <!-- Global Properties -->
- <property environment="env"/>
-
-
- <!-- building in Xcode -->
- <condition property="product" value="${env.PRODUCT_NAME}">
- <isset property="env.PRODUCT_NAME"/>
- </condition>
-
- <condition property="src" value="${env.SRCROOT}/src">
- <isset property="env.SRCROOT"/>
- </condition>
-
- <condition property="obj" value="${env.OBJECT_FILE_DIR}">
- <isset property="env.OBJECT_FILE_DIR"/>
- </condition>
-
- <condition property="dst" value="${env.BUILT_PRODUCTS_DIR}">
- <isset property="env.BUILT_PRODUCTS_DIR"/>
- </condition>
-
-
- <!-- building from the command line -->
- <condition property="src" value="src">
- <not>
- <isset property="src"/>
- </not>
- </condition>
-
- <condition property="obj" value="build/obj">
- <not>
- <isset property="obj"/>
- </not>
- </condition>
-
- <condition property="dst" value="build">
- <not>
- <isset property="dst"/>
- </not>
- </condition>
-
- <condition property="product" value="pmdefaults">
- <not>
- <isset property="product"/>
- </not>
- </condition>
-
-
- <!-- Targets -->
- <target name="init" description="Create build directories">
- <mkdir dir="${obj}/${product}"/>
- <mkdir dir="${dst}"/>
- </target>
-
- <target name="compile" depends="init" description="Compile">
- <javac destdir="${obj}/${product}" deprecation="on" source="1.5" target="1.5" fork="true" debug="true" debuglevel="lines,source">
- <src path="${src}/java"/>
- <classpath path="${src}/../lib/eawt-stubs.jar"/>
- </javac>
- </target>
-
- <target name="copy" depends="init" description="Copy resources">
-
- </target>
-
- <target name="jar" depends="compile, copy" description="Assemble Jar file">
- <jar jarfile="${dst}/${product}.jar" basedir="${obj}/${product}" manifest="resources/Manifest" index="true"/>
- </target>
-
- <target name="install" depends="jar" description="Alias for 'jar'">
- <!-- sent by Xcode -->
- </target>
-
- <target name="clean" description="Removes build directories">
- <!-- sent by Xcode -->
- <delete dir="${obj}/${product}"/>
- <delete file="${dst}/${product}.jar"/>
- </target>
-
- <target name="installhdrs" description="">
- <!-- sent by Xcode -->
- <echo>"Nothing to do for install-headers phase"</echo>
- </target>
-</project>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/find-classrefs.sh b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/find-classrefs.sh
deleted file mode 100755
index 2217580d0d..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/find-classrefs.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-
-# Prints all class references made by all classes in a Jar file
-# Depends on the output formatting of javap
-
-# create a temporary working directory
-dir=`mktemp -d $TMPDIR/classrefs.XXXXXX`
-
-asm_dump="$dir/asm_dump"
-all_classes="$dir/all_classes"
-
-# for each class in a Jar file, dump the full assembly
-javap -c -classpath "$1" `/usr/bin/jar tf "$1" | grep "\.class" | sort | xargs | sed -e 's/\.class//g'` > $asm_dump
-
-# dump the initial list of all classes in the Jar file
-/usr/bin/jar tf $1 | grep "\.class" | sed -e 's/\.class//g' >> $all_classes
-
-# dump all static class references
-cat $asm_dump | grep //class | awk -F"//class " '{print $2}' | sort | uniq >> $all_classes
-
-# dump all references to classes made in methods
-cat $asm_dump | grep //Method | awk -F"//Method " '{print $2}' | sort | uniq | grep "\." | awk -F"." '{print $1}' | sort | uniq >> $all_classes
-
-# dump all references to classes by direct field access
-cat $asm_dump | grep //Field | awk -F"//Field " '{print $2}' | sort | uniq | grep "\:L" | awk -F"\:L" '{print $2}' | sort | uniq | awk -F"\;" '{print $1}' >> $all_classes
-
-# sort and reformat
-sort $all_classes | uniq | grep -v "\"" | sed -e 's/\//\./g'
-
-# cleanup
-rm -rf $dir
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf
deleted file mode 100644
index 18f83781e7..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf
+++ /dev/null
@@ -1,14 +0,0 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf320
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
-
-\f0\b\fs24 \cf0 Author:
-\b0 \
- Roger B. Dannenberg\
-\
-
-\b With special thanks to:
-\b0 \
- National Science Foundation\
-} \ No newline at end of file
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings
deleted file mode 100644
index 7c414663d0..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings
+++ /dev/null
@@ -1,3 +0,0 @@
-/* Localized versions of Info.plist keys */
-
-NSHumanReadableCopyright = "© Carnegie Mellon University, 2010"; \ No newline at end of file
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Info.plist b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Info.plist
deleted file mode 100644
index 58bedb4501..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Info.plist
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>English</string>
- <key>CFBundleExecutable</key>
- <string>JavaApplicationStub</string>
- <key>CFBundleIconFile</key>
- <string>pmdefaults.icns</string>
- <key>CFBundleIdentifier</key>
- <string></string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>PmDefaults</string>
- <key>CFBundlePackageType</key>
- <string>APPL</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>1.0</string>
- <key>CFBundleShortVersionString</key>
- <string>1.0</string>
- <key>Java</key>
- <dict>
- <key>ClassPath</key>
- <string>$JAVAROOT/pmdefaults.jar</string>
- <key>JVMVersion</key>
- <string>1.5+</string>
- <key>MainClass</key>
- <string>pmdefaults.PmDefaults</string>
- <key>Properties</key>
- <dict>
- <key>apple.laf.useScreenMenuBar</key>
- <string>true</string>
- </dict>
- </dict>
-</dict>
-</plist>
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Manifest b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Manifest
deleted file mode 100644
index 5dee9b0dc1..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Manifest
+++ /dev/null
@@ -1 +0,0 @@
-Main-Class: pmdefaults/PmDefaults
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.c b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.c
index bcef0d1f1c..13ac683004 100644
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.c
+++ b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.c
@@ -1,59 +1,59 @@
-/* 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); }
-
-
+/* 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); }
+
+
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.h b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.h
index 6cc0392c3f..2d714254ea 100644
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.h
+++ b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmac.h
@@ -1,4 +1,4 @@
-/* pmmac.h */
-
-extern PmDeviceID pm_default_input_device_id;
+/* pmmac.h */
+
+extern PmDeviceID pm_default_input_device_id;
extern PmDeviceID pm_default_output_device_id; \ No newline at end of file
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmacosxcm.h b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmacosxcm.h
index ea79902d40..97235b5dd2 100644
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmacosxcm.h
+++ b/libs/backends/wavesaudio/portmidi/src/pm_mac/pmmacosxcm.h
@@ -1,6 +1,6 @@
-/* system-specific definitions */
-
-PmError pm_macosxcm_init(void);
-void pm_macosxcm_term(void);
-
-PmDeviceID find_default_device(char *path, int input, PmDeviceID id);
+/* system-specific definitions */
+
+PmError pm_macosxcm_init(void);
+void pm_macosxcm_term(void);
+
+PmDeviceID find_default_device(char *path, int input, PmDeviceID id);
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_mac/readbinaryplist.c b/libs/backends/wavesaudio/portmidi/src/pm_mac/readbinaryplist.c
index d8ed8fbabc..bccd095183 100644
--- a/libs/backends/wavesaudio/portmidi/src/pm_mac/readbinaryplist.c
+++ b/libs/backends/wavesaudio/portmidi/src/pm_mac/readbinaryplist.c
@@ -1,1115 +1,1115 @@
-/*
-
-readbinaryplist.c -- Roger B. Dannenberg, Jun 2008
-Based on ReadBinaryPList.m by Jens Ayton, 2007
-
-Note that this code is intended to read preference files and has an upper
-bound on file size (currently 100MB) and assumes in some places that 32 bit
-offsets are sufficient.
-
-Here are his comments:
-
-Reader for binary property list files (version 00).
-
-This has been found to work on all 566 binary plists in my ~/Library/Preferences/
-and /Library/Preferences/ directories. This probably does not provide full
-test coverage. It has also been found to provide different data to Apple's
-implementation when presented with a key-value archive. This is because Apple's
-implementation produces undocumented CFKeyArchiverUID objects. My implementation
-produces dictionaries instead, matching the in-file representation used in XML
-and OpenStep plists. See extract_uid().
-
-Full disclosure: in implementing this software, I read one comment and one
-struct defintion in CFLite, Apple's implementation, which is under the APSL
-license. I also deduced the information about CFKeyArchiverUID from that code.
-However, none of the implementation was copied.
-
-Copyright (C) 2007 Jens Ayton
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-*/
-
-/* A note about memory management:
-Strings and possibly other values are unique and because the values
-associated with IDs are cached, you end up with a directed graph rather
-than a tree. It is tricky to free the data because if you do a simple
-depth-first search to free nodes, you will free nodes twice. I decided
-to allocate memory from blocks of 1024 bytes and keep the blocks in a
-list associated with but private to this module. So the user should
-access this module by calling:
- bplist_read_file() or bplist_read_user_pref() or
- bplist_read_system_pref()
-which returns a value. When you are done with the value, call
- bplist_free_data()
-This will of course free the value_ptr returned by bplist_read_*()
-
-To deal with memory exhaustion (what happens when malloc returns
-NULL?), use setjmp/longjmp -- a single setjmp protects the whole
-parser, and allocate uses longjmp to abort. After abort, memory
-is freed and NULL is returned to caller. There is not much here
-in the way of error reporting.
-
-Memory is obtained by calling allocate which either returns the
-memory requested or calls longjmp, so callers don't have to check.
-
-*/
-
-#include <sys/types.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include "readbinaryplist.h"
-#include <Carbon/Carbon.h>
-
-#define NO 0
-#define YES 1
-#define BOOL int
-
-#define MAXPATHLEN 256
-
-/* there are 2 levels of error logging/printing:
- * BPLIST_LOG and BPLIST_LOG_VERBOSE
- * either or both can be set to non-zero to turn on
- * If BPLIST_LOG_VERBOSE is true, then BPLIST_LOG
- * is also true.
- *
- * In the code, logging is done by calling either
- * bplist_log() or bplist_log_verbose(), which take
- * parameters like printf but might be a no-op.
- */
-
-/* #define BPLIST_LOG_VERBOSE 1 */
-
-#if BPLIST_LOG_VERBOSE
- #ifndef BPLIST_LOG
- #define BPLIST_LOG 1
- #endif
-#endif
-
-#if BPLIST_LOG
- #define bplist_log printf
-#else
- #define bplist_log(...)
-#endif
-
-#if BPLIST_LOG_VERBOSE
- #define bplist_log_verbose bplist_log
-#else
- #define bplist_log_verbose(...)
-#endif
-
-
-/********* MEMORY MANAGEMENT ********/
-#define BLOCK_SIZE 1024
-// memory is aligned to multiples of this; assume malloc automatically
-// aligns to this number and assume this number is > sizeof(void *)
-#define ALIGNMENT 8
-static void *block_list = NULL;
-static char *free_ptr = NULL;
-static char *end_ptr = NULL;
-static jmp_buf abort_parsing;
-
-static void *allocate(size_t size)
-{
- void *result;
- if (free_ptr + size > end_ptr) {
- size_t how_much = BLOCK_SIZE;
- // align everything to 8 bytes
- if (size > BLOCK_SIZE - ALIGNMENT) {
- how_much = size + ALIGNMENT;
- }
- result = malloc(how_much);
- if (result == NULL) {
- /* serious problem */
- longjmp(abort_parsing, 1);
- }
- *((void **)result) = block_list;
- block_list = result;
- free_ptr = ((char *) result) + ALIGNMENT;
- end_ptr = ((char *) result) + how_much;
- }
- // now, there is enough rooom at free_ptr
- result = free_ptr;
- free_ptr += size;
- return result;
-}
-
-void bplist_free_data()
-{
- while (block_list) {
- void *next = *(void **)block_list;
- free(block_list);
- block_list = next;
- }
- free_ptr = NULL;
- end_ptr = NULL;
-}
-
-// layout of trailer -- last 32 bytes in plist data
- uint8_t unused[6];
- uint8_t offset_int_size;
- uint8_t object_ref_size;
- uint64_t object_count;
- uint64_t top_level_object;
- uint64_t offset_table_offset;
-
-
-enum
-{
- kHEADER_SIZE = 8,
- kTRAILER_SIZE = 32, //sizeof(bplist_trailer_node),
- kMINIMUM_SANE_SIZE = kHEADER_SIZE + kTRAILER_SIZE
-};
-
-
-static const char kHEADER_BYTES[kHEADER_SIZE] = "bplist00";
-
-// map from UID key to previously parsed value
-typedef struct cache_struct {
- uint64_t key;
- value_ptr value;
- struct cache_struct *next;
-} cache_node, *cache_ptr;
-
-
-typedef struct bplist_info
-{
- uint64_t object_count;
- const uint8_t *data_bytes;
- uint64_t length;
- uint64_t offset_table_offset;
- uint8_t offset_int_size;
- uint8_t object_ref_size;
- cache_ptr cache;
-} bplist_info_node, *bplist_info_ptr;
-
-
-static value_ptr bplist_read_pldata(pldata_ptr data);
-static value_ptr bplist_read_pref(char *filename, OSType folder_type);
-static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset, uint8_t size);
-static uint64_t read_offset(bplist_info_ptr bplist, uint64_t index);
-static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset, uint64_t *outValue, size_t *outSize);
-
-static value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef);
-static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset);
-static value_ptr extract_int(bplist_info_ptr bplist, uint64_t offset);
-static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset);
-static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset);
-static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset);
-static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset);
-static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset);
-static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset);
-static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset);
-static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset);
-
-
-value_ptr value_create()
-{
- value_ptr value = (value_ptr) allocate(sizeof(value_node));
- return value;
-}
-
-
-void value_set_integer(value_ptr v, int64_t i) {
- v->tag = kTAG_INT; v->integer = i;
-}
-
-void value_set_real(value_ptr v, double d) {
- v->tag = kTAG_REAL; v->real = d;
-}
-
-// d is seconds since 1 January 2001
-void value_set_date(value_ptr v, double d) {
- v->tag = kTAG_DATE; v->real = d;
-}
-
-void value_set_ascii_string(value_ptr v, const uint8_t *s, size_t len) {
- v->tag = kTAG_ASCIISTRING;
- v->string = (char *) allocate(len + 1);
- memcpy(v->string, s, len);
- v->string[len] = 0;
-}
-
-void value_set_unicode_string(value_ptr v, const uint8_t *s, size_t len) {
- v->tag = kTAG_UNICODESTRING;
- v->string = (char *) allocate(len + 1);
- memcpy(v->string, s, len);
- v->string[len] = 0;
-}
-
-void value_set_uid(value_ptr v, uint64_t uid)
-{
- v->tag = kTAG_UID; v->uinteger = uid;
-}
-
-// v->data points to a pldata that points to the actual bytes
-// the bytes are copied, so caller must free byte source (*data)
-void value_set_data(value_ptr v, const uint8_t *data, size_t len) {
- v->tag = kTAG_DATA;
- pldata_ptr pldata = (pldata_ptr) allocate(sizeof(pldata_node));
- pldata->data = (uint8_t *) allocate(len);
- memcpy(pldata->data, data, len);
- pldata->len = len;
- v->data = pldata;
- printf("value at %p gets data at %p\n", v, pldata);
-}
-
-// caller releases ownership of array to value_ptr v
-void value_set_array(value_ptr v, value_ptr *array, size_t length) {
- array_ptr a = (array_ptr) allocate(sizeof(array_node));
- a->array = array;
- a->length = length;
- v->tag = kTAG_ARRAY;
- v->array = a;
-}
-
-// caller releases ownership of dict to value_ptr v
-void value_set_dict(value_ptr v, dict_ptr dict) {
- v->tag = kTAG_DICTIONARY;
- v->dict = dict;
-}
-
-
-// look up an objectref in the cache, a ref->value_ptr mapping
-value_ptr cache_lookup(cache_ptr cache, uint64_t ref)
-{
- while (cache) {
- if (cache->key == ref) {
- return cache->value;
- }
- cache = cache->next;
- }
- return NULL;
-}
-
-
-// insert an objectref and value in the cache
-void cache_insert(cache_ptr *cache, uint64_t ref, value_ptr value)
-{
- cache_ptr c = (cache_ptr) allocate(sizeof(cache_node));
- c->key = ref;
- c->value = value;
- c->next = *cache;
- *cache = c;
-}
-
-
-// insert an objectref and value in a dictionary
-void dict_insert(dict_ptr *dict, value_ptr key, value_ptr value)
-{
- dict_ptr d = (dict_ptr) allocate(sizeof(dict_node));
- d->key = key;
- d->value = value;
- d->next = *dict;
- *dict = d;
-}
-
-
-BOOL is_binary_plist(pldata_ptr data)
-{
- if (data->len < kMINIMUM_SANE_SIZE) return NO;
- return memcmp(data->data, kHEADER_BYTES, kHEADER_SIZE) == 0;
-}
-
-
-value_ptr bplist_read_file(char *filename)
-{
- struct stat stbuf;
- pldata_node pldata;
- FILE *file;
- size_t n;
- value_ptr value;
- int rslt = stat(filename, &stbuf);
- if (rslt) {
- #if BPLIST_LOG
- perror("in stat");
- #endif
- bplist_log("Could not stat %s, error %d\n", filename, rslt);
- return NULL;
- }
- // if file is >100MB, assume it is not a preferences file and give up
- if (stbuf.st_size > 100000000) {
- bplist_log("Large file %s encountered (%llu bytes) -- not read\n",
- filename, stbuf.st_size);
- return NULL;
- }
- pldata.len = (size_t) stbuf.st_size;
- // note: this is supposed to be malloc, not allocate. It is separate
- // from the graph structure, large, and easy to free right after
- // parsing.
- pldata.data = (uint8_t *) malloc(pldata.len);
- if (!pldata.data) {
- bplist_log("Could not allocate %lu bytes for %s\n",
- (unsigned long) pldata.len, filename);
- return NULL;
- }
- file = fopen(filename, "rb");
- if (!file) {
- bplist_log("Could not open %s\n", filename);
- return NULL;
- }
- n = fread(pldata.data, 1, pldata.len, file);
- if (n != pldata.len) {
- bplist_log("Error reading from %s\n", filename);
- return NULL;
- }
- value = bplist_read_pldata(&pldata);
- free(pldata.data);
- return value;
-}
-
-
-value_ptr bplist_read_pref(char *filename, OSType folder_type)
-{
- FSRef prefdir;
- char cstr[MAXPATHLEN];
-
- OSErr err = FSFindFolder(kOnAppropriateDisk, folder_type,
- FALSE, &prefdir);
- if (err) {
- bplist_log("Error finding preferences folder: %d\n", err);
- return NULL;
- }
- err = FSRefMakePath(&prefdir, (UInt8 *) cstr, (UInt32) (MAXPATHLEN - 1));
- if (err) {
- bplist_log("Error making path name for preferences folder: %d\n", err);
- return NULL;
- }
- strlcat(cstr, "/", MAXPATHLEN);
- strlcat(cstr, filename, MAXPATHLEN);
- return bplist_read_file(cstr);
-}
-
-
-value_ptr bplist_read_system_pref(char *filename) {
- return bplist_read_pref(filename, kSystemPreferencesFolderType);
-}
-
-
-value_ptr bplist_read_user_pref(char *filename) {
- return bplist_read_pref(filename, kPreferencesFolderType);
-}
-
-
-// data is stored with high-order bytes first.
-// read from plist data in a machine-independent fashion
-//
-uint64_t convert_uint64(uint8_t *ptr)
-{
- uint64_t rslt = 0;
- int i;
- // shift in bytes, high-order first
- for (i = 0; i < sizeof(uint64_t); i++) {
- rslt <<= 8;
- rslt += ptr[i];
- }
- return rslt;
-}
-
-
-value_ptr bplist_read_pldata(pldata_ptr data)
-{
- value_ptr result = NULL;
- bplist_info_node bplist;
- uint8_t *ptr;
- uint64_t top_level_object;
- int i;
-
- if (data == NULL) return NULL;
- if (!is_binary_plist(data)) {
- bplist_log("Bad binary plist: too short or invalid header.\n");
- return NULL;
- }
-
- // read trailer
- ptr = (uint8_t *) (data->data + data->len - kTRAILER_SIZE);
- bplist.offset_int_size = ptr[6];
- bplist.object_ref_size = ptr[7];
- bplist.object_count = convert_uint64(ptr + 8);
- top_level_object = convert_uint64(ptr + 16);
- bplist.offset_table_offset = convert_uint64(ptr + 24);
-
- // Basic sanity checks
- if (bplist.offset_int_size < 1 || bplist.offset_int_size > 8 ||
- bplist.object_ref_size < 1 || bplist.object_ref_size > 8 ||
- bplist.offset_table_offset < kHEADER_SIZE) {
- bplist_log("Bad binary plist: trailer declared insane.\n");
- return NULL;
- }
-
- // Ensure offset table is inside file
- uint64_t offsetTableSize = bplist.offset_int_size * bplist.object_count;
- if (offsetTableSize + bplist.offset_table_offset + kTRAILER_SIZE >
- data->len) {
- bplist_log("Bad binary plist: offset table overlaps end of container.\n");
- return NULL;
- }
-
- bplist.data_bytes = data->data;
- bplist.length = data->len;
- bplist.cache = NULL; /* dictionary is empty */
-
- bplist_log_verbose("Got a sane bplist with %llu items, offset_int_size: %u, object_ref_size: %u\n",
- bplist.object_count, bplist.offset_int_size,
- bplist.object_ref_size);
- /* at this point, we are ready to do some parsing which allocates
- memory for the result data structure. If memory allocation (using
- allocate fails, a longjmp will return to here and we simply give up
- */
- i = setjmp(abort_parsing);
- if (i == 0) {
- result = extract_object(&bplist, top_level_object);
- } else {
- bplist_log("allocate() failed to allocate memory. Giving up.\n");
- result = NULL;
- }
- if (!result) {
- bplist_free_data();
- }
- return result;
-}
-
-
-static value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef)
-{
- uint64_t offset;
- value_ptr result = NULL;
- uint8_t objectTag;
-
- if (objectRef >= bplist->object_count) {
- // Out-of-range object reference.
- bplist_log("Bad binary plist: object index is out of range.\n");
- return NULL;
- }
-
- // Use cached object if it exists
- result = cache_lookup(bplist->cache, objectRef);
- if (result != NULL) return result;
-
- // Otherwise, find object in file.
- offset = read_offset(bplist, objectRef);
- if (offset > bplist->length) {
- // Out-of-range offset.
- bplist_log("Bad binary plist: object outside container.\n");
- return NULL;
- }
- objectTag = *(bplist->data_bytes + offset);
- switch (objectTag & 0xF0) {
- case kTAG_SIMPLE:
- result = extract_simple(bplist, offset);
- break;
-
- case kTAG_INT:
- result = extract_int(bplist, offset);
- break;
-
- case kTAG_REAL:
- result = extract_real(bplist, offset);
- break;
-
- case kTAG_DATE:
- result = extract_date(bplist, offset);
- break;
-
- case kTAG_DATA:
- result = extract_data(bplist, offset);
- break;
-
- case kTAG_ASCIISTRING:
- result = extract_ascii_string(bplist, offset);
- break;
-
- case kTAG_UNICODESTRING:
- result = extract_unicode_string(bplist, offset);
- break;
-
- case kTAG_UID:
- result = extract_uid(bplist, offset);
- break;
-
- case kTAG_ARRAY:
- result = extract_array(bplist, offset);
- break;
-
- case kTAG_DICTIONARY:
- result = extract_dictionary(bplist, offset);
- break;
-
- default:
- // Unknown tag.
- bplist_log("Bad binary plist: unknown tag 0x%X.\n",
- (objectTag & 0x0F) >> 4);
- result = NULL;
- }
-
- // Cache and return result.
- if (result != NULL)
- cache_insert(&bplist->cache, objectRef, result);
- return result;
-}
-
-
-static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset,
- uint8_t size)
-{
- assert(bplist->data_bytes != NULL && size >= 1 && size <= 8 &&
- offset + size <= bplist->length);
-
- uint64_t result = 0;
- const uint8_t *byte = bplist->data_bytes + offset;
-
- do {
- // note that ints seem to be high-order first
- result = (result << 8) | *byte++;
- } while (--size);
-
- return result;
-}
-
-
-static uint64_t read_offset(bplist_info_ptr bplist, uint64_t index)
-{
- assert(index < bplist->object_count);
-
- return read_sized_int(bplist,
- bplist->offset_table_offset + bplist->offset_int_size * index,
- bplist->offset_int_size);
-}
-
-
-static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset,
- uint64_t *outValue, size_t *outSize)
-{
- uint32_t size;
- int64_t value;
-
- assert(bplist->data_bytes != NULL && offset < bplist->length);
-
- size = 1 << (bplist->data_bytes[offset] & 0x0F);
- if (size > 8) {
- // Maximum allowable size in this implementation is 1<<3 = 8 bytes.
- // This also happens to be the biggest we can handle.
- return NO;
- }
-
- if (offset + 1 + size > bplist->length) {
- // Out of range.
- return NO;
- }
-
- value = read_sized_int(bplist, offset + 1, size);
-
- if (outValue != NULL) *outValue = value;
- if (outSize != NULL) *outSize = size + 1; // +1 for tag byte.
- return YES;
-}
-
-
-static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset)
-{
- assert(bplist->data_bytes != NULL && offset < bplist->length);
- value_ptr value = value_create();
-
- switch (bplist->data_bytes[offset]) {
- case kVALUE_NULL:
- value->tag = kVALUE_NULL;
- return value;
-
- case kVALUE_TRUE:
- value->tag = kVALUE_TRUE;
- return value;
-
- case kVALUE_FALSE:
- value->tag = kVALUE_FALSE;
- return value;
- }
-
- // Note: kVALUE_FILLER is treated as invalid, because it, er, is.
- bplist_log("Bad binary plist: invalid atom.\n");
- free(value);
- return NULL;
-}
-
-
-static value_ptr extract_int(bplist_info_ptr bplist, uint64_t offset)
-{
- value_ptr value = value_create();
- value->tag = kTAG_INT;
-
- if (!read_self_sized_int(bplist, offset, &value->uinteger, NULL)) {
- bplist_log("Bad binary plist: invalid integer object.\n");
- }
-
- /* NOTE: originally, I sign-extended here. This was the wrong thing; it
- turns out that negative ints are always stored as 64-bit, and smaller
- ints are unsigned.
- */
- return value;
-}
-
-
-static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset)
-{
- value_ptr value = value_create();
- uint32_t size;
-
- assert(bplist->data_bytes != NULL && offset < bplist->length);
-
- size = 1 << (bplist->data_bytes[offset] & 0x0F);
-
- // FIXME: what to do if faced with other sizes for float/double?
- assert (sizeof (float) == sizeof (uint32_t) &&
- sizeof (double) == sizeof (uint64_t));
-
- if (offset + 1 + size > bplist->length) {
- bplist_log("Bad binary plist: %s object overlaps end of container.\n",
- "floating-point number");
- free(value);
- return NULL;
- }
-
- if (size == sizeof (float)) {
- // cast is ok because we know size is 4 bytes
- uint32_t i = (uint32_t) read_sized_int(bplist, offset + 1, size);
- // Note that this handles byte swapping.
- value_set_real(value, *(float *)&i);
- return value;
- } else if (size == sizeof (double)) {
- uint64_t i = read_sized_int(bplist, offset + 1, size);
- // Note that this handles byte swapping.
- value_set_real(value, *(double *)&i);
- return value;
- } else {
- // Can't handle floats of other sizes.
- bplist_log("Bad binary plist: can't handle %u-byte float.\n", size);
- free(value);
- return NULL;
- }
-}
-
-
-static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset)
-{
- value_ptr value;
- assert(bplist->data_bytes != NULL && offset < bplist->length);
-
- // Data has size code like int and real, but only 3 (meaning 8 bytes) is valid.
- if (bplist->data_bytes[offset] != kVALUE_FULLDATETAG) {
- bplist_log("Bad binary plist: invalid size for date object.\n");
- return NULL;
- }
-
- if (offset + 1 + sizeof (double) > bplist->length) {
- bplist_log("Bad binary plist: %s object overlaps end of container.\n",
- "date");
- return NULL;
- }
-
- // FIXME: what to do if faced with other sizes for double?
- assert (sizeof (double) == sizeof (uint64_t));
-
- uint64_t date = read_sized_int(bplist, offset + 1, sizeof(double));
- // Note that this handles byte swapping.
- value = value_create();
- value_set_date(value, *(double *)&date);
- return value;
-}
-
-
-uint64_t bplist_get_a_size(bplist_info_ptr bplist,
- uint64_t *offset_ptr, char *msg)
-{
- uint64_t size = bplist->data_bytes[*offset_ptr] & 0x0F;
- (*offset_ptr)++;
- if (size == 0x0F) {
- // 0x0F means separate int size follows.
- // Smaller values are used for short data.
- size_t extra; // the length of the data size we are about to read
- if ((bplist->data_bytes[*offset_ptr] & 0xF0) != kTAG_INT) {
- // Bad data, mistagged size int
- bplist_log("Bad binary plist: %s object size is not tagged as int.\n",
- msg);
- return UINT64_MAX; // error
- }
-
- // read integer data as size, extra tells how many bytes to skip
- if (!read_self_sized_int(bplist, *offset_ptr, &size, &extra)) {
- bplist_log("Bad binary plist: invalid %s object size tag.\n",
- "data");
- return UINT64_MAX; // error
- }
- (*offset_ptr) += extra;
- }
-
- if (*offset_ptr + size > bplist->length) {
- bplist_log("Bad binary plist: %s object overlaps end of container.\n",
- "data");
- return UINT64_MAX; // error
- }
- return size;
-}
-
-
-static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset)
-{
- uint64_t size;
- value_ptr value;
-
- assert(bplist->data_bytes != NULL && offset < bplist->length);
-
- if ((size = bplist_get_a_size(bplist, &offset, "data")) == UINT64_MAX)
- return NULL;
-
- value = value_create();
- // cast is ok because we only allow files up to 100MB:
- value_set_data(value, bplist->data_bytes + (size_t) offset, (size_t) size);
- return value;
-}
-
-
-static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset)
-{
- uint64_t size;
- value_ptr value; // return value
-
- assert(bplist->data_bytes != NULL && offset < bplist->length);
-
- if ((size = bplist_get_a_size(bplist, &offset, "ascii string")) ==
- UINT64_MAX)
- return NULL;
-
- value = value_create();
- // cast is ok because we only allow 100MB files
- value_set_ascii_string(value, bplist->data_bytes + (size_t) offset,
- (size_t) size);
- return value;
-}
-
-
-static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset)
-{
- uint64_t size;
- value_ptr value;
-
- assert(bplist->data_bytes != NULL && offset < bplist->length);
-
- if ((size = bplist_get_a_size(bplist, &offset, "unicode string")) ==
- UINT64_MAX)
- return NULL;
-
- value = value_create();
- // cast is ok because we only allow 100MB files
- value_set_unicode_string(value, bplist->data_bytes + (size_t) offset,
- (size_t) size);
- return value;
-}
-
-
-static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset)
-{
- /* UIDs are used by Cocoa's key-value coder.
- When writing other plist formats, they are expanded to dictionaries of
- the form <dict><key>CF$UID</key><integer>value</integer></dict>, so we
- do the same here on reading. This results in plists identical to what
- running plutil -convert xml1 gives us. However, this is not the same
- result as [Core]Foundation's plist parser, which extracts them as un-
- introspectable CF objects. In fact, it even seems to convert the CF$UID
- dictionaries from XML plists on the fly.
- */
-
- value_ptr value;
- uint64_t uid;
-
- if (!read_self_sized_int(bplist, offset, &uid, NULL)) {
- bplist_log("Bad binary plist: invalid UID object.\n");
- return NULL;
- }
-
- // assert(NO); // original code suggests using a string for a key
- // but our dictionaries all use big ints for keys, so I don't know
- // what to do here
-
- // In practice, I believe this code is never executed by PortMidi.
- // I changed it to do something and not raise compiler warnings, but
- // not sure what the code should do.
-
- value = value_create();
- value_set_uid(value, uid);
- // return [NSDictionary dictionaryWithObject:
- // [NSNumber numberWithUnsignedLongLong:value]
- // forKey:"CF$UID"];
- return value;
-}
-
-
-static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset)
-{
- uint64_t i, count;
- uint64_t size;
- uint64_t elementID;
- value_ptr element = NULL;
- value_ptr *array = NULL;
- value_ptr value = NULL;
- BOOL ok = YES;
-
- assert(bplist->data_bytes != NULL && offset < bplist->length);
-
- if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX)
- return NULL;
-
- if (count > UINT64_MAX / bplist->object_ref_size - offset) {
- // Offset overflow.
- bplist_log("Bad binary plist: %s object overlaps end of container.\n",
- "array");
- return NULL;
- }
-
- size = bplist->object_ref_size * count;
- if (size + offset > bplist->length) {
- bplist_log("Bad binary plist: %s object overlaps end of container.\n",
- "array");
- return NULL;
- }
-
- // got count, the number of array elements
-
- value = value_create();
- assert(value);
-
- if (count == 0) {
- // count must be size_t or smaller because max file size is 100MB
- value_set_array(value, array, (size_t) count);
- return value;
- }
-
- array = allocate(sizeof(value_ptr) * (size_t) count);
-
- for (i = 0; i != count; ++i) {
- bplist_log_verbose("[%u]\n", i);
- elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size,
- bplist->object_ref_size);
- element = extract_object(bplist, elementID);
- if (element != NULL) {
- array[i] = element;
- } else {
- ok = NO;
- break;
- }
- }
- if (ok) { // count is smaller than size_t max because of 100MB file limit
- value_set_array(value, array, (size_t) count);
- }
-
- return value;
-}
-
-
-static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset)
-{
- uint64_t i, count;
- uint64_t size;
- uint64_t elementID;
- value_ptr value = NULL;
- dict_ptr dict = NULL;
- BOOL ok = YES;
-
- assert(bplist->data_bytes != NULL && offset < bplist->length);
-
-
- if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX)
- return NULL;
-
- if (count > UINT64_MAX / (bplist->object_ref_size * 2) - offset) {
- // Offset overflow.
- bplist_log("Bad binary plist: %s object overlaps end of container.\n",
- "dictionary");
- return NULL;
- }
-
- size = bplist->object_ref_size * count * 2;
- if (size + offset > bplist->length) {
- bplist_log("Bad binary plist: %s object overlaps end of container.\n",
- "dictionary");
- return NULL;
- }
-
- value = value_create();
- if (count == 0) {
- value_set_dict(value, NULL);
- return value;
- }
-
- for (i = 0; i != count; ++i) {
- value_ptr key;
- value_ptr val;
- elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size,
- bplist->object_ref_size);
- key = extract_object(bplist, elementID);
- if (key != NULL) {
- bplist_log_verbose("key: %p\n", key);
- } else {
- ok = NO;
- break;
- }
-
- elementID = read_sized_int(bplist,
- offset + (i + count) * bplist->object_ref_size,
- bplist->object_ref_size);
- val = extract_object(bplist, elementID);
- if (val != NULL) {
- dict_insert(&dict, key, val);
- } else {
- ok = NO;
- break;
- }
- }
- if (ok) {
- value_set_dict(value, dict);
- }
-
- return value;
-}
-
-/*************** functions for accessing values ****************/
-
-
-char *value_get_asciistring(value_ptr v)
-{
- if (v->tag != kTAG_ASCIISTRING) return NULL;
- return v->string;
-}
-
-
-value_ptr value_dict_lookup_using_string(value_ptr v, char *key)
-{
- dict_ptr dict;
- if (v->tag != kTAG_DICTIONARY) return NULL; // not a dictionary
- dict = v->dict;
- /* search for key */
- while (dict) {
- if (dict->key && dict->key->tag == kTAG_ASCIISTRING &&
- strcmp(key, dict->key->string) == 0) { // found it
- return dict->value;
- }
- dict = dict->next;
- }
- return NULL; /* not found */
-}
-
-value_ptr value_dict_lookup_using_path(value_ptr v, char *path)
-{
- char key[MAX_KEY_SIZE];
- while (*path) { /* more to the path */
- int i = 0;
- while (i < MAX_KEY_SIZE - 1) {
- key[i] = *path++;
- if (key[i] == '/') { /* end of entry in path */
- key[i + 1] = 0;
- break;
- }
- if (!key[i]) {
- path--; /* back up to end of string char */
- break; /* this will cause outer loop to exit */
- }
- i++;
- }
- if (!v || v->tag != kTAG_DICTIONARY) return NULL;
- /* now, look up the key to get next value */
- v = value_dict_lookup_using_string(v, key);
- if (v == NULL) return NULL;
- }
- return v;
-}
-
-
-/*************** functions for debugging ***************/
-
-void plist_print(value_ptr v)
-{
- size_t i;
- int comma_needed;
- dict_ptr dict;
- if (!v) {
- printf("NULL");
- return;
- }
- switch (v->tag & 0xF0) {
- case kTAG_SIMPLE:
- switch (v->tag) {
- case kVALUE_NULL:
- printf("NULL@%p", v); break;
- case kVALUE_FALSE:
- printf("FALSE@%p", v); break;
- case kVALUE_TRUE:
- printf("TRUE@%p", v); break;
- default:
- printf("UNKNOWN tag=%x@%p", v->tag, v); break;
- }
- break;
- case kTAG_INT:
- printf("%lld@%p", v->integer, v); break;
- case kTAG_REAL:
- printf("%g@%p", v->real, v); break;
- case kTAG_DATE:
- printf("date:%g@%p", v->real, v); break;
- case kTAG_DATA:
- printf("data@%p->%p:[%p:", v, v->data, v->data->data);
- for (i = 0; i < v->data->len; i++) {
- printf(" %2x", v->data->data[i]);
- }
- printf("]"); break;
- case kTAG_ASCIISTRING:
- printf("%p:\"%s\"@%p", v->string, v->string, v); break;
- case kTAG_UNICODESTRING:
- printf("unicode:%p:\"%s\"@%p", v->string, v->string, v); break;
- case kTAG_UID:
- printf("UID:%llu@%p", v->uinteger, v); break;
- case kTAG_ARRAY:
- comma_needed = FALSE;
- printf("%p->%p:[%p:", v, v->array, v->array->array);
- for (i = 0; i < v->array->length; i++) {
- if (comma_needed) printf(", ");
- plist_print(v->array->array[i]);
- comma_needed = TRUE;
- }
- printf("]"); break;
- case kTAG_DICTIONARY:
- comma_needed = FALSE;
- printf("%p:[", v);
- dict = v->dict;
- while (dict) {
- if (comma_needed) printf(", ");
- printf("%p:", dict);
- plist_print(dict->key);
- printf("->");
- plist_print(dict->value);
- comma_needed = TRUE;
- dict = dict->next;
- }
- printf("]"); break;
- default:
- printf("UNKNOWN tag=%x", v->tag);
- break;
- }
-}
-
-
+/*
+
+readbinaryplist.c -- Roger B. Dannenberg, Jun 2008
+Based on ReadBinaryPList.m by Jens Ayton, 2007
+
+Note that this code is intended to read preference files and has an upper
+bound on file size (currently 100MB) and assumes in some places that 32 bit
+offsets are sufficient.
+
+Here are his comments:
+
+Reader for binary property list files (version 00).
+
+This has been found to work on all 566 binary plists in my ~/Library/Preferences/
+and /Library/Preferences/ directories. This probably does not provide full
+test coverage. It has also been found to provide different data to Apple's
+implementation when presented with a key-value archive. This is because Apple's
+implementation produces undocumented CFKeyArchiverUID objects. My implementation
+produces dictionaries instead, matching the in-file representation used in XML
+and OpenStep plists. See extract_uid().
+
+Full disclosure: in implementing this software, I read one comment and one
+struct defintion in CFLite, Apple's implementation, which is under the APSL
+license. I also deduced the information about CFKeyArchiverUID from that code.
+However, none of the implementation was copied.
+
+Copyright (C) 2007 Jens Ayton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+*/
+
+/* A note about memory management:
+Strings and possibly other values are unique and because the values
+associated with IDs are cached, you end up with a directed graph rather
+than a tree. It is tricky to free the data because if you do a simple
+depth-first search to free nodes, you will free nodes twice. I decided
+to allocate memory from blocks of 1024 bytes and keep the blocks in a
+list associated with but private to this module. So the user should
+access this module by calling:
+ bplist_read_file() or bplist_read_user_pref() or
+ bplist_read_system_pref()
+which returns a value. When you are done with the value, call
+ bplist_free_data()
+This will of course free the value_ptr returned by bplist_read_*()
+
+To deal with memory exhaustion (what happens when malloc returns
+NULL?), use setjmp/longjmp -- a single setjmp protects the whole
+parser, and allocate uses longjmp to abort. After abort, memory
+is freed and NULL is returned to caller. There is not much here
+in the way of error reporting.
+
+Memory is obtained by calling allocate which either returns the
+memory requested or calls longjmp, so callers don't have to check.
+
+*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include "readbinaryplist.h"
+#include <Carbon/Carbon.h>
+
+#define NO 0
+#define YES 1
+#define BOOL int
+
+#define MAXPATHLEN 256
+
+/* there are 2 levels of error logging/printing:
+ * BPLIST_LOG and BPLIST_LOG_VERBOSE
+ * either or both can be set to non-zero to turn on
+ * If BPLIST_LOG_VERBOSE is true, then BPLIST_LOG
+ * is also true.
+ *
+ * In the code, logging is done by calling either
+ * bplist_log() or bplist_log_verbose(), which take
+ * parameters like printf but might be a no-op.
+ */
+
+/* #define BPLIST_LOG_VERBOSE 1 */
+
+#if BPLIST_LOG_VERBOSE
+ #ifndef BPLIST_LOG
+ #define BPLIST_LOG 1
+ #endif
+#endif
+
+#if BPLIST_LOG
+ #define bplist_log printf
+#else
+ #define bplist_log(...)
+#endif
+
+#if BPLIST_LOG_VERBOSE
+ #define bplist_log_verbose bplist_log
+#else
+ #define bplist_log_verbose(...)
+#endif
+
+
+/********* MEMORY MANAGEMENT ********/
+#define BLOCK_SIZE 1024
+// memory is aligned to multiples of this; assume malloc automatically
+// aligns to this number and assume this number is > sizeof(void *)
+#define ALIGNMENT 8
+static void *block_list = NULL;
+static char *free_ptr = NULL;
+static char *end_ptr = NULL;
+static jmp_buf abort_parsing;
+
+static void *allocate(size_t size)
+{
+ void *result;
+ if (free_ptr + size > end_ptr) {
+ size_t how_much = BLOCK_SIZE;
+ // align everything to 8 bytes
+ if (size > BLOCK_SIZE - ALIGNMENT) {
+ how_much = size + ALIGNMENT;
+ }
+ result = malloc(how_much);
+ if (result == NULL) {
+ /* serious problem */
+ longjmp(abort_parsing, 1);
+ }
+ *((void **)result) = block_list;
+ block_list = result;
+ free_ptr = ((char *) result) + ALIGNMENT;
+ end_ptr = ((char *) result) + how_much;
+ }
+ // now, there is enough rooom at free_ptr
+ result = free_ptr;
+ free_ptr += size;
+ return result;
+}
+
+void bplist_free_data()
+{
+ while (block_list) {
+ void *next = *(void **)block_list;
+ free(block_list);
+ block_list = next;
+ }
+ free_ptr = NULL;
+ end_ptr = NULL;
+}
+
+// layout of trailer -- last 32 bytes in plist data
+ uint8_t unused[6];
+ uint8_t offset_int_size;
+ uint8_t object_ref_size;
+ uint64_t object_count;
+ uint64_t top_level_object;
+ uint64_t offset_table_offset;
+
+
+enum
+{
+ kHEADER_SIZE = 8,
+ kTRAILER_SIZE = 32, //sizeof(bplist_trailer_node),
+ kMINIMUM_SANE_SIZE = kHEADER_SIZE + kTRAILER_SIZE
+};
+
+
+static const char kHEADER_BYTES[kHEADER_SIZE] = "bplist00";
+
+// map from UID key to previously parsed value
+typedef struct cache_struct {
+ uint64_t key;
+ value_ptr value;
+ struct cache_struct *next;
+} cache_node, *cache_ptr;
+
+
+typedef struct bplist_info
+{
+ uint64_t object_count;
+ const uint8_t *data_bytes;
+ uint64_t length;
+ uint64_t offset_table_offset;
+ uint8_t offset_int_size;
+ uint8_t object_ref_size;
+ cache_ptr cache;
+} bplist_info_node, *bplist_info_ptr;
+
+
+static value_ptr bplist_read_pldata(pldata_ptr data);
+static value_ptr bplist_read_pref(char *filename, OSType folder_type);
+static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset, uint8_t size);
+static uint64_t read_offset(bplist_info_ptr bplist, uint64_t index);
+static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset, uint64_t *outValue, size_t *outSize);
+
+static value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef);
+static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_int(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset);
+static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset);
+
+
+value_ptr value_create()
+{
+ value_ptr value = (value_ptr) allocate(sizeof(value_node));
+ return value;
+}
+
+
+void value_set_integer(value_ptr v, int64_t i) {
+ v->tag = kTAG_INT; v->integer = i;
+}
+
+void value_set_real(value_ptr v, double d) {
+ v->tag = kTAG_REAL; v->real = d;
+}
+
+// d is seconds since 1 January 2001
+void value_set_date(value_ptr v, double d) {
+ v->tag = kTAG_DATE; v->real = d;
+}
+
+void value_set_ascii_string(value_ptr v, const uint8_t *s, size_t len) {
+ v->tag = kTAG_ASCIISTRING;
+ v->string = (char *) allocate(len + 1);
+ memcpy(v->string, s, len);
+ v->string[len] = 0;
+}
+
+void value_set_unicode_string(value_ptr v, const uint8_t *s, size_t len) {
+ v->tag = kTAG_UNICODESTRING;
+ v->string = (char *) allocate(len + 1);
+ memcpy(v->string, s, len);
+ v->string[len] = 0;
+}
+
+void value_set_uid(value_ptr v, uint64_t uid)
+{
+ v->tag = kTAG_UID; v->uinteger = uid;
+}
+
+// v->data points to a pldata that points to the actual bytes
+// the bytes are copied, so caller must free byte source (*data)
+void value_set_data(value_ptr v, const uint8_t *data, size_t len) {
+ v->tag = kTAG_DATA;
+ pldata_ptr pldata = (pldata_ptr) allocate(sizeof(pldata_node));
+ pldata->data = (uint8_t *) allocate(len);
+ memcpy(pldata->data, data, len);
+ pldata->len = len;
+ v->data = pldata;
+ printf("value at %p gets data at %p\n", v, pldata);
+}
+
+// caller releases ownership of array to value_ptr v
+void value_set_array(value_ptr v, value_ptr *array, size_t length) {
+ array_ptr a = (array_ptr) allocate(sizeof(array_node));
+ a->array = array;
+ a->length = length;
+ v->tag = kTAG_ARRAY;
+ v->array = a;
+}
+
+// caller releases ownership of dict to value_ptr v
+void value_set_dict(value_ptr v, dict_ptr dict) {
+ v->tag = kTAG_DICTIONARY;
+ v->dict = dict;
+}
+
+
+// look up an objectref in the cache, a ref->value_ptr mapping
+value_ptr cache_lookup(cache_ptr cache, uint64_t ref)
+{
+ while (cache) {
+ if (cache->key == ref) {
+ return cache->value;
+ }
+ cache = cache->next;
+ }
+ return NULL;
+}
+
+
+// insert an objectref and value in the cache
+void cache_insert(cache_ptr *cache, uint64_t ref, value_ptr value)
+{
+ cache_ptr c = (cache_ptr) allocate(sizeof(cache_node));
+ c->key = ref;
+ c->value = value;
+ c->next = *cache;
+ *cache = c;
+}
+
+
+// insert an objectref and value in a dictionary
+void dict_insert(dict_ptr *dict, value_ptr key, value_ptr value)
+{
+ dict_ptr d = (dict_ptr) allocate(sizeof(dict_node));
+ d->key = key;
+ d->value = value;
+ d->next = *dict;
+ *dict = d;
+}
+
+
+BOOL is_binary_plist(pldata_ptr data)
+{
+ if (data->len < kMINIMUM_SANE_SIZE) return NO;
+ return memcmp(data->data, kHEADER_BYTES, kHEADER_SIZE) == 0;
+}
+
+
+value_ptr bplist_read_file(char *filename)
+{
+ struct stat stbuf;
+ pldata_node pldata;
+ FILE *file;
+ size_t n;
+ value_ptr value;
+ int rslt = stat(filename, &stbuf);
+ if (rslt) {
+ #if BPLIST_LOG
+ perror("in stat");
+ #endif
+ bplist_log("Could not stat %s, error %d\n", filename, rslt);
+ return NULL;
+ }
+ // if file is >100MB, assume it is not a preferences file and give up
+ if (stbuf.st_size > 100000000) {
+ bplist_log("Large file %s encountered (%llu bytes) -- not read\n",
+ filename, stbuf.st_size);
+ return NULL;
+ }
+ pldata.len = (size_t) stbuf.st_size;
+ // note: this is supposed to be malloc, not allocate. It is separate
+ // from the graph structure, large, and easy to free right after
+ // parsing.
+ pldata.data = (uint8_t *) malloc(pldata.len);
+ if (!pldata.data) {
+ bplist_log("Could not allocate %lu bytes for %s\n",
+ (unsigned long) pldata.len, filename);
+ return NULL;
+ }
+ file = fopen(filename, "rb");
+ if (!file) {
+ bplist_log("Could not open %s\n", filename);
+ return NULL;
+ }
+ n = fread(pldata.data, 1, pldata.len, file);
+ if (n != pldata.len) {
+ bplist_log("Error reading from %s\n", filename);
+ return NULL;
+ }
+ value = bplist_read_pldata(&pldata);
+ free(pldata.data);
+ return value;
+}
+
+
+value_ptr bplist_read_pref(char *filename, OSType folder_type)
+{
+ FSRef prefdir;
+ char cstr[MAXPATHLEN];
+
+ OSErr err = FSFindFolder(kOnAppropriateDisk, folder_type,
+ FALSE, &prefdir);
+ if (err) {
+ bplist_log("Error finding preferences folder: %d\n", err);
+ return NULL;
+ }
+ err = FSRefMakePath(&prefdir, (UInt8 *) cstr, (UInt32) (MAXPATHLEN - 1));
+ if (err) {
+ bplist_log("Error making path name for preferences folder: %d\n", err);
+ return NULL;
+ }
+ strlcat(cstr, "/", MAXPATHLEN);
+ strlcat(cstr, filename, MAXPATHLEN);
+ return bplist_read_file(cstr);
+}
+
+
+value_ptr bplist_read_system_pref(char *filename) {
+ return bplist_read_pref(filename, kSystemPreferencesFolderType);
+}
+
+
+value_ptr bplist_read_user_pref(char *filename) {
+ return bplist_read_pref(filename, kPreferencesFolderType);
+}
+
+
+// data is stored with high-order bytes first.
+// read from plist data in a machine-independent fashion
+//
+uint64_t convert_uint64(uint8_t *ptr)
+{
+ uint64_t rslt = 0;
+ int i;
+ // shift in bytes, high-order first
+ for (i = 0; i < sizeof(uint64_t); i++) {
+ rslt <<= 8;
+ rslt += ptr[i];
+ }
+ return rslt;
+}
+
+
+value_ptr bplist_read_pldata(pldata_ptr data)
+{
+ value_ptr result = NULL;
+ bplist_info_node bplist;
+ uint8_t *ptr;
+ uint64_t top_level_object;
+ int i;
+
+ if (data == NULL) return NULL;
+ if (!is_binary_plist(data)) {
+ bplist_log("Bad binary plist: too short or invalid header.\n");
+ return NULL;
+ }
+
+ // read trailer
+ ptr = (uint8_t *) (data->data + data->len - kTRAILER_SIZE);
+ bplist.offset_int_size = ptr[6];
+ bplist.object_ref_size = ptr[7];
+ bplist.object_count = convert_uint64(ptr + 8);
+ top_level_object = convert_uint64(ptr + 16);
+ bplist.offset_table_offset = convert_uint64(ptr + 24);
+
+ // Basic sanity checks
+ if (bplist.offset_int_size < 1 || bplist.offset_int_size > 8 ||
+ bplist.object_ref_size < 1 || bplist.object_ref_size > 8 ||
+ bplist.offset_table_offset < kHEADER_SIZE) {
+ bplist_log("Bad binary plist: trailer declared insane.\n");
+ return NULL;
+ }
+
+ // Ensure offset table is inside file
+ uint64_t offsetTableSize = bplist.offset_int_size * bplist.object_count;
+ if (offsetTableSize + bplist.offset_table_offset + kTRAILER_SIZE >
+ data->len) {
+ bplist_log("Bad binary plist: offset table overlaps end of container.\n");
+ return NULL;
+ }
+
+ bplist.data_bytes = data->data;
+ bplist.length = data->len;
+ bplist.cache = NULL; /* dictionary is empty */
+
+ bplist_log_verbose("Got a sane bplist with %llu items, offset_int_size: %u, object_ref_size: %u\n",
+ bplist.object_count, bplist.offset_int_size,
+ bplist.object_ref_size);
+ /* at this point, we are ready to do some parsing which allocates
+ memory for the result data structure. If memory allocation (using
+ allocate fails, a longjmp will return to here and we simply give up
+ */
+ i = setjmp(abort_parsing);
+ if (i == 0) {
+ result = extract_object(&bplist, top_level_object);
+ } else {
+ bplist_log("allocate() failed to allocate memory. Giving up.\n");
+ result = NULL;
+ }
+ if (!result) {
+ bplist_free_data();
+ }
+ return result;
+}
+
+
+static value_ptr extract_object(bplist_info_ptr bplist, uint64_t objectRef)
+{
+ uint64_t offset;
+ value_ptr result = NULL;
+ uint8_t objectTag;
+
+ if (objectRef >= bplist->object_count) {
+ // Out-of-range object reference.
+ bplist_log("Bad binary plist: object index is out of range.\n");
+ return NULL;
+ }
+
+ // Use cached object if it exists
+ result = cache_lookup(bplist->cache, objectRef);
+ if (result != NULL) return result;
+
+ // Otherwise, find object in file.
+ offset = read_offset(bplist, objectRef);
+ if (offset > bplist->length) {
+ // Out-of-range offset.
+ bplist_log("Bad binary plist: object outside container.\n");
+ return NULL;
+ }
+ objectTag = *(bplist->data_bytes + offset);
+ switch (objectTag & 0xF0) {
+ case kTAG_SIMPLE:
+ result = extract_simple(bplist, offset);
+ break;
+
+ case kTAG_INT:
+ result = extract_int(bplist, offset);
+ break;
+
+ case kTAG_REAL:
+ result = extract_real(bplist, offset);
+ break;
+
+ case kTAG_DATE:
+ result = extract_date(bplist, offset);
+ break;
+
+ case kTAG_DATA:
+ result = extract_data(bplist, offset);
+ break;
+
+ case kTAG_ASCIISTRING:
+ result = extract_ascii_string(bplist, offset);
+ break;
+
+ case kTAG_UNICODESTRING:
+ result = extract_unicode_string(bplist, offset);
+ break;
+
+ case kTAG_UID:
+ result = extract_uid(bplist, offset);
+ break;
+
+ case kTAG_ARRAY:
+ result = extract_array(bplist, offset);
+ break;
+
+ case kTAG_DICTIONARY:
+ result = extract_dictionary(bplist, offset);
+ break;
+
+ default:
+ // Unknown tag.
+ bplist_log("Bad binary plist: unknown tag 0x%X.\n",
+ (objectTag & 0x0F) >> 4);
+ result = NULL;
+ }
+
+ // Cache and return result.
+ if (result != NULL)
+ cache_insert(&bplist->cache, objectRef, result);
+ return result;
+}
+
+
+static uint64_t read_sized_int(bplist_info_ptr bplist, uint64_t offset,
+ uint8_t size)
+{
+ assert(bplist->data_bytes != NULL && size >= 1 && size <= 8 &&
+ offset + size <= bplist->length);
+
+ uint64_t result = 0;
+ const uint8_t *byte = bplist->data_bytes + offset;
+
+ do {
+ // note that ints seem to be high-order first
+ result = (result << 8) | *byte++;
+ } while (--size);
+
+ return result;
+}
+
+
+static uint64_t read_offset(bplist_info_ptr bplist, uint64_t index)
+{
+ assert(index < bplist->object_count);
+
+ return read_sized_int(bplist,
+ bplist->offset_table_offset + bplist->offset_int_size * index,
+ bplist->offset_int_size);
+}
+
+
+static BOOL read_self_sized_int(bplist_info_ptr bplist, uint64_t offset,
+ uint64_t *outValue, size_t *outSize)
+{
+ uint32_t size;
+ int64_t value;
+
+ assert(bplist->data_bytes != NULL && offset < bplist->length);
+
+ size = 1 << (bplist->data_bytes[offset] & 0x0F);
+ if (size > 8) {
+ // Maximum allowable size in this implementation is 1<<3 = 8 bytes.
+ // This also happens to be the biggest we can handle.
+ return NO;
+ }
+
+ if (offset + 1 + size > bplist->length) {
+ // Out of range.
+ return NO;
+ }
+
+ value = read_sized_int(bplist, offset + 1, size);
+
+ if (outValue != NULL) *outValue = value;
+ if (outSize != NULL) *outSize = size + 1; // +1 for tag byte.
+ return YES;
+}
+
+
+static value_ptr extract_simple(bplist_info_ptr bplist, uint64_t offset)
+{
+ assert(bplist->data_bytes != NULL && offset < bplist->length);
+ value_ptr value = value_create();
+
+ switch (bplist->data_bytes[offset]) {
+ case kVALUE_NULL:
+ value->tag = kVALUE_NULL;
+ return value;
+
+ case kVALUE_TRUE:
+ value->tag = kVALUE_TRUE;
+ return value;
+
+ case kVALUE_FALSE:
+ value->tag = kVALUE_FALSE;
+ return value;
+ }
+
+ // Note: kVALUE_FILLER is treated as invalid, because it, er, is.
+ bplist_log("Bad binary plist: invalid atom.\n");
+ free(value);
+ return NULL;
+}
+
+
+static value_ptr extract_int(bplist_info_ptr bplist, uint64_t offset)
+{
+ value_ptr value = value_create();
+ value->tag = kTAG_INT;
+
+ if (!read_self_sized_int(bplist, offset, &value->uinteger, NULL)) {
+ bplist_log("Bad binary plist: invalid integer object.\n");
+ }
+
+ /* NOTE: originally, I sign-extended here. This was the wrong thing; it
+ turns out that negative ints are always stored as 64-bit, and smaller
+ ints are unsigned.
+ */
+ return value;
+}
+
+
+static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset)
+{
+ value_ptr value = value_create();
+ uint32_t size;
+
+ assert(bplist->data_bytes != NULL && offset < bplist->length);
+
+ size = 1 << (bplist->data_bytes[offset] & 0x0F);
+
+ // FIXME: what to do if faced with other sizes for float/double?
+ assert (sizeof (float) == sizeof (uint32_t) &&
+ sizeof (double) == sizeof (uint64_t));
+
+ if (offset + 1 + size > bplist->length) {
+ bplist_log("Bad binary plist: %s object overlaps end of container.\n",
+ "floating-point number");
+ free(value);
+ return NULL;
+ }
+
+ if (size == sizeof (float)) {
+ // cast is ok because we know size is 4 bytes
+ uint32_t i = (uint32_t) read_sized_int(bplist, offset + 1, size);
+ // Note that this handles byte swapping.
+ value_set_real(value, *(float *)&i);
+ return value;
+ } else if (size == sizeof (double)) {
+ uint64_t i = read_sized_int(bplist, offset + 1, size);
+ // Note that this handles byte swapping.
+ value_set_real(value, *(double *)&i);
+ return value;
+ } else {
+ // Can't handle floats of other sizes.
+ bplist_log("Bad binary plist: can't handle %u-byte float.\n", size);
+ free(value);
+ return NULL;
+ }
+}
+
+
+static value_ptr extract_date(bplist_info_ptr bplist, uint64_t offset)
+{
+ value_ptr value;
+ assert(bplist->data_bytes != NULL && offset < bplist->length);
+
+ // Data has size code like int and real, but only 3 (meaning 8 bytes) is valid.
+ if (bplist->data_bytes[offset] != kVALUE_FULLDATETAG) {
+ bplist_log("Bad binary plist: invalid size for date object.\n");
+ return NULL;
+ }
+
+ if (offset + 1 + sizeof (double) > bplist->length) {
+ bplist_log("Bad binary plist: %s object overlaps end of container.\n",
+ "date");
+ return NULL;
+ }
+
+ // FIXME: what to do if faced with other sizes for double?
+ assert (sizeof (double) == sizeof (uint64_t));
+
+ uint64_t date = read_sized_int(bplist, offset + 1, sizeof(double));
+ // Note that this handles byte swapping.
+ value = value_create();
+ value_set_date(value, *(double *)&date);
+ return value;
+}
+
+
+uint64_t bplist_get_a_size(bplist_info_ptr bplist,
+ uint64_t *offset_ptr, char *msg)
+{
+ uint64_t size = bplist->data_bytes[*offset_ptr] & 0x0F;
+ (*offset_ptr)++;
+ if (size == 0x0F) {
+ // 0x0F means separate int size follows.
+ // Smaller values are used for short data.
+ size_t extra; // the length of the data size we are about to read
+ if ((bplist->data_bytes[*offset_ptr] & 0xF0) != kTAG_INT) {
+ // Bad data, mistagged size int
+ bplist_log("Bad binary plist: %s object size is not tagged as int.\n",
+ msg);
+ return UINT64_MAX; // error
+ }
+
+ // read integer data as size, extra tells how many bytes to skip
+ if (!read_self_sized_int(bplist, *offset_ptr, &size, &extra)) {
+ bplist_log("Bad binary plist: invalid %s object size tag.\n",
+ "data");
+ return UINT64_MAX; // error
+ }
+ (*offset_ptr) += extra;
+ }
+
+ if (*offset_ptr + size > bplist->length) {
+ bplist_log("Bad binary plist: %s object overlaps end of container.\n",
+ "data");
+ return UINT64_MAX; // error
+ }
+ return size;
+}
+
+
+static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset)
+{
+ uint64_t size;
+ value_ptr value;
+
+ assert(bplist->data_bytes != NULL && offset < bplist->length);
+
+ if ((size = bplist_get_a_size(bplist, &offset, "data")) == UINT64_MAX)
+ return NULL;
+
+ value = value_create();
+ // cast is ok because we only allow files up to 100MB:
+ value_set_data(value, bplist->data_bytes + (size_t) offset, (size_t) size);
+ return value;
+}
+
+
+static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset)
+{
+ uint64_t size;
+ value_ptr value; // return value
+
+ assert(bplist->data_bytes != NULL && offset < bplist->length);
+
+ if ((size = bplist_get_a_size(bplist, &offset, "ascii string")) ==
+ UINT64_MAX)
+ return NULL;
+
+ value = value_create();
+ // cast is ok because we only allow 100MB files
+ value_set_ascii_string(value, bplist->data_bytes + (size_t) offset,
+ (size_t) size);
+ return value;
+}
+
+
+static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset)
+{
+ uint64_t size;
+ value_ptr value;
+
+ assert(bplist->data_bytes != NULL && offset < bplist->length);
+
+ if ((size = bplist_get_a_size(bplist, &offset, "unicode string")) ==
+ UINT64_MAX)
+ return NULL;
+
+ value = value_create();
+ // cast is ok because we only allow 100MB files
+ value_set_unicode_string(value, bplist->data_bytes + (size_t) offset,
+ (size_t) size);
+ return value;
+}
+
+
+static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset)
+{
+ /* UIDs are used by Cocoa's key-value coder.
+ When writing other plist formats, they are expanded to dictionaries of
+ the form <dict><key>CF$UID</key><integer>value</integer></dict>, so we
+ do the same here on reading. This results in plists identical to what
+ running plutil -convert xml1 gives us. However, this is not the same
+ result as [Core]Foundation's plist parser, which extracts them as un-
+ introspectable CF objects. In fact, it even seems to convert the CF$UID
+ dictionaries from XML plists on the fly.
+ */
+
+ value_ptr value;
+ uint64_t uid;
+
+ if (!read_self_sized_int(bplist, offset, &uid, NULL)) {
+ bplist_log("Bad binary plist: invalid UID object.\n");
+ return NULL;
+ }
+
+ // assert(NO); // original code suggests using a string for a key
+ // but our dictionaries all use big ints for keys, so I don't know
+ // what to do here
+
+ // In practice, I believe this code is never executed by PortMidi.
+ // I changed it to do something and not raise compiler warnings, but
+ // not sure what the code should do.
+
+ value = value_create();
+ value_set_uid(value, uid);
+ // return [NSDictionary dictionaryWithObject:
+ // [NSNumber numberWithUnsignedLongLong:value]
+ // forKey:"CF$UID"];
+ return value;
+}
+
+
+static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset)
+{
+ uint64_t i, count;
+ uint64_t size;
+ uint64_t elementID;
+ value_ptr element = NULL;
+ value_ptr *array = NULL;
+ value_ptr value = NULL;
+ BOOL ok = YES;
+
+ assert(bplist->data_bytes != NULL && offset < bplist->length);
+
+ if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX)
+ return NULL;
+
+ if (count > UINT64_MAX / bplist->object_ref_size - offset) {
+ // Offset overflow.
+ bplist_log("Bad binary plist: %s object overlaps end of container.\n",
+ "array");
+ return NULL;
+ }
+
+ size = bplist->object_ref_size * count;
+ if (size + offset > bplist->length) {
+ bplist_log("Bad binary plist: %s object overlaps end of container.\n",
+ "array");
+ return NULL;
+ }
+
+ // got count, the number of array elements
+
+ value = value_create();
+ assert(value);
+
+ if (count == 0) {
+ // count must be size_t or smaller because max file size is 100MB
+ value_set_array(value, array, (size_t) count);
+ return value;
+ }
+
+ array = allocate(sizeof(value_ptr) * (size_t) count);
+
+ for (i = 0; i != count; ++i) {
+ bplist_log_verbose("[%u]\n", i);
+ elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size,
+ bplist->object_ref_size);
+ element = extract_object(bplist, elementID);
+ if (element != NULL) {
+ array[i] = element;
+ } else {
+ ok = NO;
+ break;
+ }
+ }
+ if (ok) { // count is smaller than size_t max because of 100MB file limit
+ value_set_array(value, array, (size_t) count);
+ }
+
+ return value;
+}
+
+
+static value_ptr extract_dictionary(bplist_info_ptr bplist, uint64_t offset)
+{
+ uint64_t i, count;
+ uint64_t size;
+ uint64_t elementID;
+ value_ptr value = NULL;
+ dict_ptr dict = NULL;
+ BOOL ok = YES;
+
+ assert(bplist->data_bytes != NULL && offset < bplist->length);
+
+
+ if ((count = bplist_get_a_size(bplist, &offset, "array")) == UINT64_MAX)
+ return NULL;
+
+ if (count > UINT64_MAX / (bplist->object_ref_size * 2) - offset) {
+ // Offset overflow.
+ bplist_log("Bad binary plist: %s object overlaps end of container.\n",
+ "dictionary");
+ return NULL;
+ }
+
+ size = bplist->object_ref_size * count * 2;
+ if (size + offset > bplist->length) {
+ bplist_log("Bad binary plist: %s object overlaps end of container.\n",
+ "dictionary");
+ return NULL;
+ }
+
+ value = value_create();
+ if (count == 0) {
+ value_set_dict(value, NULL);
+ return value;
+ }
+
+ for (i = 0; i != count; ++i) {
+ value_ptr key;
+ value_ptr val;
+ elementID = read_sized_int(bplist, offset + i * bplist->object_ref_size,
+ bplist->object_ref_size);
+ key = extract_object(bplist, elementID);
+ if (key != NULL) {
+ bplist_log_verbose("key: %p\n", key);
+ } else {
+ ok = NO;
+ break;
+ }
+
+ elementID = read_sized_int(bplist,
+ offset + (i + count) * bplist->object_ref_size,
+ bplist->object_ref_size);
+ val = extract_object(bplist, elementID);
+ if (val != NULL) {
+ dict_insert(&dict, key, val);
+ } else {
+ ok = NO;
+ break;
+ }
+ }
+ if (ok) {
+ value_set_dict(value, dict);
+ }
+
+ return value;
+}
+
+/*************** functions for accessing values ****************/
+
+
+char *value_get_asciistring(value_ptr v)
+{
+ if (v->tag != kTAG_ASCIISTRING) return NULL;
+ return v->string;
+}
+
+
+value_ptr value_dict_lookup_using_string(value_ptr v, char *key)
+{
+ dict_ptr dict;
+ if (v->tag != kTAG_DICTIONARY) return NULL; // not a dictionary
+ dict = v->dict;
+ /* search for key */
+ while (dict) {
+ if (dict->key && dict->key->tag == kTAG_ASCIISTRING &&
+ strcmp(key, dict->key->string) == 0) { // found it
+ return dict->value;
+ }
+ dict = dict->next;
+ }
+ return NULL; /* not found */
+}
+
+value_ptr value_dict_lookup_using_path(value_ptr v, char *path)
+{
+ char key[MAX_KEY_SIZE];
+ while (*path) { /* more to the path */
+ int i = 0;
+ while (i < MAX_KEY_SIZE - 1) {
+ key[i] = *path++;
+ if (key[i] == '/') { /* end of entry in path */
+ key[i + 1] = 0;
+ break;
+ }
+ if (!key[i]) {
+ path--; /* back up to end of string char */
+ break; /* this will cause outer loop to exit */
+ }
+ i++;
+ }
+ if (!v || v->tag != kTAG_DICTIONARY) return NULL;
+ /* now, look up the key to get next value */
+ v = value_dict_lookup_using_string(v, key);
+ if (v == NULL) return NULL;
+ }
+ return v;
+}
+
+
+/*************** functions for debugging ***************/
+
+void plist_print(value_ptr v)
+{
+ size_t i;
+ int comma_needed;
+ dict_ptr dict;
+ if (!v) {
+ printf("NULL");
+ return;
+ }
+ switch (v->tag & 0xF0) {
+ case kTAG_SIMPLE:
+ switch (v->tag) {
+ case kVALUE_NULL:
+ printf("NULL@%p", v); break;
+ case kVALUE_FALSE:
+ printf("FALSE@%p", v); break;
+ case kVALUE_TRUE:
+ printf("TRUE@%p", v); break;
+ default:
+ printf("UNKNOWN tag=%x@%p", v->tag, v); break;
+ }
+ break;
+ case kTAG_INT:
+ printf("%lld@%p", v->integer, v); break;
+ case kTAG_REAL:
+ printf("%g@%p", v->real, v); break;
+ case kTAG_DATE:
+ printf("date:%g@%p", v->real, v); break;
+ case kTAG_DATA:
+ printf("data@%p->%p:[%p:", v, v->data, v->data->data);
+ for (i = 0; i < v->data->len; i++) {
+ printf(" %2x", v->data->data[i]);
+ }
+ printf("]"); break;
+ case kTAG_ASCIISTRING:
+ printf("%p:\"%s\"@%p", v->string, v->string, v); break;
+ case kTAG_UNICODESTRING:
+ printf("unicode:%p:\"%s\"@%p", v->string, v->string, v); break;
+ case kTAG_UID:
+ printf("UID:%llu@%p", v->uinteger, v); break;
+ case kTAG_ARRAY:
+ comma_needed = FALSE;
+ printf("%p->%p:[%p:", v, v->array, v->array->array);
+ for (i = 0; i < v->array->length; i++) {
+ if (comma_needed) printf(", ");
+ plist_print(v->array->array[i]);
+ comma_needed = TRUE;
+ }
+ printf("]"); break;
+ case kTAG_DICTIONARY:
+ comma_needed = FALSE;
+ printf("%p:[", v);
+ dict = v->dict;
+ while (dict) {
+ if (comma_needed) printf(", ");
+ printf("%p:", dict);
+ plist_print(dict->key);
+ printf("->");
+ plist_print(dict->value);
+ comma_needed = TRUE;
+ dict = dict->next;
+ }
+ printf("]"); break;
+ default:
+ printf("UNKNOWN tag=%x", v->tag);
+ break;
+ }
+}
+
+
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_win/pmwin.c b/libs/backends/wavesaudio/portmidi/src/pm_win/pmwin.c
index aeed48554d..5b4dec63fc 100644
--- a/libs/backends/wavesaudio/portmidi/src/pm_win/pmwin.c
+++ b/libs/backends/wavesaudio/portmidi/src/pm_win/pmwin.c
@@ -1,143 +1,143 @@
-/* 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);
-}
-
-
+/* 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);
+}
+
+
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.c b/libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.c
index 2de8109a0a..ab66f80dc1 100644
--- a/libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.c
+++ b/libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.c
@@ -1,1464 +1,1464 @@
-/* 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;
-}
+/* 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;
+}
diff --git a/libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.h b/libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.h
index 94742001bc..53c5fe2841 100644
--- a/libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.h
+++ b/libs/backends/wavesaudio/portmidi/src/pm_win/pmwinmm.h
@@ -1,5 +1,5 @@
-/* midiwin32.h -- system-specific definitions */
-
-void pm_winmm_init( void );
-void pm_winmm_term( void );
-
+/* midiwin32.h -- system-specific definitions */
+
+void pm_winmm_init( void );
+void pm_winmm_term( void );
+
diff --git a/libs/backends/wavesaudio/portmidi/src/porttime/ptmacosx_mach.c b/libs/backends/wavesaudio/portmidi/src/porttime/ptmacosx_mach.c
index c23210e4dc..753f5832ef 100644
--- a/libs/backends/wavesaudio/portmidi/src/porttime/ptmacosx_mach.c
+++ b/libs/backends/wavesaudio/portmidi/src/porttime/ptmacosx_mach.c
@@ -1,131 +1,131 @@
-/* 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);
-}
+/* 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);
+}
diff --git a/libs/backends/wavesaudio/portmidi/src/porttime/ptwinmm.c b/libs/backends/wavesaudio/portmidi/src/porttime/ptwinmm.c
deleted file mode 100644
index 17675bd6c6..0000000000
--- a/libs/backends/wavesaudio/portmidi/src/porttime/ptwinmm.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* ptwinmm.c -- portable timer implementation for win32 */
-
-
-#include "porttime.h"
-#include "windows.h"
-#include "time.h"
-
-
-TIMECAPS caps;
-
-static long time_offset = 0;
-static int time_started_flag = FALSE;
-static long time_resolution;
-static MMRESULT timer_id;
-static PtCallback *time_callback;
-
-void CALLBACK winmm_time_callback(UINT uID, UINT uMsg, DWORD_PTR dwUser,
- DWORD_PTR dw1, DWORD_PTR dw2)
-{
- (*time_callback)(Pt_Time(), (void *) dwUser);
-}
-
-
-PMEXPORT PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
-{
- if (time_started_flag) return ptAlreadyStarted;
- timeBeginPeriod(resolution);
- time_resolution = resolution;
- time_offset = timeGetTime();
- time_started_flag = TRUE;
- time_callback = callback;
- if (callback) {
- timer_id = timeSetEvent(resolution, 1, winmm_time_callback,
- (DWORD_PTR) userData, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
- if (!timer_id) return ptHostError;
- }
- return ptNoError;
-}
-
-
-PMEXPORT PtError Pt_Stop()
-{
- if (!time_started_flag) return ptAlreadyStopped;
- if (time_callback && timer_id) {
- timeKillEvent(timer_id);
- time_callback = NULL;
- timer_id = 0;
- }
- time_started_flag = FALSE;
- timeEndPeriod(time_resolution);
- return ptNoError;
-}
-
-
-PMEXPORT int Pt_Started()
-{
- return time_started_flag;
-}
-
-
-PMEXPORT PtTimestamp Pt_Time()
-{
- return timeGetTime() - time_offset;
-}
-
-
-PMEXPORT void Pt_Sleep(int32_t duration)
-{
- Sleep(duration);
-}
diff --git a/libs/backends/wavesaudio/waves_audiobackend.cc b/libs/backends/wavesaudio/waves_audiobackend.cc
index 4691163f6d..0d54752782 100644
--- a/libs/backends/wavesaudio/waves_audiobackend.cc
+++ b/libs/backends/wavesaudio/waves_audiobackend.cc
@@ -1,1375 +1,1184 @@
-/*
- 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 ();
-}
-
-
-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 ();
-} \ No newline at end of file
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "waves_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" << std::endl;
+ 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: " << (int64_t)parameter << std::endl;
+ break;
+ case WCMRAudioDeviceManagerClient::DeviceDroppedSamples:
+ std::cout << "------------------------------- WCMRAudioDeviceManagerClient::DeviceDroppedSamples" << std::endl;
+ break;
+ case WCMRAudioDeviceManagerClient::DeviceStoppedStreaming:
+ std::cout << "------------------------------- WCMRAudioDeviceManagerClient::DeviceStoppedStreaming" << std::endl;
+ break;
+ case WCMRAudioDeviceManagerClient::DeviceConnectionLost:
+ std::cout << "------------------------------- WCMRAudioDeviceManagerClient::DeviceConnectionLost" << std::endl;
+ break;
+ case WCMRAudioDeviceManagerClient::DeviceListChanged:
+ std::cout << "------------------------------- WCMRAudioDeviceManagerClient::DeviceListChanged" << std::endl;
+ 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)
+ , _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 (false)
+ , _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 WCMRAudioDeviceList& devices = _audio_device_manager.Devices ();
+
+ for (WCMRAudioDeviceListConstIter deviceIter = devices.begin (); deviceIter != devices.end (); ++deviceIter) {
+ /* COMMENTED DBG LOGS */ std::cout << "\t Device found: " << (*deviceIter)->DeviceName () << std::endl;
+ devicesStatus.push_back (DeviceStatus ((*deviceIter)->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;
+
+ std::vector<int> sr;
+
+ WCMRAudioDevice * device = _audio_device_manager.GetDeviceByName (device_name);
+
+ if (!device) {
+ std::cerr << "WavesAudioBackend::available_sample_rates (): Failed to find device [" << device_name << "]" << std::endl;
+ return std::vector<float> ();
+ }
+
+ sr = device->SamplingRates ();
+ /* COMMENTED DBG LOGS */ std::cout << "\tFound " << sr.size () << " sample rates for " << device->DeviceName () << ":";
+
+ std::vector<float> sample_rates (sr.begin (), sr.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 ():" << 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;
+
+ WCMRAudioDevice * device = _audio_device_manager.GetDeviceByName (device_name);
+ if (!device) {
+ std::cerr << "WavesAudioBackend::available_buffer_sizes (): Failed to find device [" << device_name << "]" << std::endl;
+ return std::vector<uint32_t> ();
+ }
+
+ std::vector<uint32_t> buffer_sizes (device->BufferSizes ().begin (), device->BufferSizes ().end ());
+
+ /* COMMENTED DBG LOGS */ std::cout << "\tFound " << buffer_sizes.size () << " buffer sizes for " << device->DeviceName () << ":";
+ /* 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
+{
+
+ WCMRAudioDevice * device = _audio_device_manager.GetDeviceByName (device_name);
+
+ if (!device) {
+ std::cerr << "WavesAudioBackend::available_input_channel_count (): Failed to find device [" << device_name << "]" << std::endl;
+ return 0;
+ }
+
+ uint32_t num_of_input_channels = device->InputChannels ().size ();
+
+ /* 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
+{
+ std::vector<std::string> output_channels;
+
+ WCMRAudioDevice * device = _audio_device_manager.GetDeviceByName (device_name);
+ if (!device) {
+ std::cerr << "WavesAudioBackend::available_output_channel_count (): Failed to find device [" << device_name << "]" << std::endl;
+ return 0;
+ }
+
+ uint32_t num_of_output_channels = device->OutputChannels ().size ();
+
+ /* 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;
+ }
+
+ WCMRAudioDevice * device = _audio_device_manager.GetDeviceByName (device_name);
+
+ if (!device) {
+ std::cerr << "WavesAudioBackend::set_device_name (): Failed to find device [" << device_name << "]!" << std::endl;
+ return -1;
+ }
+
+ 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;
+ }
+ }
+
+ _device = NULL;
+
+ 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::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 = sample_rate;
+ _init_dsp_load_history();
+ engine.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_sample_rate (): [" << _device->DeviceName() << "]->SetCurrentBufferSize (" << buffer_size << ") failed (" << retVal << ") !" << std::endl;
+ return -1;
+ }
+
+ _buffer_size = buffer_size;
+ _init_dsp_load_history();
+ engine.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_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
+{
+ /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::device_name (): " << _device->DeviceName () << std::endl;
+ if (!_device) {
+ return "";
+ }
+ 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;
+}
+
+
+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) {
+ std::cout << _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 retVal = eNoErr;
+
+ if (!_device) {
+ std::cerr << "WavesAudioBackend::stop (): No device is set!" << std::endl;
+ return -1;
+ }
+
+ /* COMMENTED DBG LOGS */ std::cout << "\t[" << _device->DeviceName () << "]" << std::endl;
+
+ retVal = _device->SetStreaming (false);
+ if (retVal != eNoErr) {
+ std::cerr << "WavesAudioBackend::stop (): [" << _device->DeviceName () << "]->SetStreaming () failed!" << std::endl;
+ return -1;
+ }
+
+ _midi_device_manager.stop ();
+
+ _unregister_system_audio_ports ();
+ _unregister_system_midi_ports ();
+ return 0;
+}
+
+
+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 << " 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,
+};
+
+
+extern "C" ARDOURBACKEND_API ARDOUR::AudioBackendInfo* descriptor ()
+{
+ /* COMMENTED DBG LOGS */ std::cout << "waves_backend.dll : ARDOUR::AudioBackendInfo* descriptor (): " << std::endl;
+ return &WavesAudioBackend::backend_info ();
+}
diff --git a/libs/backends/wavesaudio/waves_audiobackend.h b/libs/backends/wavesaudio/waves_audiobackend.h
index 6fd91913d1..3a56f7b55a 100644
--- a/libs/backends/wavesaudio/waves_audiobackend.h
+++ b/libs/backends/wavesaudio/waves_audiobackend.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Valeriy Kamyshniy
+ Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -41,7 +41,7 @@
class ArdourAudioDeviceManager : public WCMRCoreAudioDeviceManager
{
public:
- ArdourAudioDeviceManager (WCMRAudioDeviceManagerClient *client) : WCMRCoreAudioDeviceManager (client, eAllDevices) {};
+ ArdourAudioDeviceManager (WCMRAudioDeviceManagerClient *client) : WCMRCoreAudioDeviceManager (client, eFullDuplexDevices, true, eCABS_Simple, false) {};
};
#elif defined (_WINDOWS)
@@ -51,7 +51,7 @@ class ArdourAudioDeviceManager : public WCMRCoreAudioDeviceManager
class ArdourAudioDeviceManager : public WCMRPortAudioDeviceManager
{
public:
- ArdourAudioDeviceManager (WCMRAudioDeviceManagerClient *client) : WCMRPortAudioDeviceManager (client, eAllDevices) {};
+ ArdourAudioDeviceManager (WCMRAudioDeviceManagerClient *client) : WCMRPortAudioDeviceManager (client, eFullDuplexDevices, paASIO) {};
};
#endif
@@ -103,14 +103,10 @@ 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);
@@ -127,8 +123,6 @@ class WavesMidiPort;
virtual uint32_t buffer_size () const;
- virtual SampleFormat sample_format () const;
-
virtual bool interleaved () const;
virtual uint32_t input_channels () const;
@@ -281,7 +275,6 @@ class WavesMidiPort;
WavesMidiDeviceManager _midi_device_manager;
WCMRAudioDevice *_device;
- SampleFormat _sample_format;
bool _interleaved;
static std::string __instantiated_name;
uint32_t _input_channels;
@@ -324,15 +317,8 @@ 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 ();
diff --git a/libs/backends/wavesaudio/waves_audiobackend.latency.cc b/libs/backends/wavesaudio/waves_audiobackend.latency.cc
index e1869cbf1f..c0d2fcd315 100644
--- a/libs/backends/wavesaudio/waves_audiobackend.latency.cc
+++ b/libs/backends/wavesaudio/waves_audiobackend.latency.cc
@@ -1,90 +1,90 @@
-/*
- 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);
-}
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "waves_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);
+}
diff --git a/libs/backends/wavesaudio/waves_audiobackend.midi.cc b/libs/backends/wavesaudio/waves_audiobackend.midi.cc
index 13019b9a99..94c674d073 100644
--- a/libs/backends/wavesaudio/waves_audiobackend.midi.cc
+++ b/libs/backends/wavesaudio/waves_audiobackend.midi.cc
@@ -1,353 +1,354 @@
-/*
- 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;
-}
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <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;
+}
diff --git a/libs/backends/wavesaudio/waves_audiobackend.port_engine.cc b/libs/backends/wavesaudio/waves_audiobackend.port_engine.cc
index f798ff4c14..6225468864 100644
--- a/libs/backends/wavesaudio/waves_audiobackend.port_engine.cc
+++ b/libs/backends/wavesaudio/waves_audiobackend.port_engine.cc
@@ -1,654 +1,654 @@
-/*
- 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 ();
-}
-
-
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "waves_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 ();
+}
+
+
diff --git a/libs/backends/wavesaudio/waves_audioport.cc b/libs/backends/wavesaudio/waves_audioport.cc
index 600066b83c..62bacdbcea 100644
--- a/libs/backends/wavesaudio/waves_audioport.cc
+++ b/libs/backends/wavesaudio/waves_audioport.cc
@@ -1,62 +1,62 @@
-/*
- 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
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "waves_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));
+}
diff --git a/libs/backends/wavesaudio/waves_audioport.h b/libs/backends/wavesaudio/waves_audioport.h
index e377760fc4..a0f878bee5 100644
--- a/libs/backends/wavesaudio/waves_audioport.h
+++ b/libs/backends/wavesaudio/waves_audioport.h
@@ -1,58 +1,58 @@
-/*
- 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__ */
-
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_waves_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__ */
+
diff --git a/libs/backends/wavesaudio/waves_dataport.cc b/libs/backends/wavesaudio/waves_dataport.cc
index f97bd97846..84f4efaf6c 100644
--- a/libs/backends/wavesaudio/waves_dataport.cc
+++ b/libs/backends/wavesaudio/waves_dataport.cc
@@ -1,142 +1,142 @@
-/*
- 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;
-}
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "waves_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;
+}
diff --git a/libs/backends/wavesaudio/waves_dataport.h b/libs/backends/wavesaudio/waves_dataport.h
index d8b095351c..fd8dd8090b 100644
--- a/libs/backends/wavesaudio/waves_dataport.h
+++ b/libs/backends/wavesaudio/waves_dataport.h
@@ -1,115 +1,115 @@
-/*
- 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__ */
-
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_waves_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__ */
+
diff --git a/libs/backends/wavesaudio/waves_midi_buffer.cc b/libs/backends/wavesaudio/waves_midi_buffer.cc
index 03f5ca71db..24527de0e5 100644
--- a/libs/backends/wavesaudio/waves_midi_buffer.cc
+++ b/libs/backends/wavesaudio/waves_midi_buffer.cc
@@ -1,49 +1,50 @@
-/*
- 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;
-}
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "waves_midi_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;
+}
diff --git a/libs/backends/wavesaudio/waves_midi_buffer.h b/libs/backends/wavesaudio/waves_midi_buffer.h
index 5e58b783bb..b1f6e90c36 100644
--- a/libs/backends/wavesaudio/waves_midi_buffer.h
+++ b/libs/backends/wavesaudio/waves_midi_buffer.h
@@ -1,48 +1,47 @@
-/*
- 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__ */
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef __libardour_waves_midi_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__ */
diff --git a/libs/backends/wavesaudio/waves_midi_device.cc b/libs/backends/wavesaudio/waves_midi_device.cc
index 0f84c6d262..aa305955a6 100644
--- a/libs/backends/wavesaudio/waves_midi_device.cc
+++ b/libs/backends/wavesaudio/waves_midi_device.cc
@@ -1,268 +1,268 @@
-/*
- 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;
-}
-
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "waves_midi_device.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;
+}
+
diff --git a/libs/backends/wavesaudio/waves_midi_device.h b/libs/backends/wavesaudio/waves_midi_device.h
index ce3bb3c486..a8b734736d 100644
--- a/libs/backends/wavesaudio/waves_midi_device.h
+++ b/libs/backends/wavesaudio/waves_midi_device.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Gorobchenko Dmytro
+ Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/libs/backends/wavesaudio/waves_midi_device_manager.cc b/libs/backends/wavesaudio/waves_midi_device_manager.cc
index f3cd7424c9..84667a2dbd 100644
--- a/libs/backends/wavesaudio/waves_midi_device_manager.cc
+++ b/libs/backends/wavesaudio/waves_midi_device_manager.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Paul Davis
+ Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/libs/backends/wavesaudio/waves_midi_device_manager.h b/libs/backends/wavesaudio/waves_midi_device_manager.h
index 9d9124fc83..75a2757f90 100644
--- a/libs/backends/wavesaudio/waves_midi_device_manager.h
+++ b/libs/backends/wavesaudio/waves_midi_device_manager.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Gorobchenko Dmytro
+ Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/libs/backends/wavesaudio/waves_midi_event.cc b/libs/backends/wavesaudio/waves_midi_event.cc
index 08b8bdfc65..532555c958 100644
--- a/libs/backends/wavesaudio/waves_midi_event.cc
+++ b/libs/backends/wavesaudio/waves_midi_event.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Valeriy amyshniy
+ Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include "memory.h"
#include "waves_midi_event.h"
diff --git a/libs/backends/wavesaudio/waves_midi_event.h b/libs/backends/wavesaudio/waves_midi_event.h
index 510438e888..9015a2ce81 100644
--- a/libs/backends/wavesaudio/waves_midi_event.h
+++ b/libs/backends/wavesaudio/waves_midi_event.h
@@ -1,75 +1,75 @@
-/*
- 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__ */
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_waves_midi_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__ */
diff --git a/libs/backends/wavesaudio/waves_midiport.cc b/libs/backends/wavesaudio/waves_midiport.cc
index cadf36eb2a..8a77776c5e 100644
--- a/libs/backends/wavesaudio/waves_midiport.cc
+++ b/libs/backends/wavesaudio/waves_midiport.cc
@@ -1,61 +1,61 @@
-/*
- 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
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "waves_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 ();
+}
diff --git a/libs/backends/wavesaudio/waves_midiport.h b/libs/backends/wavesaudio/waves_midiport.h
index 09bbf1b1f0..6df1c2b04a 100644
--- a/libs/backends/wavesaudio/waves_midiport.h
+++ b/libs/backends/wavesaudio/waves_midiport.h
@@ -1,64 +1,64 @@
-/*
- 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__ */
-
+/*
+ Copyright (C) 2014 Waves Audio Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_waves_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__ */
+
diff --git a/libs/backends/wavesaudio/wavesapi/BasicTypes/WCFourCC.h b/libs/backends/wavesaudio/wavesapi/BasicTypes/WCFourCC.h
index 477fd25af9..165acc3295 100644
--- a/libs/backends/wavesaudio/wavesapi/BasicTypes/WCFourCC.h
+++ b/libs/backends/wavesaudio/wavesapi/BasicTypes/WCFourCC.h
@@ -1,3 +1,21 @@
+/*
+ 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__
diff --git a/libs/backends/wavesaudio/wavesapi/BasicTypes/WTByteOrder.h b/libs/backends/wavesaudio/wavesapi/BasicTypes/WTByteOrder.h
index 587c60ac60..7d7fd8c1a9 100644
--- a/libs/backends/wavesaudio/wavesapi/BasicTypes/WTByteOrder.h
+++ b/libs/backends/wavesaudio/wavesapi/BasicTypes/WTByteOrder.h
@@ -1,3 +1,21 @@
+/*
+ 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__
diff --git a/libs/backends/wavesaudio/wavesapi/BasicTypes/WUComPtr.h b/libs/backends/wavesaudio/wavesapi/BasicTypes/WUComPtr.h
index 0658e6a9e6..6193da38bb 100644
--- a/libs/backends/wavesaudio/wavesapi/BasicTypes/WUComPtr.h
+++ b/libs/backends/wavesaudio/wavesapi/BasicTypes/WUComPtr.h
@@ -1,3 +1,21 @@
+/*
+ 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__
diff --git a/libs/backends/wavesaudio/wavesapi/BasicTypes/WUDefines.h b/libs/backends/wavesaudio/wavesapi/BasicTypes/WUDefines.h
index 346ab44186..ea5c840d97 100644
--- a/libs/backends/wavesaudio/wavesapi/BasicTypes/WUDefines.h
+++ b/libs/backends/wavesaudio/wavesapi/BasicTypes/WUDefines.h
@@ -1,3 +1,21 @@
+/*
+ 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__
diff --git a/libs/backends/wavesaudio/wavesapi/BasicTypes/WUMathConsts.h b/libs/backends/wavesaudio/wavesapi/BasicTypes/WUMathConsts.h
index 041bf3792b..6f51bfa3f6 100644
--- a/libs/backends/wavesaudio/wavesapi/BasicTypes/WUMathConsts.h
+++ b/libs/backends/wavesaudio/wavesapi/BasicTypes/WUMathConsts.h
@@ -1,3 +1,21 @@
+/*
+ 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__
diff --git a/libs/backends/wavesaudio/wavesapi/BasicTypes/WUTypes.h b/libs/backends/wavesaudio/wavesapi/BasicTypes/WUTypes.h
index 2f91df333a..c28547eddb 100644
--- a/libs/backends/wavesaudio/wavesapi/BasicTypes/WUTypes.h
+++ b/libs/backends/wavesaudio/wavesapi/BasicTypes/WUTypes.h
@@ -1,3 +1,21 @@
+/*
+ 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__
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/IncludeWindows.h b/libs/backends/wavesaudio/wavesapi/devicemanager/IncludeWindows.h
index 313b38ea46..5dd8f0ed50 100644
--- a/libs/backends/wavesaudio/wavesapi/devicemanager/IncludeWindows.h
+++ b/libs/backends/wavesaudio/wavesapi/devicemanager/IncludeWindows.h
@@ -1,31 +1,49 @@
-#ifndef __IncludeWindows_h__
-#define __IncludeWindows_h__
+/*
+ Copyright (C) 2013 Waves Audio Ltd.
-#ifdef _WINDOWS
+ 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.
-/* Copy to include
-#include "IncludeWindows.h"
-*/
-
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0601 // Windows 7
-#endif
-
-#ifndef WINVER
-#define WINVER 0x0601 // Windows 7
-#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.
-#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__
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#ifndef __IncludeWindows_h__
+#define __IncludeWindows_h__
+
+#ifdef _WINDOWS
+
+/* Copy to include
+#include "IncludeWindows.h"
+*/
+
+#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__
+
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.cpp b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.cpp
index 00ee1c247f..ae5ef3a923 100644
--- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.cpp
+++ b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.cpp
@@ -1,6 +1,23 @@
+/*
+ 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
//!
@@ -10,6 +27,10 @@
#include "WCMRAudioDeviceManager.h"
+
+
+
+
//**********************************************************************************************
// WCMRAudioDevice::WCMRAudioDevice
//
@@ -18,21 +39,27 @@
//! and streaming will also be provided by the derived implementations.
//!
//! \param *pManager : The audio device manager that's managing this device.
+//!
//! \return Nothing.
//!
//**********************************************************************************************
-WCMRAudioDevice::WCMRAudioDevice (WCMRAudioDeviceManager *pManager) :
- m_pMyManager (pManager)
- , m_ConnectionStatus (DeviceDisconnected)
- , m_IsActive (false)
- , m_IsStreaming (false)
- , m_CurrentSamplingRate (-1)
- , m_CurrentBufferSize (0)
- , m_LeftMonitorChannel (-1)
- , m_RightMonitorChannel (-1)
- , m_MonitorGain (1.0f)
+WCMRAudioDevice::WCMRAudioDevice (WCMRAudioDeviceManager *pManager)
{
+ m_pMyManager = pManager;
m_DeviceName = "Unknown";
+
+ m_ConnectionStatus = DeviceDisconnected;
+ m_IsActive = false;
+ m_IsStreaming = false;
+
+ m_CurrentSamplingRate = -1;
+ m_CurrentBufferSize = 0;
+
+ m_LeftMonitorChannel = -1;
+ m_RightMonitorChannel = -1;
+ m_MonitorGain = 1.0f;
+
+
}
@@ -538,7 +565,6 @@ uint32_t WCMRAudioDevice::GetLatency (bool isInput)
return 0;
}
-
//**********************************************************************************************
// WCMRAudioDeviceManager::WCMRAudioDeviceManager
//
@@ -550,13 +576,15 @@ uint32_t WCMRAudioDevice::GetLatency (bool isInput)
//!
//**********************************************************************************************
WCMRAudioDeviceManager::WCMRAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter)
- : m_eAudioDeviceFilter(eCurAudioDeviceFilter)
- , m_CurrentDevice(0)
- , m_pTheClient (pTheClient)
+ : m_pTheClient (pTheClient)
+ , m_eAudioDeviceFilter(eCurAudioDeviceFilter)
{
+ //The derived classes will do lot more init!
+ return;
}
+
//**********************************************************************************************
// WCMRAudioDeviceManager::~WCMRAudioDeviceManager
//
@@ -571,21 +599,19 @@ WCMRAudioDeviceManager::~WCMRAudioDeviceManager()
{
AUTO_FUNC_DEBUG;
- std::cout << "API::Destroying AudioDeviceManager " << std::endl;
try
{
- // 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;
-
+ //Need to call release on our devices, and erase them from list
+ std::vector<WCMRAudioDevice*>::iterator deviceIter;
+ while (m_Devices.size())
+ {
+ WCMRAudioDevice *pDeviceToRelease = m_Devices.back();
+ m_Devices.pop_back();
+ if (pDeviceToRelease)
+ SAFE_RELEASE (pDeviceToRelease);
+ }
+
+ //The derived classes may want to do additional de-int!
}
catch (...)
{
@@ -595,48 +621,109 @@ WCMRAudioDeviceManager::~WCMRAudioDeviceManager()
}
-WCMRAudioDevice* WCMRAudioDeviceManager::InitNewCurrentDevice(const std::string & deviceName)
-{
- return initNewCurrentDeviceImpl(deviceName);
-}
-void WCMRAudioDeviceManager::DestroyCurrentDevice()
+//**********************************************************************************************
+// 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()
{
- return destroyCurrentDeviceImpl();
+ 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);
}
-const DeviceInfoVec WCMRAudioDeviceManager::DeviceInfoList() const
+
+
+//**********************************************************************************************
+// 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
{
- wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
- return m_DeviceInfoVec;
+ return (m_Devices);
}
-WTErr WCMRAudioDeviceManager::GetDeviceInfoByName(const std::string & nameToMatch, DeviceInfo & devInfo) const
+
+//**********************************************************************************************
+// *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
{
- wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
- DeviceInfoVecConstIter iter = m_DeviceInfoVec.begin();
- for (; iter != m_DeviceInfoVec.end(); ++iter)
+ //Need to check all our devices...
+ WCMRAudioDevice *pRetVal = NULL;
+
+ WCMRAudioDeviceListConstIter deviceIter;
+ for (deviceIter = m_Devices.begin(); deviceIter != m_Devices.end(); deviceIter++)
{
- if (nameToMatch == (*iter)->m_DeviceName)
- {
- devInfo = *(*iter);
- return eNoErr;
- }
+ if ((*deviceIter)->DeviceName() == nameToMatch)
+ {
+ pRetVal = *deviceIter;
+ break;
+ }
}
-
- return eRMResNotFound;
+
+ return (pRetVal);
}
-
-WTErr WCMRAudioDeviceManager::GetDeviceBufferSizes(const std::string & nameToMatch, std::vector<int>& bufferSizes) const
+//**********************************************************************************************
+// *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()
{
- return getDeviceBufferSizesImpl(nameToMatch, bufferSizes);
+ //Need to check all our devices...
+ WCMRAudioDevice *pRetVal = NULL;
+
+ WCMRAudioDeviceListIter deviceIter = m_Devices.begin();
+ if(deviceIter != m_Devices.end())
+ {
+ pRetVal = *deviceIter;
+ }
+ return (pRetVal);
}
+
+
//**********************************************************************************************
// WCMRAudioDeviceManager::NotifyClient
//
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.h b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.h
index a3b1baa784..0d6aa55dea 100644
--- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.h
+++ b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRAudioDeviceManager.h
@@ -1,6 +1,23 @@
+/*
+ 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
//!
@@ -25,35 +42,19 @@
#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 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<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 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
@@ -70,7 +71,6 @@ class WCMRAudioDeviceManagerClient
BufferSizeChanged,
ClockSourceChanged,
DeviceStoppedStreaming,
- DeviceStartsStreaming,
DeviceDroppedSamples,
DeviceConnectionLost,
DeviceGenericError,
@@ -123,7 +123,7 @@ public:
{
DeviceAvailable,
DeviceDisconnected,
- DeviceErrors
+ DeviceError
};
WCMRAudioDevice (WCMRAudioDeviceManager *pManager);///<Constructor
@@ -167,8 +167,6 @@ 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!
@@ -193,7 +191,6 @@ 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
{
@@ -205,44 +202,65 @@ 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.
-
- WCMRAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter); ///< constructor
- virtual ~WCMRAudioDeviceManager(void); ///< Destructor
+ WCMRAudioDevice* GetDefaultDevice()
+ {
+ //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+ return GetDefaultDevice_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;
+ virtual WTErr DoIdle()
+ {
+ //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+ return DoIdle_Private();
+ }
- //virtual void EnableVerboseLogging(bool /*bEnable*/, const std::string& /*logFilePath*/) { };
+ const WCMRAudioDeviceList& Devices() const
+ {
+ //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+ return Devices_Private();
+ }
- //notify backend
- void NotifyClient (WCMRAudioDeviceManagerClient::NotificationReason forReason, void *pParam = NULL);
+ WCMRAudioDevice* GetDeviceByName(const std::string & nameToMatch) const
+ {
+ //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+ return GetDeviceByName_Private(nameToMatch);
+ }
-protected:
+public:
+
+ WCMRAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter
+ ); ///< constructor
+ virtual ~WCMRAudioDeviceManager(void); ///< Destructor
- mutable wvNS::wvThread::ThreadMutex m_AudioDeviceInfoVecMutex; // mutex to lock device info list
- DeviceInfoVec m_DeviceInfoVec;
+ virtual WTErr UpdateDeviceList () = 0; //has to be overridden!
+
- 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;
+ //This is primarily for use by WCMRAudioDevice and it's descendants... We could have made it
+ //protected and made WCMRAudioDevice a friend, and then in some way found a way to extend
+ //the friendship to WCMRAudioDevice's descendants, but that would require a lot of extra
+ //effort!
+ void NotifyClient (WCMRAudioDeviceManagerClient::NotificationReason forReason, void *pParam = NULL);
+ virtual void EnableVerboseLogging(bool /*bEnable*/, const std::string& /*logFilePath*/) { };
+
+protected:
- WCMRAudioDeviceManagerClient *m_pTheClient; ///< The device manager's client, used to send notifications.
+ //< NOTE : Mutex protection is commented, but wrapper classes are still there, in case they are required in future.
+ //wvNS::wvThread::ThreadMutex m_AudioDeviceManagerMutex; ///< Mutex for Audio device manager class function access.
+ WCMRAudioDeviceManagerClient *m_pTheClient; ///< The device manager's client, used to send notifications.
+
+ WCMRAudioDeviceList m_Devices; ///< List of all relevant devices devices
+ eAudioDeviceFilter m_eAudioDeviceFilter; // filter of 'm_Devices'
};
#endif //#ifndef __WCMRAudioDeviceManager_h_
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp
index 10da07fef1..b66d2519ca 100644
--- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp
+++ b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp
@@ -1,6 +1,23 @@
+/*
+ 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
//!
@@ -41,8 +58,6 @@ 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.
@@ -151,7 +166,7 @@ WCMRCoreAudioDevice::WCMRCoreAudioDevice (WCMRCoreAudioDeviceManager *pManager,
m_CurrentBufferSize = (int)bufferSize;
- UpdateDeviceInfo();
+ UpdateDeviceInfo(true /*updateSRSupported*/, true /* updateBufferSizes */);
//should use a valid current SR...
if (m_SamplingRates.size())
@@ -237,11 +252,14 @@ 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 ()
+WTErr WCMRCoreAudioDevice::UpdateDeviceInfo (bool updateSRSupported, bool updateBufferSizes)
{
AUTO_FUNC_DEBUG;
@@ -254,8 +272,17 @@ WTErr WCMRCoreAudioDevice::UpdateDeviceInfo ()
WTErr errSR = eNoErr;
WTErr errBS = eNoErr;
- errSR = UpdateDeviceSampleRates();
- errBS = UpdateDeviceBufferSizes();
+ if (updateSRSupported)
+ {
+ errSR = UpdateDeviceSampleRates();
+ }
+
+ //update SR list... This is done conditionally, because some devices may not like
+ //changing the SR later on, just to check on things.
+ if (updateBufferSizes)
+ {
+ errBS = UpdateDeviceBufferSizes();
+ }
if(errName != eNoErr || errIn != eNoErr || errOut != eNoErr || errSR != eNoErr || errBS != eNoErr)
{
@@ -759,7 +786,7 @@ WTErr WCMRCoreAudioDevice::SetCurrentSamplingRate (int newRate)
retVal = SetAndCheckCurrentSamplingRate (newRate);
if(retVal == eNoErr)
{
- retVal = UpdateDeviceInfo ();
+ retVal = UpdateDeviceInfo (false/*updateSRSupported*/, true/*updateBufferSizes*/);
}
//reactivate it.
@@ -1732,7 +1759,7 @@ WTErr WCMRCoreAudioDevice::SetActive (bool newState)
m_DropsReported = 0;
m_IgnoreThisDrop = true;
- UpdateDeviceInfo();
+ UpdateDeviceInfo(true /*updateSRSupported */, true /* updateBufferSizes#*/);
}
@@ -2290,10 +2317,14 @@ OSStatus WCMRCoreAudioDevice::GetStreamLatency(AudioDeviceID device, bool isInpu
//! \return Nothing.
//!
//**********************************************************************************************
-WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient,
- eAudioDeviceFilter eCurAudioDeviceFilter, bool useMultithreading, bool bNocopy)
- : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter)
+WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter
+ , bool useMultithreading, eCABS_Method eCABS_method, bool bNocopy)
+ : WCMRAudioDeviceManager (pTheClient, eCurAudioDeviceFilter
+ )
+ , m_UpdateDeviceListRequested(0)
+ , m_UpdateDeviceListProcessed(0)
, m_UseMultithreading (useMultithreading)
+ , m_eCABS_Method(eCABS_method)
, m_bNoCopyAudioBuffer(bNocopy)
{
AUTO_FUNC_DEBUG;
@@ -2316,13 +2347,13 @@ WCMRCoreAudioDeviceManager::WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerCli
}
//add a listener to find out when devices change...
- AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, DevicePropertyChangeCallback, this);
-
+ AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, StaticPropertyChangeProc, this);
+
//Always add the None device first...
- m_NoneDevice = new WCMRNativeAudioNoneDevice(this);
+ m_Devices.push_back (new WCMRNativeAudioNoneDevice(this));
//prepare our initial list...
- generateDeviceListImpl();
+ UpdateDeviceList_Private();
return;
}
@@ -2345,7 +2376,25 @@ WCMRCoreAudioDeviceManager::~WCMRCoreAudioDeviceManager()
try
{
- delete m_NoneDevice;
+ AudioHardwareRemovePropertyListener (kAudioHardwarePropertyDevices, StaticPropertyChangeProc);
+
+ //Note: We purposely release the device list here, instead of
+ //depending on the superclass to do it, as by the time the superclass'
+ //destructor executes, we will have called Pa_Terminate()!
+
+ //Need to call release on our devices, and erase them from list
+ std::vector<WCMRAudioDevice*>::iterator deviceIter;
+ while (m_Devices.size())
+ {
+ WCMRAudioDevice *pDeviceToRelease = m_Devices.back();
+ m_Devices.pop_back();
+
+ SAFE_RELEASE (pDeviceToRelease);
+ }
+
+
+ //The derived classes may want to do additional de-int!
+
}
catch (...)
{
@@ -2356,511 +2405,313 @@ WCMRCoreAudioDeviceManager::~WCMRCoreAudioDeviceManager()
}
-WCMRAudioDevice* WCMRCoreAudioDeviceManager::initNewCurrentDeviceImpl(const std::string & deviceName)
+//**********************************************************************************************
+// 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)
{
- 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 *pMyManager = (WCMRCoreAudioDeviceManager *)inClientData;
+
+ if (pMyManager)
+ return pMyManager->PropertyChangeProc (inPropertyID);
+
+ return 0;
}
-void WCMRCoreAudioDeviceManager::destroyCurrentDeviceImpl()
-{
- 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)
- {
- //! 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;
-}
-
-
-WTErr WCMRCoreAudioDeviceManager::getDeviceMaxInputChannels(DeviceID deviceId, unsigned int& inputChannels)
+
+//**********************************************************************************************
+// 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)
{
- AUTO_FUNC_DEBUG;
- WTErr retVal = eNoErr;
- OSStatus err = kAudioHardwareNoError;
- UInt32 propSize = 0;
- inputChannels = 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
+ OSStatus retVal = 0;
+ switch (inPropertyID)
{
- retVal = eCoreAudioFailed;
- DEBUG_MSG("Failed to get device Input channels property size. Device Name: " << m_DeviceName.c_str());
+ case kAudioHardwarePropertyDevices:
+ m_UpdateDeviceListRequested++;
+ break;
+ default:
+ break;
}
return retVal;
}
-
-WTErr WCMRCoreAudioDeviceManager::getDeviceMaxOutputChannels(DeviceID deviceId, unsigned int& outputChannels)
+//**********************************************************************************************
+// 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)
{
- AUTO_FUNC_DEBUG;
-
- WTErr retVal = eNoErr;
- OSStatus err = kAudioHardwareNoError;
- UInt32 propSize = 0;
- outputChannels = 0;
+ 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);
- //! 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
+ std::ostringstream stream_str;
+ while (p_splited_orig_str != 0)
{
- retVal = eCoreAudioFailed;
- DEBUG_MSG("Failed to get device Output channels property size. Device Name: " << m_DeviceName.c_str());
+ 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);
}
-
- return retVal;
+ delete[] orig_c_str;
+ return_str = stream_str.str();
}
-
-
-WTErr WCMRCoreAudioDeviceManager::generateDeviceListImpl()
+
+
+//**********************************************************************************************
+// WCMRCoreAudioDeviceManager::UpdateDeviceList_Private
+//
+//! Updates the list of devices maintained by the manager. If devices have gone away, they are removed
+//! if new devices have been connected, they are added to the list.
+//!
+//! \param none
+//!
+//! \return eNoErr on success, an error code on failure.
+//!
+//**********************************************************************************************
+WTErr WCMRCoreAudioDeviceManager::UpdateDeviceList_Private()
{
AUTO_FUNC_DEBUG;
- // 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
+
+ try
{
+
+ // Define 2 vectors for input and output - only for eMatchedDuplexDevices case
+ WCMRAudioDeviceList adOnlyIn;
+ WCMRAudioDeviceList adOnlyOut;
+
//Get device count...
UInt32 propSize = 0;
osErr = AudioHardwareGetPropertyInfo (kAudioHardwarePropertyDevices, &propSize, NULL);
ASSERT_ERROR(osErr, "AudioHardwareGetProperty 1");
if (WUIsError(osErr))
throw osErr;
-
+
size_t numDevices = propSize / sizeof (AudioDeviceID);
deviceIDs = new AudioDeviceID[numDevices];
-
+
//retrieve the device IDs
propSize = numDevices * sizeof (AudioDeviceID);
osErr = AudioHardwareGetProperty (kAudioHardwarePropertyDevices, &propSize, deviceIDs);
ASSERT_ERROR(osErr, "Error while getting audio devices: AudioHardwareGetProperty 2");
if (WUIsError(osErr))
throw osErr;
-
- //now add the ones that are not there...
- for (size_t deviceIndex = 0; deviceIndex < numDevices; deviceIndex++)
+
+ //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*/)
{
- 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)
+ 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++)
{
- //Get property: name.
- char* deviceName = new char[propSize];
- osErr = AudioDeviceGetProperty(deviceIDs[deviceIndex], 0, 0, kAudioDevicePropertyDeviceName, &propSize, deviceName);
- if (osErr == kAudioHardwareNoError)
+ if (myDeviceID == deviceIDs[reportedDeviceIndex])
{
- pDevInfo = new DeviceInfo(deviceIDs[deviceIndex], deviceName);
+ deviceFound = true;
+ break;
}
- else
+ }
+
+ if (!deviceFound)
+ {
+ //it's no longer there, need to remove it!
+ WCMRAudioDevice *pTheDeviceToErase = *deviceIter;
+ deviceIter = m_Devices.erase (deviceIter);
+ if (pTheDeviceToErase->Active())
{
- retVal = eCoreAudioFailed;
- DEBUG_MSG("Failed to get device name. Device ID: " << m_DeviceID);
+ NotifyClient (WCMRAudioDeviceManagerClient::DeviceConnectionLost);
}
-
- delete [] deviceName;
+ SAFE_RELEASE (pTheDeviceToErase);
}
else
+ deviceIter++;
+ }
+
+ //now add the ones that are not there...
+ for (reportedDeviceIndex = 0; reportedDeviceIndex < numDevices; reportedDeviceIndex++)
+ {
+ bool deviceFound = false;
+ for (deviceIter = m_Devices.begin(); deviceIter != m_Devices.end(); deviceIter++)
{
- retVal = eCoreAudioFailed;
- DEBUG_MSG("Failed to get device name property size. Device ID: " << m_DeviceID);
- }
-
- if (pDevInfo)
- {
- //Retrieve all the information we need for the device
- WTErr wErr = eNoErr;
-
- //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)
+ 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])
{
- DEBUG_MSG ("Failed to get device max output channels count. Device ID: " << m_DeviceID);
- delete pDevInfo;
- continue; //proceed to the next device
+ deviceFound = true;
+ break;
}
+ }
+
+ if (!deviceFound)
+ {
+ //add it to our list...
+ //build a device object...
+ WCMRCoreAudioDevice *pNewDevice = new WCMRCoreAudioDevice (this, deviceIDs[reportedDeviceIndex], m_UseMultithreading, m_bNoCopyAudioBuffer);
+ bool bDeleteNewDevice = true;
- pDevInfo->m_MaxOutputChannels = maxOutputChannels;
-
- //Now check if this device is acceptable according to current input/output settings
- bool bRejectDevice = false;
- switch(m_eAudioDeviceFilter)
+ if (pNewDevice)
{
+
+ // Don't delete the new device by default, since most cases use it
+ bDeleteNewDevice = false;
+
+ // Insert the new device to the device list according to its enum
+ switch(m_eAudioDeviceFilter)
+ {
case eInputOnlyDevices:
- if (pDevInfo->m_MaxInputChannels != 0)
+ if ((int) pNewDevice->InputChannels().size() != 0)
{
- m_DeviceInfoVec.push_back(pDevInfo);
+ m_Devices.push_back (pNewDevice);
}
else
{
// Delete unnecesarry device
- bRejectDevice = true;
+ bDeleteNewDevice = true;
}
break;
case eOutputOnlyDevices:
- if (pDevInfo->m_MaxOutputChannels != 0)
+ if ((int) pNewDevice->OutputChannels().size() != 0)
{
- m_DeviceInfoVec.push_back(pDevInfo);
+ m_Devices.push_back (pNewDevice);
}
else
{
// Delete unnecesarry device
- bRejectDevice = true;
+ bDeleteNewDevice = true;
}
break;
case eFullDuplexDevices:
- if (pDevInfo->m_MaxInputChannels != 0 && pDevInfo->m_MaxOutputChannels != 0)
+ if ((int) pNewDevice->InputChannels().size() != 0 && (int) pNewDevice->OutputChannels().size() != 0)
{
- m_DeviceInfoVec.push_back(pDevInfo);
+ m_Devices.push_back (pNewDevice);
}
else
{
// Delete unnecesarry device
- bRejectDevice = true;
+ bDeleteNewDevice = true;
}
break;
case eAllDevices:
default:
- m_DeviceInfoVec.push_back(pDevInfo);
+ m_Devices.push_back (pNewDevice);
break;
+ }
}
- if(bRejectDevice)
+ if(bDeleteNewDevice)
{
syslog (LOG_NOTICE, "%s rejected, In Channels = %d, Out Channels = %d\n",
- pDevInfo->m_DeviceName.c_str(), pDevInfo->m_MaxInputChannels, pDevInfo->m_MaxOutputChannels);
+ pNewDevice->DeviceName().c_str(), (int) pNewDevice->InputChannels().size(),
+ (int) pNewDevice->OutputChannels().size());
// In case of Input and Output both channels being Zero, we will release memory; since we created CoreAudioDevice but we are Not adding it in list.
- delete pDevInfo;
+ SAFE_RELEASE(pNewDevice);
}
}
}
-
-
+
+
//If no devices were found, that's not a good thing!
- if (m_DeviceInfoVec.empty())
+ if (m_Devices.empty())
{
DEBUG_MSG ("No matching CoreAudio devices were found\n");
- }
+ }
+
+
+ m_UpdateDeviceListRequested = m_UpdateDeviceListProcessed = 0;
+
}
catch (...)
{
if (WUNoError(retVal))
retVal = eCoreAudioFailed;
}
-
- delete[] deviceIDs;
+
+ safe_delete_array(deviceIDs);
closelog();
-
+
return retVal;
}
-WTErr WCMRCoreAudioDeviceManager::updateDeviceListImpl()
-{
- wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex);
- WTErr err = generateDeviceListImpl();
-
- if (eNoErr != err)
- {
- 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;
-}
-
-WTErr WCMRCoreAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector<int>& bufferSizes) const
+//**********************************************************************************************
+// 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()
{
- AUTO_FUNC_DEBUG;
-
- WTErr retVal = eNoErr;
- OSStatus err = kAudioHardwareNoError;
- UInt32 propSize = 0;
+ //WTErr retVal = eNoErr;
- 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)
- {
- // 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
+ //wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+
+ //If there's something specific to CoreAudio manager idle handling do it here...
+ if (m_UpdateDeviceListRequested != m_UpdateDeviceListProcessed)
{
- retVal = eCoreAudioFailed;
- DEBUG_MSG("Failed to get device buffer sizes range. Device Name: " << m_DeviceName.c_str());
+ m_UpdateDeviceListProcessed = m_UpdateDeviceListRequested;
+ UpdateDeviceList_Private();
+ NotifyClient (WCMRAudioDeviceManagerClient::DeviceListChanged);
}
- }
- else
- {
- retVal = eRMResNotFound;
- std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl;
- }
+ }
-
- return retVal;
+ //Note that the superclass is going to call all the devices' DoIdle() anyway...
+ return (WCMRAudioDeviceManager::DoIdle());
}
-
-OSStatus WCMRCoreAudioDeviceManager::DevicePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData)
-{
- switch (inPropertyID)
- {
- case kAudioHardwarePropertyDevices:
- {
- WCMRCoreAudioDeviceManager* pManager = (WCMRCoreAudioDeviceManager*)inClientData;
- if (pManager)
- pManager->updateDeviceListImpl();
- }
- break;
- default:
- break;
- }
-
- return 0;
-}
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h
index 5cfbedb9c9..96d2a9d70e 100644
--- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h
+++ b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRCoreAudioDeviceManager.h
@@ -1,6 +1,23 @@
+/*
+ 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
//!
@@ -121,7 +138,7 @@ protected:
uint32_t m_NextSampleToUse;
#endif //WV_USE_TONE_GEN
- WTErr UpdateDeviceInfo ();
+ WTErr UpdateDeviceInfo (bool updateSRSupported, bool updateBufferSizes);
WTErr UpdateDeviceName();
WTErr UpdateDeviceInputs();
WTErr UpdateDeviceOutputs();
@@ -164,28 +181,40 @@ class WCMRCoreAudioDeviceManager : public WCMRAudioDeviceManager
public:
WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter,
- bool useMultithreading = true, bool bNocopy = false); ///< constructor
+ bool useMultithreading = true, eCABS_Method eCABS_method = eCABS_Simple, bool bNocopy = false); ///< constructor
virtual ~WCMRCoreAudioDeviceManager(void); ///< Destructor
+
+
+ virtual WTErr UpdateDeviceList() //has to be overridden!
+ {
+ //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+ return UpdateDeviceList_Private();
+ }
+
+ virtual eCABS_Method GetBufferSizeMethod()
+ {
+ //wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
+ return GetBufferSizeMethod_Private();
+ }
+
+ virtual WTErr DoIdle();
+
+private:
+ WTErr UpdateDeviceList_Private();
+ eCABS_Method GetBufferSizeMethod_Private() { return m_eCABS_Method; }
protected:
- 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;
-
+
+ int m_UpdateDeviceListRequested; ///< Number of times device list change has been detected.
+ int m_UpdateDeviceListProcessed; ///< Number of times device list change has been processed.
bool m_UseMultithreading; ///< Flag indicates whether to use multi-threading for audio processing.
bool m_bNoCopyAudioBuffer;
-
-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;
+ eCABS_Method m_eCABS_Method; // Type of core audio buffer size list method
+
+ static OSStatus StaticPropertyChangeProc (AudioHardwarePropertyID inPropertyID, void* inClientData);
+ OSStatus PropertyChangeProc (AudioHardwarePropertyID inPropertyID);
+
+ void remove_pattern(const std::string& original_str, const std::string& pattern_str, std::string& return_str);
};
#endif //#ifndef __WCMRCoreAudioDeviceManager_h_
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.cpp b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.cpp
index b04bb7ab71..0cba7ee851 100644
--- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.cpp
+++ b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.cpp
@@ -1,6 +1,23 @@
+/*
+ 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
//!
@@ -119,12 +136,6 @@ WTErr WCMRNativeAudioNoneDevice::SetCurrentBufferSize (int newSize)
}
-WTErr WCMRNativeAudioNoneDevice::UpdateDeviceInfo ()
-{
- return eNoErr;
-}
-
-
WTErr WCMRNativeAudioNoneDevice::SetStreaming (bool newState)
{
if (Streaming() == newState)
@@ -133,8 +144,7 @@ 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;
diff --git a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.h b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.h
index 75c5e1430c..dc350ff6be 100644
--- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.h
+++ b/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRNativeAudio.h
@@ -1,6 +1,23 @@
+/*
+ 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
//!
@@ -25,10 +42,9 @@ 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 () {}
@@ -36,6 +52,7 @@ 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.
+
};
@@ -48,7 +65,6 @@ 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:
@@ -59,11 +75,11 @@ private:
#else
inline void _usleep(uint64_t usec) { ::usleep(usec); }
#endif
- static const size_t __m_NumInputChannels = 0;
- static const size_t __m_NumOutputChannels = 0;
+ static const size_t __m_NumInputChannels = 32;
+ static const size_t __m_NumOutputChannels = 32;
pthread_t m_SilenceThread;
- float *_m_inputBuffer;
- float *_m_outputBuffer;
+ 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
deleted file mode 100644
index 2f6cd710ff..0000000000
--- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.cpp
+++ /dev/null
@@ -1,1697 +0,0 @@
-//----------------------------------------------------------------------------------
-//
-// 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
deleted file mode 100644
index acbed161e2..0000000000
--- a/libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.h
+++ /dev/null
@@ -1,160 +0,0 @@
-//----------------------------------------------------------------------------------
-//
-// 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_
diff --git a/libs/backends/wavesaudio/wavesapi/miscutils/MinMaxUtilities.h b/libs/backends/wavesaudio/wavesapi/miscutils/MinMaxUtilities.h
index 79b530a16b..cd48169bf2 100644
--- a/libs/backends/wavesaudio/wavesapi/miscutils/MinMaxUtilities.h
+++ b/libs/backends/wavesaudio/wavesapi/miscutils/MinMaxUtilities.h
@@ -1,3 +1,21 @@
+/*
+ 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__
diff --git a/libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.cpp b/libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.cpp
index a644b61c92..e3de715508 100644
--- a/libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.cpp
+++ b/libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.cpp
@@ -1,69 +1,87 @@
-#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 ;
-
- QueryPerformanceFrequency(&Frequency) ;
- QueryPerformanceCounter(&Count);
- theTime = uint64_t((Count.QuadPart * 1000000.0 / Frequency.QuadPart));
-#endif
-
-#if defined(__linux__) || defined(__MACOS__)
-// Mac code replaced by posix calls, to reduce Carbon dependency.
- timeval buf;
-
- 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
-*/
-void UMicrosecondsAccumulator::Start()
-{
- m_start_time.ReadTime();
-}
+ Copyright (C) 2013 Waves Audio Ltd.
-void UMicrosecondsAccumulator::Stop()
-{
- UMicroseconds stop_time;
-
- m_accumulator += stop_time.GetNativeTime() - m_start_time.GetNativeTime();
-}
+ 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.
-void UMicrosecondsAccumulator::Clear()
-{
- m_start_time = 0;
- m_accumulator = 0;
-}
+ 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.
-UMicroseconds UMicrosecondsAccumulator::GetAccumulatedTime() const
-{
- return m_accumulator;
-}
+ 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.
-UMicrosecondsAccumulator& UMicrosecondsAccumulator::operator+=(const UMicrosecondsAccumulator& inaccum_to_add)
-{
- m_accumulator += inaccum_to_add.GetAccumulatedTime();
- return *this;
-}
-
-} // namespace wvNS {
+*/
+#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 ;
+
+ QueryPerformanceFrequency(&Frequency) ;
+ QueryPerformanceCounter(&Count);
+ theTime = uint64_t((Count.QuadPart * 1000000.0 / Frequency.QuadPart));
+#endif
+
+#if defined(__linux__) || defined(__MACOS__)
+// Mac code replaced by posix calls, to reduce Carbon dependency.
+ timeval buf;
+
+ 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
+*/
+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 {
diff --git a/libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.h b/libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.h
index e50a256cce..64d1f8824d 100644
--- a/libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.h
+++ b/libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.h
@@ -1,105 +1,123 @@
-#ifndef __UMicroseconds_h__
- #define __UMicroseconds_h__
-
-/* Copy to include
-#include "UMicroseconds.h"
-*/
-
-
-
-#include "BasicTypes/WUDefines.h"
-#include "BasicTypes/WUTypes.h"
-
-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:
+/*
+ Copyright (C) 2013 Waves Audio Ltd.
- UMicroseconds()
- {
- ReadTime();
- }
+ 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.
- UMicroseconds(const TimeKeeper in_initVal) : theTime(in_initVal) {}
+ 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.
- 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;}
+ 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.
- 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__
+*/
+#ifndef __UMicroseconds_h__
+ #define __UMicroseconds_h__
+
+/* Copy to include
+#include "UMicroseconds.h"
+*/
+
+
+
+#include "BasicTypes/WUDefines.h"
+#include "BasicTypes/WUTypes.h"
+
+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__
diff --git a/libs/backends/wavesaudio/wavesapi/miscutils/WCFixedString.h b/libs/backends/wavesaudio/wavesapi/miscutils/WCFixedString.h
index a14d8584d0..4c7264b1d5 100644
--- a/libs/backends/wavesaudio/wavesapi/miscutils/WCFixedString.h
+++ b/libs/backends/wavesaudio/wavesapi/miscutils/WCFixedString.h
@@ -1,3 +1,21 @@
+/*
+ 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__
diff --git a/libs/backends/wavesaudio/wavesapi/miscutils/WUErrors.h b/libs/backends/wavesaudio/wavesapi/miscutils/WUErrors.h
index f0080e4019..11bca17087 100644
--- a/libs/backends/wavesaudio/wavesapi/miscutils/WUErrors.h
+++ b/libs/backends/wavesaudio/wavesapi/miscutils/WUErrors.h
@@ -1,3 +1,21 @@
+/*
+ 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__
@@ -35,7 +53,6 @@ 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;
diff --git a/libs/backends/wavesaudio/wavesapi/miscutils/safe_delete.h b/libs/backends/wavesaudio/wavesapi/miscutils/safe_delete.h
index 30976224c1..72de3388bf 100644
--- a/libs/backends/wavesaudio/wavesapi/miscutils/safe_delete.h
+++ b/libs/backends/wavesaudio/wavesapi/miscutils/safe_delete.h
@@ -1,3 +1,21 @@
+/*
+ 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__
diff --git a/libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.cpp b/libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.cpp
index 8353a758c8..34c4a41e20 100644
--- a/libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.cpp
+++ b/libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.cpp
@@ -1,3 +1,21 @@
+/*
+ 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.
diff --git a/libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.h b/libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.h
index de9b20c2fa..791978958c 100644
--- a/libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.h
+++ b/libs/backends/wavesaudio/wavesapi/refmanager/WCRefManager.h
@@ -1,3 +1,21 @@
+/*
+ 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
diff --git a/libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.cpp b/libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.cpp
index 123c41678c..62fc04007b 100644
--- a/libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.cpp
+++ b/libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.cpp
@@ -1,3 +1,21 @@
+/*
+ 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
diff --git a/libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.h b/libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.h
index e95117482c..c97808b059 100644
--- a/libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.h
+++ b/libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.h
@@ -1,3 +1,21 @@
+/*
+ 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_
diff --git a/libs/backends/wavesaudio/wavesapi/wavespublicapi/1.0/WavesPublicAPI_Defines.h b/libs/backends/wavesaudio/wavesapi/wavespublicapi/1.0/WavesPublicAPI_Defines.h
index 1e1b95d8ec..470ce77c62 100644
--- a/libs/backends/wavesaudio/wavesapi/wavespublicapi/1.0/WavesPublicAPI_Defines.h
+++ b/libs/backends/wavesaudio/wavesapi/wavespublicapi/1.0/WavesPublicAPI_Defines.h
@@ -1,3 +1,21 @@
+/*
+ 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__
diff --git a/libs/backends/wavesaudio/wavesapi/wavespublicapi/WTErr.h b/libs/backends/wavesaudio/wavesapi/wavespublicapi/WTErr.h
index 9078d7666d..6c6a0b9dec 100644
--- a/libs/backends/wavesaudio/wavesapi/wavespublicapi/WTErr.h
+++ b/libs/backends/wavesaudio/wavesapi/wavespublicapi/WTErr.h
@@ -1,5 +1,22 @@
+/*
+ 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
///////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/libs/backends/wavesaudio/wavesapi/wavespublicapi/wstdint.h b/libs/backends/wavesaudio/wavesapi/wavespublicapi/wstdint.h
index 494eb8f6b9..a933696638 100644
--- a/libs/backends/wavesaudio/wavesapi/wavespublicapi/wstdint.h
+++ b/libs/backends/wavesaudio/wavesapi/wavespublicapi/wstdint.h
@@ -1,3 +1,21 @@
+/*
+ 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__
diff --git a/libs/backends/wavesaudio/wscript b/libs/backends/wavesaudio/wscript
index b2a552ff18..814f16bc44 100755..100644
--- a/libs/backends/wavesaudio/wscript
+++ b/libs/backends/wavesaudio/wscript
@@ -19,18 +19,14 @@ 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):
-
- if bld.env['build_target'] == 'mingw':
- obj = bld(features = 'cxx cxxshlib')
+ obj = bld(features = 'c cxx cxxshlib')
+ if bld.env['build_target'] == 'mountain_lion':
+ obj.framework = 'CoreMidi'
else:
- obj = bld(features = 'cxx cxxshlib', framework = ["CoreMidi"])
-
+ obj.framework = 'CoreMIDI'
obj.source = [
'waves_audiobackend.cc',
'waves_audiobackend.latency.cc',
@@ -45,59 +41,34 @@ 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_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'
]
-
- 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',
- 'wavesapi/threads',
- 'portmidi',
- 'portmidi/src/pm_common'
- ]
-
+ 'wavesapi',
+ 'wavesapi/refmanager',
+ 'wavesapi/wavespublicapi',
+ 'wavesapi/devicemanager',
+ 'wavesapi/miscutils',
+ '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'
- if bld.env['build_target'] == 'mingw':
- obj.uselib = ['PORTAUDIO']
+ obj.use = [ 'libardour', 'libpbd' ]
obj.vnum = WAVESAUDIOBACKEND_VERSION
- 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'
- ]
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'backends')
+ obj.defines = ['PACKAGE="' + I18N_PACKAGE + '"',
+ '__MACOS__',
+ 'ARDOURBACKEND_DLL_EXPORTS'
+ ]