From 8a6762f189680a7ae6d2060aab97be0c43ae227a Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 29 Apr 2014 16:30:56 -0400 Subject: [PATCH] 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. --- libs/backends/wavesaudio/portmidi/pmutil.h | 254 +- .../portmidi/src/pm_common/pminternal.h | 356 +- .../portmidi/src/pm_mac/Makefile.osx | 129 - .../portmidi/src/pm_mac/README_MAC.txt | 163 - .../pm_mac/pm_mac.xcodeproj/project.pbxproj | 594 ---- .../contents.xcworkspacedata | 7 - .../UserInterfaceState.xcuserstate | Bin 5803 -> 0 bytes .../xcschemes/Assemble Application.xcscheme | 86 - .../xcschemes/Compile Java.xcscheme | 59 - .../xcschemes/CopyJavaSources.xcscheme | 59 - .../xcschemes/JPortMidiHeaders.xcscheme | 59 - .../xcschemes/PmDefaults.xcscheme | 59 - .../xcschemes/xcschememanagement.plist | 62 - .../xcschemes/Assemble Application.xcscheme | 86 - .../xcschemes/Compile Java.xcscheme | 59 - .../xcschemes/CopyJavaSources.xcscheme | 59 - .../xcschemes/JPortMidiHeaders.xcscheme | 59 - .../xcschemes/PmDefaults.xcscheme | 59 - .../xcschemes/xcschememanagement.plist | 62 - .../src/pm_mac/pmdefaults/make/build.xml | 87 - .../pm_mac/pmdefaults/make/find-classrefs.sh | 31 - .../resources/English.lproj/Credits.rtf | 14 - .../resources/English.lproj/InfoPlist.strings | 3 - .../pm_mac/pmdefaults/resources/Info.plist | 40 - .../src/pm_mac/pmdefaults/resources/Manifest | 1 - .../wavesaudio/portmidi/src/pm_mac/pmmac.c | 118 +- .../wavesaudio/portmidi/src/pm_mac/pmmac.h | 6 +- .../portmidi/src/pm_mac/pmmacosxcm.h | 12 +- .../portmidi/src/pm_mac/readbinaryplist.c | 2230 ++++++------- .../wavesaudio/portmidi/src/pm_win/pmwin.c | 286 +- .../wavesaudio/portmidi/src/pm_win/pmwinmm.c | 2928 ++++++++--------- .../wavesaudio/portmidi/src/pm_win/pmwinmm.h | 10 +- .../portmidi/src/porttime/ptmacosx_mach.c | 262 +- .../portmidi/src/porttime/ptwinmm.c | 70 - .../backends/wavesaudio/waves_audiobackend.cc | 2559 +++++++------- libs/backends/wavesaudio/waves_audiobackend.h | 20 +- .../wavesaudio/waves_audiobackend.latency.cc | 180 +- .../wavesaudio/waves_audiobackend.midi.cc | 707 ++-- .../waves_audiobackend.port_engine.cc | 1308 ++++---- libs/backends/wavesaudio/waves_audioport.cc | 124 +- libs/backends/wavesaudio/waves_audioport.h | 116 +- libs/backends/wavesaudio/waves_dataport.cc | 284 +- libs/backends/wavesaudio/waves_dataport.h | 230 +- libs/backends/wavesaudio/waves_midi_buffer.cc | 99 +- libs/backends/wavesaudio/waves_midi_buffer.h | 95 +- libs/backends/wavesaudio/waves_midi_device.cc | 536 +-- libs/backends/wavesaudio/waves_midi_device.h | 2 +- .../wavesaudio/waves_midi_device_manager.cc | 2 +- .../wavesaudio/waves_midi_device_manager.h | 2 +- libs/backends/wavesaudio/waves_midi_event.cc | 3 +- libs/backends/wavesaudio/waves_midi_event.h | 150 +- libs/backends/wavesaudio/waves_midiport.cc | 122 +- libs/backends/wavesaudio/waves_midiport.h | 128 +- .../wavesaudio/wavesapi/BasicTypes/WCFourCC.h | 18 + .../wavesapi/BasicTypes/WTByteOrder.h | 18 + .../wavesaudio/wavesapi/BasicTypes/WUComPtr.h | 18 + .../wavesapi/BasicTypes/WUDefines.h | 18 + .../wavesapi/BasicTypes/WUMathConsts.h | 18 + .../wavesaudio/wavesapi/BasicTypes/WUTypes.h | 18 + .../wavesapi/devicemanager/IncludeWindows.h | 74 +- .../devicemanager/WCMRAudioDeviceManager.cpp | 207 +- .../devicemanager/WCMRAudioDeviceManager.h | 130 +- .../WCMRCoreAudioDeviceManager.cpp | 681 ++-- .../WCMRCoreAudioDeviceManager.h | 67 +- .../devicemanager/WCMRNativeAudio.cpp | 28 +- .../wavesapi/devicemanager/WCMRNativeAudio.h | 36 +- .../WCMRPortAudioDeviceManager.cpp | 1697 ---------- .../WCMRPortAudioDeviceManager.h | 160 - .../wavesapi/miscutils/MinMaxUtilities.h | 18 + .../wavesapi/miscutils/UMicroseconds.cpp | 152 +- .../wavesapi/miscutils/UMicroseconds.h | 226 +- .../wavesapi/miscutils/WCFixedString.h | 18 + .../wavesaudio/wavesapi/miscutils/WUErrors.h | 19 +- .../wavesapi/miscutils/safe_delete.h | 18 + .../wavesapi/refmanager/WCRefManager.cpp | 18 + .../wavesapi/refmanager/WCRefManager.h | 18 + .../wavesapi/threads/WCThreadSafe.cpp | 18 + .../wavesapi/threads/WCThreadSafe.h | 18 + .../1.0/WavesPublicAPI_Defines.h | 18 + .../wavesapi/wavespublicapi/WTErr.h | 19 +- .../wavesapi/wavespublicapi/wstdint.h | 18 + libs/backends/wavesaudio/wscript | 83 +- 82 files changed, 7629 insertions(+), 11256 deletions(-) delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/Makefile.osx delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/README_MAC.txt delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.pbxproj delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/project.xcworkspace/xcuserdata/VKamyshniy.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Assemble Application.xcscheme delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/Compile Java.xcscheme delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/CopyJavaSources.xcscheme delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/JPortMidiHeaders.xcscheme delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/PmDefaults.xcscheme delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/VKamyshniy.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/Assemble Application.xcscheme delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/Compile Java.xcscheme delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/CopyJavaSources.xcscheme delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/JPortMidiHeaders.xcscheme delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/PmDefaults.xcscheme delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pm_mac.xcodeproj/xcuserdata/gzharun.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/build.xml delete mode 100755 libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/make/find-classrefs.sh delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/Credits.rtf delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/English.lproj/InfoPlist.strings delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Info.plist delete mode 100644 libs/backends/wavesaudio/portmidi/src/pm_mac/pmdefaults/resources/Manifest delete mode 100644 libs/backends/wavesaudio/portmidi/src/porttime/ptwinmm.c delete mode 100644 libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.cpp delete mode 100644 libs/backends/wavesaudio/wavesapi/devicemanager/WCMRPortAudioDeviceManager.h mode change 100755 => 100644 libs/backends/wavesaudio/wscript 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 = ""; }; - 3DE21390124655760033C839 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = ""; }; - 3DE213BE1246557F0033C839 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = ""; }; - 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 = ""; }; - 89D0F0220F392F20007831A7 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; - 89D0F0230F392F20007831A7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 89D0F03E0F39304A007831A7 /* JavaApplicationStub */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = JavaApplicationStub; path = /System/Library/Frameworks/JavaVM.framework/Versions/A/Resources/MacOS/JavaApplicationStub; sourceTree = ""; }; - 89D0F0840F394066007831A7 /* JavaNativeFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaNativeFoundation.framework; path = /System/Library/Frameworks/JavaVM.framework/Versions/A/Frameworks/JavaNativeFoundation.framework; sourceTree = ""; }; - 89D0F1390F3948A9007831A7 /* pmdefaults/make */ = {isa = PBXFileReference; lastKnownFileType = folder; path = pmdefaults/make; sourceTree = ""; }; - 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 = ""; }; - 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 = ""; - }; - 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = "Other Frameworks"; - sourceTree = ""; - }; - 19C28FACFE9D520D11CA2CBB /* Products */ = { - isa = PBXGroup; - children = ( - 89D0F15D0F3A0FF7007831A7 /* pmdefaults.jar */, - 8D1107320486CEB800E47090 /* PmDefaults.app */, - ); - name = Products; - sourceTree = ""; - }; - 29B97314FDCFA39411CA2CEA /* pmdefaults */ = { - isa = PBXGroup; - children = ( - 3DE216101246ABE30033C839 /* libpmjni.dylib */, - 89D0F0260F392F48007831A7 /* Source */, - 89D0F0200F392F20007831A7 /* Resources */, - 89D0F1390F3948A9007831A7 /* pmdefaults/make */, - 29B97323FDCFA39411CA2CEA /* Frameworks */, - 19C28FACFE9D520D11CA2CBB /* Products */, - ); - name = pmdefaults; - sourceTree = ""; - }; - 29B97323FDCFA39411CA2CEA /* Frameworks */ = { - isa = PBXGroup; - children = ( - 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, - 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, - ); - name = Frameworks; - sourceTree = ""; - }; - 3DE2136A124652E20033C839 /* pm_java */ = { - isa = PBXGroup; - children = ( - 3DE21379124653150033C839 /* pmdefaults */, - 3DE2137A1246531D0033C839 /* jportmidi */, - ); - name = pm_java; - path = ..; - sourceTree = ""; - }; - 3DE21379124653150033C839 /* pmdefaults */ = { - isa = PBXGroup; - children = ( - 3DE2137D124653CB0033C839 /* PmDefaultsFrame.java */, - 3DE2137B1246538B0033C839 /* PmDefaults.java */, - ); - name = pmdefaults; - sourceTree = ""; - }; - 3DE2137A1246531D0033C839 /* jportmidi */ = { - isa = PBXGroup; - children = ( - 3DE21382124654DE0033C839 /* JPortMidiException.java */, - 3DE21381124654CF0033C839 /* JPortMidiApi.java */, - 3DE21380124654BC0033C839 /* JPortMidi.java */, - ); - name = jportmidi; - sourceTree = ""; - }; - 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 = ""; - }; - 89D0F0260F392F48007831A7 /* Source */ = { - isa = PBXGroup; - children = ( - 3DE2136A124652E20033C839 /* pm_java */, - ); - name = Source; - path = pmdefaults/src; - sourceTree = ""; - }; -/* 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 = ""; - }; - 89D0F0210F392F20007831A7 /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 89D0F0220F392F20007831A7 /* English */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; -/* 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 @@ - - - - - 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 104c0fe910b0326ad03007a1f3bd4eeaded688d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5803 zcma)A349Y}+JBx&CYj01B$IL#6e%r~v)G%KBKDT6rO<;?j*vD(8%dLpq#PFHSw!#v zL;*pNqb&-^g5t7@yY9NKuI{(uvM8&r?s_X8c&+Q_uE+AdlW9`ovcJ##e#vC!Ip62_ zzt20(L7z7q$;>2;D-Q&;0EY~8{sE#E8GUR!zS1V`{4j|K{xckLAVd@heL1-j>Ad#IXnTs zfhXa&a2lS6Kf*b972bsR;R1XDU&7b$J(^HL85JCW191=z!xS8jd6cEk5*FcP zyavm#9H-+9tj7kNi;cJd7o!I?T!tYGV+1>}6IbIpyb0IiZFmRn#9ep~c40U6;2}JQ z$MI+QOMD!Eg}=jR@L4>Af5F%BZG0a;;($Yr<4l~H<2egw9&1$;hM zV=i^drLH9qUAZMWWu@gg6>M1rCG00JFQcG5hpjTRu(YByx3C~HztW`+j$57PuVnEI zw}dp!Uls5$2gYBj+;FYWc)j1dtV5gTVWIFY@oFKLI*hTGv_x2$U*6qIjnxGLzGio5 zTDZX*_BQ*NvE;ZTY#F5qq`{q?Ir)X-Q?fI2*Nji;%*xHo9G_B{m%V1q3(?%?KwcLN zW^r`90284A3Sm-{k#;`|WTWv{3$yAd35DFNx*0=JV|DGUXmiH$cnws*=tD3Cu7zSK zfl?@ga&l4<^`rhYfCkc_Lr}>wHx;JAbatId$t-U}XcSFl*IG(lJ2HgomzgG({WG)zv>YOTwu~0NZ6O8VHd2~e=%%>~$r8&zR z>f+u^i)ig(BlIq4?uNzSrlFKZBV!6Y&Yk#zn(ZtN9qvYo2(DTxv>V3+ti@EXXswkqL3agxW}`qb1T2Vm1H&vcy)p8FuK! zxdrZkt#BvY1>0adji(HnKvz>HWl{DaxSN4X8r;Lad*EKmVUUtbdF)$El?J%%hG>;uUqlOe{jC*#Jy0H(dL?73Evu@HxFa3m|0L_USg|tb_Ior> zv?l5pb{M$Dj4)vM@0uOD=H8eYQaaeggOs4PR9g}VX>s!gd;iW(1_GHn9%Sb+Y$(WK za3I9ubr>Fiq%Jr@`CV|7ChAzPTWoOqI<#;}SXU8aeGpFQ#r_Z#biu<^Na+p1c2~Q* zB}RV)egUI<;88dQkI^J5qRBn*OLlXLu3lOO`P}5iw3V2v{!!hZn;8|Vz zX(sRtO=0ZU_UN)qT9;+gthHu({Yy1ZN}n3m?Xx0nTIiBTF@0y?Y_)04d7DrpY*DtiAGeI~B`%yK`Vi?3k z`(Q7v_;yN=OU5e_ppt;mY z^QejDABHr{U|UEfW?~j*qu#3v*d~%pZFB>5(t5otR2{3!wdRi2RxP9(WBW_o^XUG} z+S2cFhdla%bY^2wO~%F8!TT{%xwgdJ;fq978G2HBAJyn%YB<6gb&eJcX<_!qt>Y}4 zE1WUQanNt_MK`lcS_h|KF-s_3OAEWOgcj*uk2I|JZhZgEKrBZUc%81Gl3ZOll@?Qa zU6tGGk5Ol04J7qo6;|Uca#J(4^x$k3v|948P%Y6jGA6;Cj#FAK+hhH$(Z6vdXPcc% z9gxV|3qC)5ew`L**CL@+(b~j$Y_h;6(#R2WY9TH%s@h<1>kQ4*N)9$A_CZoX0RyLk ziTP{R#N?LXQW$*@Td@tjcs+UPdRj`pgXqI{^kab9DL~68MCtPy+##=yzu~!T*a`=H zT9Xk?Bcpl^^rbSMotT;BxKfYk3i5YBC5sYE$&k20eW#6qZf#2-7{fqZgKKrE8z~r< za`qZGU{|-TV$8_RxRJ3(8yRn*aBm~y?Q9mnO}LpNw4$$xx8k;he%g*ZsDqZXK1}c{ zt++F>4|n6<1i5{9nbClq!G!KTi1#Ic4j#q_^rao4)m?a$)CVWAs8)V2Q@)>vbFjBLw0 zf*0@;{1iXK&+!ZVJAR4(pxbE^ZKf@B2W_Q0=`PxKglz#|Gc5ZTeuLlQclzkYHi7M| zV|UOl+DrS`9Xk^;P$^~5zcd)|`Xk}!;fg^Vo6LsvLb#FZDB6W91EKmkGa1qiG75~r zpmAs`)!G;+20{yr(^+jxo2H*H`y01&I{fUs5b^q>*v~37HnkbTOkc7w%^9|0)Lv61 z!C)mTkMJ~qmDlf$8)n)Q?t6Q-H&C37lM>pLvvVqIQ_ewmcX3YIN$L8gR?S8YHZ8Mt zuWMjJiaYsG(m*ybZKn06&8DrUyG+|ndrgN;Crpo-erA?iN#}CW+BTu%X-TO%Pp4M zESoG_EPE~cEnSu#%YBwZmLry=gNt+KARZnJK;c3BTv@3$VY9jmqV)~~EzTmL11zzJr-A_zi1p}#Ox7%OB6IYOQ=QJ5kW z3#CH2P$@JC?ZOSh8ey%lPFOE&5Vi?-3%i6p!d_v&@KfPI;e>EfctkiQ{7(42@CV^} z;f!!rcwKl)ct?0&_(1qbxG2h^Lv)J$#erh7I8sa(M~P#^e6dh05~qm8VyQSooFmqW z4Pv9%B({n^(JuzY4snIJO6(N3h&#oD;t}zvcuag)JSjdRo)VuC&xn5&-xA*u-xEI) zFNmLtpW93}**4fV);8WY!Io*uw&mLLZ3VVTwi&i6+br8`Tdl3$HrF=KHs7|;7PQ@J z+iB~zowB`V`^@%@WR+}^EIA~n)K4msrb;uUDyc@ABh^Xsq$N_j6p)rlVd(~GwREFI z(mLt5^o;bnbYA*Mx*&ZjeJgz@eJ@><1zD06*&(OPIr3zAid-z0%H?vEJWHM}*UI(s zT-hyq<%qml-YxHy_siY#LHU09Dfv(Gi}Ii4SL9dazsjG>f0r*RoMKk2il|6Re`T<8 zg)&qbri@pzlpG~bnWRisrYOZqwK7-nC|+f$(yoM*h_YN+sjOEvE4!6F%Du`y<*0I8 zc}V%0@^j@;MQ~PoIL-vR5&)Lt}U$dWg*c<~L$&Mk8D;-xkCOQfoMUHD6 z*E*&;W;m)GvmA|%b&idW6OLav-gLaDN@}t?PR&rSRI8Dx>&Rl1Sv(#DUtZ>e8);s4qo16=ri<~~^ zTIVL`oz88}9nRg(d!7572b?FJr=4Fo|CxkI<|Ip!kmO8CO6s4Ko-{5gD>^^`$Ms&v L8`s!xQqKPY@X^3( 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 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 @@ - - - - - SchemeUserState - - Assemble Application.xcscheme - - orderHint - 4 - - Compile Java.xcscheme - - orderHint - 3 - - CopyJavaSources.xcscheme - - orderHint - 2 - - JPortMidiHeaders.xcscheme - - orderHint - 0 - - PmDefaults.xcscheme - - orderHint - 1 - - - SuppressBuildableAutocreation - - 3D634CAB1247805C0020F829 - - primary - - - 3DE2142D124662AA0033C839 - - primary - - - 89D0F0480F393A6F007831A7 - - primary - - - 89D0F1C90F3B704E007831A7 - - primary - - - 8D1107260486CEB800E47090 - - primary - - - - - 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 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 @@ - - - - - SchemeUserState - - Assemble Application.xcscheme - - orderHint - 5 - - Compile Java.xcscheme - - orderHint - 4 - - CopyJavaSources.xcscheme - - orderHint - 3 - - JPortMidiHeaders.xcscheme - - orderHint - 1 - - PmDefaults.xcscheme - - orderHint - 2 - - - SuppressBuildableAutocreation - - 3D634CAB1247805C0020F829 - - primary - - - 3DE2142D124662AA0033C839 - - primary - - - 89D0F0480F393A6F007831A7 - - primary - - - 89D0F1C90F3B704E007831A7 - - primary - - - 8D1107260486CEB800E47090 - - primary - - - - - 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "Nothing to do for install-headers phase" - - 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 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - JavaApplicationStub - CFBundleIconFile - pmdefaults.icns - CFBundleIdentifier - - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - PmDefaults - CFBundlePackageType - APPL - CFBundleSignature - ???? - CFBundleVersion - 1.0 - CFBundleShortVersionString - 1.0 - Java - - ClassPath - $JAVAROOT/pmdefaults.jar - JVMVersion - 1.5+ - MainClass - pmdefaults.PmDefaults - Properties - - apple.laf.useScreenMenuBar - true - - - - 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 -#include -#include -#include -#include -#include -#include "readbinaryplist.h" -#include - -#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 CF$UIDvalue, 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 +#include +#include +#include +#include +#include +#include "readbinaryplist.h" +#include + +#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 CF$UIDvalue, 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 - -/* 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 + +/* 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 -#include "porttime.h" - -/* asserts used to verify portMidi code logic is sound; later may want - something more graceful */ -#include -#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 +#include "porttime.h" + +/* asserts used to verify portMidi code logic is sound; later may want + something more graceful */ +#include +#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 -#include -#include - -#import -#import -#import -#import -#include - -#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 +#include +#include + +#import +#import +#import +#import +#include + +#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 -WavesAudioBackend::enumerate_drivers () const -{ - // this backend does not suppose driver selection - assert (false); - - return std::vector (); -} - - -int -WavesAudioBackend::set_driver (const std::string& /*drivername*/) -{ - //Waves audio backend does not suppose driver selection - assert (false); - - return -1; -} - - -std::vector -WavesAudioBackend::enumerate_devices () const -{ - // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::enumerate_devices (): " << std::endl; - - std::vector 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 -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 (); - } - - // COMMENTED DBG LOGS */ std::cout << "\tFound " << devInfo.m_AvailableSampleRates.size () << " sample rates for " << device_name << ":"; - - std::vector sample_rates (devInfo.m_AvailableSampleRates.begin (), devInfo.m_AvailableSampleRates.end ()); - - // COMMENTED DBG LOGS */ for (std::vector::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 -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 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 (); - } - - std::vector 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::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 ("")) << "]!" << 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 (_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(_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 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 (arg); - boost::function 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::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::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::iterator it = _physical_audio_inputs.begin (); - it != _physical_audio_inputs.end(); - ++it) - { - memcpy((*it)->buffer(), *buffer, copied_bytes); - ++buffer; - } -#else - std::vector::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::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::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 __instance; - - -boost::shared_ptr -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 +WavesAudioBackend::enumerate_drivers () const +{ + // this backend does not suppose driver selection + assert (false); + + return std::vector (); +} + + +int +WavesAudioBackend::set_driver (const std::string& /*drivername*/) +{ + //Waves audio backend does not suppose driver selection + assert (false); + + return -1; +} + + +std::vector +WavesAudioBackend::enumerate_devices () const +{ + /* COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::enumerate_devices (): " << std::endl; + + std::vector 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 +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 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 (); + } + + sr = device->SamplingRates (); + /* COMMENTED DBG LOGS */ std::cout << "\tFound " << sr.size () << " sample rates for " << device->DeviceName () << ":"; + + std::vector sample_rates (sr.begin (), sr.end ()); + + /* COMMENTED DBG LOGS */ for (std::vector::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 +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 (); + } + + std::vector 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::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 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 ("")) << "]!" << 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 (_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(_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 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 (arg); + boost::function 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::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::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::iterator it = _physical_audio_inputs.begin (); + it != _physical_audio_inputs.end(); + ++it) + { + memcpy((*it)->buffer(), *buffer, copied_bytes); + ++buffer; + } +#else + std::vector::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::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::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 __instance; + + +boost::shared_ptr +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 - -#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 WavesAudioBackend::__available_midi_options = boost::assign::list_of ("None") ("CoreMIDI"); - -#elif _WINDOWS - -const std::vector WavesAudioBackend::__available_midi_options = boost::assign::list_of ("None") ("Multimedia Extensions"); - -#endif - - -std::vector -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 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::const_iterator it = physical_midi_ports.begin (); it != physical_midi_ports.end (); ++it) { - std::vector::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 (_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& devices = _midi_device_manager.devices (); - - for (std::vector::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 (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 (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 (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 (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::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::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 + +#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 WavesAudioBackend::__available_midi_options = boost::assign::list_of ("None") ("CoreMIDI"); + +#elif _WINDOWS + +const std::vector WavesAudioBackend::__available_midi_options = boost::assign::list_of ("None") ("Multimedia Extensions"); + +#endif + + +std::vector +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 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::const_iterator it = physical_midi_ports.begin (); it != physical_midi_ports.end (); ++it) { + std::vector::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 (_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& devices = _midi_device_manager.devices (); + + for (std::vector::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 (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 (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 (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 (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::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::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::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& 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::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::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::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::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::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& 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& connected_ports = ((WavesDataPort*)port_handle)->get_connections (); - - for (std::vector::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& 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::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::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& 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::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::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 !" << 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 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::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 (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 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::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 (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 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::const_iterator it = physical_audio_ports.begin (); it != physical_audio_ports.end (); ++it) { - std::vector::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::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& 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::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::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::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::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::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& 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& connected_ports = ((WavesDataPort*)port_handle)->get_connections (); + + for (std::vector::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& 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::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::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& 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::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::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 !" << 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 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::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 (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 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::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 (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 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::const_iterator it = physical_audio_ports.begin (); it != physical_audio_ports.end (); ++it) { + std::vector::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::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::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::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::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::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::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& 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 _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& 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 _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 () - , _name (name) -{ -} - -WavesMidiBuffer::~WavesMidiBuffer () -{ - clear (); -} - -void WavesMidiBuffer::clear () -{ - for (WavesMidiBufferIterator it = begin (); it != end (); ++it) - delete *it; - - std::vector::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 () + , _name (name) +{ +} + +WavesMidiBuffer::~WavesMidiBuffer () +{ + clear (); +} + +void WavesMidiBuffer::clear () +{ + for (WavesMidiBufferIterator it = begin (); it != end (); ++it) + delete *it; + + std::vector::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 -{ -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::iterator WavesMidiBufferIterator; -typedef std::vector::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 +{ +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::iterator WavesMidiBufferIterator; +typedef std::vector::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 -#include -#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 +#include +#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::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::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. + + 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. -/* 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 ( ...) -#endif - -#include -#include -#include -#endif // #if _WINDOWS -#endif // #ifndef __IncludeWindows_h__ - +#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 ( ...) +#endif + +#include +#include +#include +#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::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) + + +//********************************************************************************************** +// 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 initNewCurrentDeviceImpl(deviceName); -} - - -void WCMRAudioDeviceManager::DestroyCurrentDevice() -{ - return destroyCurrentDeviceImpl(); -} - - -const DeviceInfoVec WCMRAudioDeviceManager::DeviceInfoList() const -{ - wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex); - return m_DeviceInfoVec; -} - - -WTErr WCMRAudioDeviceManager::GetDeviceInfoByName(const std::string & nameToMatch, DeviceInfo & devInfo) const -{ - wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex); - DeviceInfoVecConstIter iter = m_DeviceInfoVec.begin(); - for (; iter != m_DeviceInfoVec.end(); ++iter) + WTErr retVal = eNoErr; + + //Need to call DoIdle of all our devices... + std::vector::iterator deviceIter; + for (deviceIter = m_Devices.begin(); deviceIter != m_Devices.end(); deviceIter++) { - if (nameToMatch == (*iter)->m_DeviceName) - { - devInfo = *(*iter); - return eNoErr; - } + WTErr thisDeviceErr = (*deviceIter)->DoIdle(); + + if (thisDeviceErr != eNoErr) + retVal = thisDeviceErr; } - - return eRMResNotFound; + + return (retVal); } -WTErr WCMRAudioDeviceManager::GetDeviceBufferSizes(const std::string & nameToMatch, std::vector& bufferSizes) 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 { - return getDeviceBufferSizesImpl(nameToMatch, bufferSizes); + return (m_Devices); } + +//********************************************************************************************** +// *WCMRAudioDeviceManager::GetDeviceByName_Private +// +//! Locates a device based on device name. +//! +//! \param nameToMatch : Device to look for. +//! +//! \return Pointer to the device object if found, NULL otherwise. +//! +//********************************************************************************************** +WCMRAudioDevice *WCMRAudioDeviceManager::GetDeviceByName_Private(const std::string& nameToMatch) const +{ + //Need to check all our devices... + WCMRAudioDevice *pRetVal = NULL; + + WCMRAudioDeviceListConstIter deviceIter; + for (deviceIter = m_Devices.begin(); deviceIter != m_Devices.end(); deviceIter++) + { + if ((*deviceIter)->DeviceName() == nameToMatch) + { + pRetVal = *deviceIter; + break; + } + } + + return (pRetVal); +} + +//********************************************************************************************** +// *WCMRAudioDeviceManager::GetDefaultDevice +// +//! Locates a device based on device name. +//! +//! \param nameToMatch : Device to look for. +//! +//! \return Pointer to the device object if found, NULL otherwise. +//! +//********************************************************************************************** +WCMRAudioDevice *WCMRAudioDeviceManager::GetDefaultDevice_Private() +{ + //Need to check all our devices... + WCMRAudioDevice *pRetVal = NULL; + + WCMRAudioDeviceListIter deviceIter = m_Devices.begin(); + if(deviceIter != m_Devices.end()) + { + pRetVal = *deviceIter; + } + return (pRetVal); +} + + + + //********************************************************************************************** // WCMRAudioDeviceManager::NotifyClient // 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; +typedef std::vector WCMRAudioDeviceList; ///< Vector for audio devices +typedef std::vector::iterator WCMRAudioDeviceListIter; ///< Vector iterator for audio devices +typedef std::vector::const_iterator WCMRAudioDeviceListConstIter; ///< Vector iterator for audio devices +typedef std::vector WCMRAudioConnectionsList; ///< Vector for audio devices -struct DeviceInfo -{ - DeviceID m_DeviceId; - std::string m_DeviceName; - std::vector 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 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);///& 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); + } + +public: + + WCMRAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter + ); ///< constructor + virtual ~WCMRAudioDeviceManager(void); ///< Destructor + + virtual WTErr UpdateDeviceList () = 0; //has to be overridden! + + + //This is primarily for use by WCMRAudioDevice and it's descendants... We could have made it + //protected and made WCMRAudioDevice a friend, and then in some way found a way to extend + //the friendship to WCMRAudioDevice's descendants, but that would require a lot of extra + //effort! + void NotifyClient (WCMRAudioDeviceManagerClient::NotificationReason forReason, void *pParam = NULL); + virtual void EnableVerboseLogging(bool /*bEnable*/, const std::string& /*logFilePath*/) { }; protected: - mutable wvNS::wvThread::ThreadMutex m_AudioDeviceInfoVecMutex; // mutex to lock device info list - DeviceInfoVec m_DeviceInfoVec; + //< 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. - 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& bufferSizes) const = 0; - virtual WTErr generateDeviceListImpl() = 0; - virtual WTErr updateDeviceListImpl() = 0; - - 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::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(); + WCMRCoreAudioDeviceManager *pMyManager = (WCMRCoreAudioDeviceManager *)inClientData; - 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; + if (pMyManager) + return pMyManager->PropertyChangeProc (inPropertyID); + + return 0; } -void WCMRCoreAudioDeviceManager::destroyCurrentDeviceImpl() + +//********************************************************************************************** +// 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) { - if (m_CurrentDevice != m_NoneDevice) - delete m_CurrentDevice; - - m_CurrentDevice = 0; -} - - -WTErr WCMRCoreAudioDeviceManager::getDeviceAvailableSampleRates(DeviceID deviceId, std::vector& 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) + OSStatus retVal = 0; + switch (inPropertyID) { - //! 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()); + case kAudioHardwarePropertyDevices: + m_UpdateDeviceListRequested++; + break; + default: + break; } return retVal; } - - -WTErr WCMRCoreAudioDeviceManager::getDeviceMaxInputChannels(DeviceID deviceId, unsigned int& inputChannels) -{ - 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 - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Input channels property size. Device Name: " << m_DeviceName.c_str()); - } - - 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; + 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); - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - outputChannels = 0; - - //! 1. Get property cannels output size. - err = AudioDeviceGetPropertyInfo (deviceId, 0, 0/* Output */, kAudioDevicePropertyStreamConfiguration, &propSize, NULL); - if (err == kAudioHardwareNoError) + std::ostringstream stream_str; + while (p_splited_orig_str != 0) { - //! 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()); - } + 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); } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device Output channels property size. Device Name: " << m_DeviceName.c_str()); - } - - 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::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(*deviceIter); + + //it's possible that the device is actually not a core audio device - perhaps a none device... + if (!pDeviceToWorkUpon) { - //Get property: name. - char* deviceName = new char[propSize]; - osErr = AudioDeviceGetProperty(deviceIDs[deviceIndex], 0, 0, kAudioDevicePropertyDeviceName, &propSize, deviceName); - if (osErr == kAudioHardwareNoError) + deviceIter++; + continue; + } + + AudioDeviceID myDeviceID = pDeviceToWorkUpon->DeviceID(); + bool deviceFound = false; + for (reportedDeviceIndex = 0; reportedDeviceIndex < numDevices; reportedDeviceIndex++) + { + 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); + WCMRCoreAudioDevice *pDeviceToWorkUpon = dynamic_cast(*deviceIter); + //it's possible that the device is actually not a core audio device - perhaps a none device... + if (!pDeviceToWorkUpon) + continue; + + if (pDeviceToWorkUpon->DeviceID() == deviceIDs[reportedDeviceIndex]) + { + deviceFound = true; + break; + } } - - if (pDevInfo) + + if (!deviceFound) { - //Retrieve all the information we need for the device - WTErr wErr = eNoErr; + //add it to our list... + //build a device object... + WCMRCoreAudioDevice *pNewDevice = new WCMRCoreAudioDevice (this, deviceIDs[reportedDeviceIndex], m_UseMultithreading, m_bNoCopyAudioBuffer); + bool bDeleteNewDevice = true; - //Get available sample rates for the device - std::vector availableSampleRates; - wErr = getDeviceAvailableSampleRates(pDevInfo->m_DeviceId, availableSampleRates); - - if (wErr != eNoErr) - { - DEBUG_MSG ("Failed to get device available sample rates. Device ID: " << m_DeviceID); - delete pDevInfo; - continue; //proceed to the next device - } - - pDevInfo->m_AvailableSampleRates = availableSampleRates; - - //Get max input channels - uint32 maxInputChannels; - wErr = getDeviceMaxInputChannels(pDevInfo->m_DeviceId, maxInputChannels); - - if (wErr != eNoErr) - { - DEBUG_MSG ("Failed to get device max input channels count. Device ID: " << m_DeviceID); - delete pDevInfo; - continue; //proceed to the next device - } - - pDevInfo->m_MaxInputChannels = maxInputChannels; - - //Get max output channels - uint32 maxOutputChannels; - wErr = getDeviceMaxOutputChannels(pDevInfo->m_DeviceId, maxOutputChannels); - - if (wErr != eNoErr) - { - DEBUG_MSG ("Failed to get device max output channels count. Device ID: " << m_DeviceID); - delete pDevInfo; - continue; //proceed to the next device - } - - pDevInfo->m_MaxOutputChannels = maxOutputChannels; - - //Now check if this device is acceptable according to current input/output settings - bool bRejectDevice = false; - switch(m_eAudioDeviceFilter) + 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() + +//********************************************************************************************** +// 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() { - wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceInfoVecMutex); - WTErr err = generateDeviceListImpl(); + //WTErr retVal = eNoErr; - 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) + //wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex); + + //If there's something specific to CoreAudio manager idle handling do it here... + if (m_UpdateDeviceListRequested != m_UpdateDeviceListProcessed) { - NotifyClient (WCMRAudioDeviceManagerClient::IODeviceDisconnected); - return err; + m_UpdateDeviceListProcessed = m_UpdateDeviceListRequested; + UpdateDeviceList_Private(); + NotifyClient (WCMRAudioDeviceManagerClient::DeviceListChanged); } - } - - NotifyClient (WCMRAudioDeviceManagerClient::DeviceListChanged); - - return err; + } + + //Note that the superclass is going to call all the devices' DoIdle() anyway... + return (WCMRAudioDeviceManager::DoIdle()); } - -WTErr WCMRCoreAudioDeviceManager::getDeviceBufferSizesImpl(const std::string & deviceName, std::vector& bufferSizes) const -{ - AUTO_FUNC_DEBUG; - - WTErr retVal = eNoErr; - OSStatus err = kAudioHardwareNoError; - UInt32 propSize = 0; - - bufferSizes.clear(); - - //first check if the request has been made for None device - if (deviceName == m_NoneDevice->DeviceName() ) - { - bufferSizes = m_NoneDevice->BufferSizes(); - return retVal; - } - - DeviceInfo devInfo; - retVal = GetDeviceInfoByName(deviceName, devInfo); - - if (eNoErr == retVal) - { - // 1. Get buffer size range - AudioValueRange bufferSizesRange; - propSize = sizeof (AudioValueRange); - err = AudioDeviceGetProperty (devInfo.m_DeviceId, 0, 0, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &bufferSizesRange); - if(err == kAudioHardwareNoError) - { - // 2. Run on all ranges and add them to the list - for(int bsize=0; gAllBufferSizes[bsize] > 0; bsize++) - { - if ((bufferSizesRange.mMinimum <= gAllBufferSizes[bsize]) && (bufferSizesRange.mMaximum >= gAllBufferSizes[bsize])) - { - bufferSizes.push_back (gAllBufferSizes[bsize]); - } - } - - //if we didn't get a single hit, let's simply add the min. and the max... - if (bufferSizes.empty()) - { - bufferSizes.push_back ((int)bufferSizesRange.mMinimum); - bufferSizes.push_back ((int)bufferSizesRange.mMaximum); - } - } - else - { - retVal = eCoreAudioFailed; - DEBUG_MSG("Failed to get device buffer sizes range. Device Name: " << m_DeviceName.c_str()); - } - } - else - { - retVal = eRMResNotFound; - std::cout << "API::PortAudioDeviceManager::GetBufferSizes: Device not found: "<< deviceName << std::endl; - } - - - return retVal; -} - - -OSStatus WCMRCoreAudioDeviceManager::DevicePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* inClientData) -{ - switch (inPropertyID) - { - case kAudioHardwarePropertyDevices: - { - WCMRCoreAudioDeviceManager* pManager = (WCMRCoreAudioDeviceManager*)inClientData; - if (pManager) - pManager->updateDeviceListImpl(); - } - break; - default: - break; - } - - return 0; -} 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& 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& 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);/// -#include -using namespace wvNS; -#include "IncludeWindows.h" -#include -#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::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::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(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(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 " <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(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(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::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::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& 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(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(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 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 = " <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& 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(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);///& 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& 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 -#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(&theTime)->hi;} - uint32_t UMicroseconds::lo() {return reinterpret_cast(&theTime)->lo;} -#endif + 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. + */ -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 { +#ifdef _WINDOWS + #include "IncludeWindows.h" +#endif +#if defined(__linux__) || defined(__MACOS__) + #include +#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(&theTime)->hi;} + uint32_t UMicroseconds::lo() {return reinterpret_cast(&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" +/* + 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 "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(theTime);} - operator double () const {return static_cast(theTime);} - - double Seconds() const {return static_cast(theTime) / double(1000000);} - double MilliSeconds() const {return static_cast(theTime) / double(1000);} - double MicroSeconds() const {return static_cast(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(theTime);} + operator double () const {return static_cast(theTime);} + + double Seconds() const {return static_cast(theTime) / double(1000000);} + double MilliSeconds() const {return static_cast(theTime) / double(1000);} + double MicroSeconds() const {return static_cast(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 old mode 100755 new mode 100644 index b2a552ff18..814f16bc44 --- 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' + ]