new audio engine backend for native CoreAudio audio I/O, and PortMIDI for MIDI.

Code builds, runs and functions. Full code review still pending, and some possibly changes to organization of code within the backend is possible
This commit is contained in:
Paul Davis 2014-02-24 14:39:10 -05:00
parent 0a6af1420f
commit 1de00ab6bb
84 changed files with 21936 additions and 0 deletions

View file

@ -0,0 +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 */

View file

@ -0,0 +1,654 @@
#ifndef PORT_MIDI_H
#define PORT_MIDI_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*
* PortMidi Portable Real-Time MIDI Library
* PortMidi API Header File
* Latest version available at: http://sourceforge.net/projects/portmedia
*
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
* Copyright (c) 2001-2006 Roger B. Dannenberg
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* The text above constitutes the entire PortMidi license; however,
* the PortMusic community also makes the following non-binding requests:
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* license above.
*/
/* CHANGELOG FOR PORTMIDI
* (see ../CHANGELOG.txt)
*
* NOTES ON HOST ERROR REPORTING:
*
* PortMidi errors (of type PmError) are generic, system-independent errors.
* When an error does not map to one of the more specific PmErrors, the
* catch-all code pmHostError is returned. This means that PortMidi has
* retained a more specific system-dependent error code. The caller can
* get more information by calling Pm_HasHostError() to test if there is
* a pending host error, and Pm_GetHostErrorText() to get a text string
* describing the error. Host errors are reported on a per-device basis
* because only after you open a device does PortMidi have a place to
* record the host error code. I.e. only
* those routines that receive a (PortMidiStream *) argument check and
* report errors. One exception to this is that Pm_OpenInput() and
* Pm_OpenOutput() can report errors even though when an error occurs,
* there is no PortMidiStream* to hold the error. Fortunately, both
* of these functions return any error immediately, so we do not really
* need per-device error memory. Instead, any host error code is stored
* in a global, pmHostError is returned, and the user can call
* Pm_GetHostErrorText() to get the error message (and the invalid stream
* parameter will be ignored.) The functions
* pm_init and pm_term do not fail or raise
* errors. The job of pm_init is to locate all available devices so that
* the caller can get information via PmDeviceInfo(). If an error occurs,
* the device is simply not listed as available.
*
* Host errors come in two flavors:
* a) host error
* b) host error during callback
* These can occur w/midi input or output devices. (b) can only happen
* asynchronously (during callback routines), whereas (a) only occurs while
* synchronously running PortMidi and any resulting system dependent calls.
* Both (a) and (b) are reported by the next read or write call. You can
* also query for asynchronous errors (b) at any time by calling
* Pm_HasHostError().
*
* NOTES ON COMPILE-TIME SWITCHES
*
* DEBUG assumes stdio and a console. Use this if you want automatic, simple
* error reporting, e.g. for prototyping. If you are using MFC or some
* other graphical interface with no console, DEBUG probably should be
* undefined.
* PM_CHECK_ERRORS more-or-less takes over error checking for return values,
* stopping your program and printing error messages when an error
* occurs. This also uses stdio for console text I/O.
*/
#ifndef WIN32
// Linux and OS X have stdint.h
#include <stdint.h>
#else
#ifndef INT32_DEFINED
// rather than having users install a special .h file for windows,
// just put the required definitions inline here. porttime.h uses
// these too, so the definitions are (unfortunately) duplicated there
typedef int int32_t;
typedef unsigned int uint32_t;
#define INT32_DEFINED
#endif
#endif
#ifdef _WINDLL
#define PMEXPORT __declspec(dllexport)
#else
#define PMEXPORT
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
/* default size of buffers for sysex transmission: */
#define PM_DEFAULT_SYSEX_BUFFER_SIZE 1024
/** List of portmidi errors.*/
typedef enum {
pmNoError = 0,
pmNoData = 0, /**< A "no error" return that also indicates no data avail. */
pmGotData = 1, /**< A "no error" return that also indicates data available */
pmHostError = -10000,
pmInvalidDeviceId, /** out of range or
* output device when input is requested or
* input device when output is requested or
* device is already opened
*/
pmInsufficientMemory,
pmBufferTooSmall,
pmBufferOverflow,
pmBadPtr, /* PortMidiStream parameter is NULL or
* stream is not opened or
* stream is output when input is required or
* stream is input when output is required */
pmBadData, /** illegal midi data, e.g. missing EOX */
pmInternalError,
pmBufferMaxSize /** buffer is already as large as it can be */
/* NOTE: If you add a new error type, be sure to update Pm_GetErrorText() */
} PmError;
/**
Pm_Initialize() is the library initialisation function - call this before
using the library.
*/
PMEXPORT PmError Pm_Initialize( void );
/**
Pm_Terminate() is the library termination function - call this after
using the library.
*/
PMEXPORT PmError Pm_Terminate( void );
/** A single PortMidiStream is a descriptor for an open MIDI device.
*/
typedef void PortMidiStream;
#define PmStream PortMidiStream
/**
Test whether stream has a pending host error. Normally, the client finds
out about errors through returned error codes, but some errors can occur
asynchronously where the client does not
explicitly call a function, and therefore cannot receive an error code.
The client can test for a pending error using Pm_HasHostError(). If true,
the error can be accessed and cleared by calling Pm_GetErrorText().
Errors are also cleared by calling other functions that can return
errors, e.g. Pm_OpenInput(), Pm_OpenOutput(), Pm_Read(), Pm_Write(). The
client does not need to call Pm_HasHostError(). Any pending error will be
reported the next time the client performs an explicit function call on
the stream, e.g. an input or output operation. Until the error is cleared,
no new error codes will be obtained, even for a different stream.
*/
PMEXPORT int Pm_HasHostError( PortMidiStream * stream );
/** Translate portmidi error number into human readable message.
These strings are constants (set at compile time) so client has
no need to allocate storage
*/
PMEXPORT const char *Pm_GetErrorText( PmError errnum );
/** Translate portmidi host error into human readable message.
These strings are computed at run time, so client has to allocate storage.
After this routine executes, the host error is cleared.
*/
PMEXPORT void Pm_GetHostErrorText(char * msg, unsigned int len);
#define HDRLENGTH 50
#define PM_HOST_ERROR_MSG_LEN 256u /* any host error msg will occupy less
than this number of characters */
/**
Device enumeration mechanism.
Device ids range from 0 to Pm_CountDevices()-1.
*/
typedef int PmDeviceID;
#define pmNoDevice -1
typedef struct {
int structVersion; /**< this internal structure version */
const char *interf; /**< underlying MIDI API, e.g. MMSystem or DirectX */
const char *name; /**< device name, e.g. USB MidiSport 1x1 */
int input; /**< true iff input is available */
int output; /**< true iff output is available */
int opened; /**< used by generic PortMidi code to do error checking on arguments */
} PmDeviceInfo;
/** Get devices count, ids range from 0 to Pm_CountDevices()-1. */
PMEXPORT int Pm_CountDevices( void );
/**
Pm_GetDefaultInputDeviceID(), Pm_GetDefaultOutputDeviceID()
Return the default device ID or pmNoDevice if there are no devices.
The result (but not pmNoDevice) can be passed to Pm_OpenMidi().
The default device can be specified using a small application
named pmdefaults that is part of the PortMidi distribution. This
program in turn uses the Java Preferences object created by
java.util.prefs.Preferences.userRoot().node("/PortMidi"); the
preference is set by calling
prefs.put("PM_RECOMMENDED_OUTPUT_DEVICE", prefName);
or prefs.put("PM_RECOMMENDED_INPUT_DEVICE", prefName);
In the statements above, prefName is a string describing the
MIDI device in the form "interf, name" where interf identifies
the underlying software system or API used by PortMdi to access
devices and name is the name of the device. These correspond to
the interf and name fields of a PmDeviceInfo. (Currently supported
interfaces are "MMSystem" for Win32, "ALSA" for Linux, and
"CoreMIDI" for OS X, so in fact, there is no choice of interface.)
In "interf, name", the strings are actually substrings of
the full interface and name strings. For example, the preference
"Core, Sport" will match a device with interface "CoreMIDI"
and name "In USB MidiSport 1x1". It will also match "CoreMIDI"
and "In USB MidiSport 2x2". The devices are enumerated in device
ID order, so the lowest device ID that matches the pattern becomes
the default device. Finally, if the comma-space (", ") separator
between interface and name parts of the preference is not found,
the entire preference string is interpreted as a name, and the
interface part is the empty string, which matches anything.
On the MAC, preferences are stored in
/Users/$NAME/Library/Preferences/com.apple.java.util.prefs.plist
which is a binary file. In addition to the pmdefaults program,
there are utilities that can read and edit this preference file.
On the PC,
On Linux,
*/
PMEXPORT PmDeviceID Pm_GetDefaultInputDeviceID( void );
/** see PmDeviceID Pm_GetDefaultInputDeviceID() */
PMEXPORT PmDeviceID Pm_GetDefaultOutputDeviceID( void );
/**
PmTimestamp is used to represent a millisecond clock with arbitrary
start time. The type is used for all MIDI timestampes and clocks.
*/
typedef int32_t PmTimestamp;
typedef PmTimestamp (*PmTimeProcPtr)(void *time_info);
/** TRUE if t1 before t2 */
#define PmBefore(t1,t2) ((t1-t2) < 0)
/**
\defgroup grp_device Input/Output Devices Handling
@{
*/
/**
Pm_GetDeviceInfo() returns a pointer to a PmDeviceInfo structure
referring to the device specified by id.
If id is out of range the function returns NULL.
The returned structure is owned by the PortMidi implementation and must
not be manipulated or freed. The pointer is guaranteed to be valid
between calls to Pm_Initialize() and Pm_Terminate().
*/
PMEXPORT const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id );
/**
Pm_OpenInput() and Pm_OpenOutput() open devices.
stream is the address of a PortMidiStream pointer which will receive
a pointer to the newly opened stream.
inputDevice is the id of the device used for input (see PmDeviceID above).
inputDriverInfo is a pointer to an optional driver specific data structure
containing additional information for device setup or handle processing.
inputDriverInfo is never required for correct operation. If not used
inputDriverInfo should be NULL.
outputDevice is the id of the device used for output (see PmDeviceID above.)
outputDriverInfo is a pointer to an optional driver specific data structure
containing additional information for device setup or handle processing.
outputDriverInfo is never required for correct operation. If not used
outputDriverInfo should be NULL.
For input, the buffersize specifies the number of input events to be
buffered waiting to be read using Pm_Read(). For output, buffersize
specifies the number of output events to be buffered waiting for output.
(In some cases -- see below -- PortMidi does not buffer output at all
and merely passes data to a lower-level API, in which case buffersize
is ignored.)
latency is the delay in milliseconds applied to timestamps to determine
when the output should actually occur. (If latency is < 0, 0 is assumed.)
If latency is zero, timestamps are ignored and all output is delivered
immediately. If latency is greater than zero, output is delayed until the
message timestamp plus the latency. (NOTE: the time is measured relative
to the time source indicated by time_proc. Timestamps are absolute,
not relative delays or offsets.) In some cases, PortMidi can obtain
better timing than your application by passing timestamps along to the
device driver or hardware. Latency may also help you to synchronize midi
data to audio data by matching midi latency to the audio buffer latency.
time_proc is a pointer to a procedure that returns time in milliseconds. It
may be NULL, in which case a default millisecond timebase (PortTime) is
used. If the application wants to use PortTime, it should start the timer
(call Pt_Start) before calling Pm_OpenInput or Pm_OpenOutput. If the
application tries to start the timer *after* Pm_OpenInput or Pm_OpenOutput,
it may get a ptAlreadyStarted error from Pt_Start, and the application's
preferred time resolution and callback function will be ignored.
time_proc result values are appended to incoming MIDI data, and time_proc
times are used to schedule outgoing MIDI data (when latency is non-zero).
time_info is a pointer passed to time_proc.
Example: If I provide a timestamp of 5000, latency is 1, and time_proc
returns 4990, then the desired output time will be when time_proc returns
timestamp+latency = 5001. This will be 5001-4990 = 11ms from now.
return value:
Upon success Pm_Open() returns PmNoError and places a pointer to a
valid PortMidiStream in the stream argument.
If a call to Pm_Open() fails a nonzero error code is returned (see
PMError above) and the value of port is invalid.
Any stream that is successfully opened should eventually be closed
by calling Pm_Close().
*/
PMEXPORT PmError Pm_OpenInput( PortMidiStream** stream,
PmDeviceID inputDevice,
void *inputDriverInfo,
int32_t bufferSize,
PmTimeProcPtr time_proc,
void *time_info );
PMEXPORT PmError Pm_OpenOutput( PortMidiStream** stream,
PmDeviceID outputDevice,
void *outputDriverInfo,
int32_t bufferSize,
PmTimeProcPtr time_proc,
void *time_info,
int32_t latency );
/** @} */
/**
\defgroup grp_events_filters Events and Filters Handling
@{
*/
/* \function PmError Pm_SetFilter( PortMidiStream* stream, int32_t filters )
Pm_SetFilter() sets filters on an open input stream to drop selected
input types. By default, only active sensing messages are filtered.
To prohibit, say, active sensing and sysex messages, call
Pm_SetFilter(stream, PM_FILT_ACTIVE | PM_FILT_SYSEX);
Filtering is useful when midi routing or midi thru functionality is being
provided by the user application.
For example, you may want to exclude timing messages (clock, MTC, start/stop/continue),
while allowing note-related messages to pass.
Or you may be using a sequencer or drum-machine for MIDI clock information but want to
exclude any notes it may play.
*/
/* Filter bit-mask definitions */
/** filter active sensing messages (0xFE): */
#define PM_FILT_ACTIVE (1 << 0x0E)
/** filter system exclusive messages (0xF0): */
#define PM_FILT_SYSEX (1 << 0x00)
/** filter MIDI clock message (0xF8) */
#define PM_FILT_CLOCK (1 << 0x08)
/** filter play messages (start 0xFA, stop 0xFC, continue 0xFB) */
#define PM_FILT_PLAY ((1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B))
/** filter tick messages (0xF9) */
#define PM_FILT_TICK (1 << 0x09)
/** filter undefined FD messages */
#define PM_FILT_FD (1 << 0x0D)
/** filter undefined real-time messages */
#define PM_FILT_UNDEFINED PM_FILT_FD
/** filter reset messages (0xFF) */
#define PM_FILT_RESET (1 << 0x0F)
/** filter all real-time messages */
#define PM_FILT_REALTIME (PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_CLOCK | \
PM_FILT_PLAY | PM_FILT_UNDEFINED | PM_FILT_RESET | PM_FILT_TICK)
/** filter note-on and note-off (0x90-0x9F and 0x80-0x8F */
#define PM_FILT_NOTE ((1 << 0x19) | (1 << 0x18))
/** filter channel aftertouch (most midi controllers use this) (0xD0-0xDF)*/
#define PM_FILT_CHANNEL_AFTERTOUCH (1 << 0x1D)
/** per-note aftertouch (0xA0-0xAF) */
#define PM_FILT_POLY_AFTERTOUCH (1 << 0x1A)
/** filter both channel and poly aftertouch */
#define PM_FILT_AFTERTOUCH (PM_FILT_CHANNEL_AFTERTOUCH | PM_FILT_POLY_AFTERTOUCH)
/** Program changes (0xC0-0xCF) */
#define PM_FILT_PROGRAM (1 << 0x1C)
/** Control Changes (CC's) (0xB0-0xBF)*/
#define PM_FILT_CONTROL (1 << 0x1B)
/** Pitch Bender (0xE0-0xEF*/
#define PM_FILT_PITCHBEND (1 << 0x1E)
/** MIDI Time Code (0xF1)*/
#define PM_FILT_MTC (1 << 0x01)
/** Song Position (0xF2) */
#define PM_FILT_SONG_POSITION (1 << 0x02)
/** Song Select (0xF3)*/
#define PM_FILT_SONG_SELECT (1 << 0x03)
/** Tuning request (0xF6)*/
#define PM_FILT_TUNE (1 << 0x06)
/** All System Common messages (mtc, song position, song select, tune request) */
#define PM_FILT_SYSTEMCOMMON (PM_FILT_MTC | PM_FILT_SONG_POSITION | PM_FILT_SONG_SELECT | PM_FILT_TUNE)
PMEXPORT PmError Pm_SetFilter( PortMidiStream* stream, int32_t filters );
#define Pm_Channel(channel) (1<<(channel))
/**
Pm_SetChannelMask() filters incoming messages based on channel.
The mask is a 16-bit bitfield corresponding to appropriate channels.
The Pm_Channel macro can assist in calling this function.
i.e. to set receive only input on channel 1, call with
Pm_SetChannelMask(Pm_Channel(1));
Multiple channels should be OR'd together, like
Pm_SetChannelMask(Pm_Channel(10) | Pm_Channel(11))
Note that channels are numbered 0 to 15 (not 1 to 16). Most
synthesizer and interfaces number channels starting at 1, but
PortMidi numbers channels starting at 0.
All channels are allowed by default
*/
PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask);
/**
Pm_Abort() terminates outgoing messages immediately
The caller should immediately close the output port;
this call may result in transmission of a partial midi message.
There is no abort for Midi input because the user can simply
ignore messages in the buffer and close an input device at
any time.
*/
PMEXPORT PmError Pm_Abort( PortMidiStream* stream );
/**
Pm_Close() closes a midi stream, flushing any pending buffers.
(PortMidi attempts to close open streams when the application
exits -- this is particularly difficult under Windows.)
*/
PMEXPORT PmError Pm_Close( PortMidiStream* stream );
/**
Pm_Synchronize() instructs PortMidi to (re)synchronize to the
time_proc passed when the stream was opened. Typically, this
is used when the stream must be opened before the time_proc
reference is actually advancing. In this case, message timing
may be erratic, but since timestamps of zero mean
"send immediately," initialization messages with zero timestamps
can be written without a functioning time reference and without
problems. Before the first MIDI message with a non-zero
timestamp is written to the stream, the time reference must
begin to advance (for example, if the time_proc computes time
based on audio samples, time might begin to advance when an
audio stream becomes active). After time_proc return values
become valid, and BEFORE writing the first non-zero timestamped
MIDI message, call Pm_Synchronize() so that PortMidi can observe
the difference between the current time_proc value and its
MIDI stream time.
In the more normal case where time_proc
values advance continuously, there is no need to call
Pm_Synchronize. PortMidi will always synchronize at the
first output message and periodically thereafter.
*/
PmError Pm_Synchronize( PortMidiStream* stream );
/**
Pm_Message() encodes a short Midi message into a 32-bit word. If data1
and/or data2 are not present, use zero.
Pm_MessageStatus(), Pm_MessageData1(), and
Pm_MessageData2() extract fields from a 32-bit midi message.
*/
#define Pm_Message(status, data1, data2) \
((((data2) << 16) & 0xFF0000) | \
(((data1) << 8) & 0xFF00) | \
((status) & 0xFF))
#define Pm_MessageStatus(msg) ((msg) & 0xFF)
#define Pm_MessageData1(msg) (((msg) >> 8) & 0xFF)
#define Pm_MessageData2(msg) (((msg) >> 16) & 0xFF)
typedef int32_t PmMessage; /**< see PmEvent */
/**
All midi data comes in the form of PmEvent structures. A sysex
message is encoded as a sequence of PmEvent structures, with each
structure carrying 4 bytes of the message, i.e. only the first
PmEvent carries the status byte.
Note that MIDI allows nested messages: the so-called "real-time" MIDI
messages can be inserted into the MIDI byte stream at any location,
including within a sysex message. MIDI real-time messages are one-byte
messages used mainly for timing (see the MIDI spec). PortMidi retains
the order of non-real-time MIDI messages on both input and output, but
it does not specify exactly how real-time messages are processed. This
is particulary problematic for MIDI input, because the input parser
must either prepare to buffer an unlimited number of sysex message
bytes or to buffer an unlimited number of real-time messages that
arrive embedded in a long sysex message. To simplify things, the input
parser is allowed to pass real-time MIDI messages embedded within a
sysex message, and it is up to the client to detect, process, and
remove these messages as they arrive.
When receiving sysex messages, the sysex message is terminated
by either an EOX status byte (anywhere in the 4 byte messages) or
by a non-real-time status byte in the low order byte of the message.
If you get a non-real-time status byte but there was no EOX byte, it
means the sysex message was somehow truncated. This is not
considered an error; e.g., a missing EOX can result from the user
disconnecting a MIDI cable during sysex transmission.
A real-time message can occur within a sysex message. A real-time
message will always occupy a full PmEvent with the status byte in
the low-order byte of the PmEvent message field. (This implies that
the byte-order of sysex bytes and real-time message bytes may not
be preserved -- for example, if a real-time message arrives after
3 bytes of a sysex message, the real-time message will be delivered
first. The first word of the sysex message will be delivered only
after the 4th byte arrives, filling the 4-byte PmEvent message field.
The timestamp field is observed when the output port is opened with
a non-zero latency. A timestamp of zero means "use the current time",
which in turn means to deliver the message with a delay of
latency (the latency parameter used when opening the output port.)
Do not expect PortMidi to sort data according to timestamps --
messages should be sent in the correct order, and timestamps MUST
be non-decreasing. See also "Example" for Pm_OpenOutput() above.
A sysex message will generally fill many PmEvent structures. On
output to a PortMidiStream with non-zero latency, the first timestamp
on sysex message data will determine the time to begin sending the
message. PortMidi implementations may ignore timestamps for the
remainder of the sysex message.
On input, the timestamp ideally denotes the arrival time of the
status byte of the message. The first timestamp on sysex message
data will be valid. Subsequent timestamps may denote
when message bytes were actually received, or they may be simply
copies of the first timestamp.
Timestamps for nested messages: If a real-time message arrives in
the middle of some other message, it is enqueued immediately with
the timestamp corresponding to its arrival time. The interrupted
non-real-time message or 4-byte packet of sysex data will be enqueued
later. The timestamp of interrupted data will be equal to that of
the interrupting real-time message to insure that timestamps are
non-decreasing.
*/
typedef struct {
PmMessage message;
PmTimestamp timestamp;
} PmEvent;
/**
@}
*/
/** \defgroup grp_io Reading and Writing Midi Messages
@{
*/
/**
Pm_Read() retrieves midi data into a buffer, and returns the number
of events read. Result is a non-negative number unless an error occurs,
in which case a PmError value will be returned.
Buffer Overflow
The problem: if an input overflow occurs, data will be lost, ultimately
because there is no flow control all the way back to the data source.
When data is lost, the receiver should be notified and some sort of
graceful recovery should take place, e.g. you shouldn't resume receiving
in the middle of a long sysex message.
With a lock-free fifo, which is pretty much what we're stuck with to
enable portability to the Mac, it's tricky for the producer and consumer
to synchronously reset the buffer and resume normal operation.
Solution: the buffer managed by PortMidi will be flushed when an overflow
occurs. The consumer (Pm_Read()) gets an error message (pmBufferOverflow)
and ordinary processing resumes as soon as a new message arrives. The
remainder of a partial sysex message is not considered to be a "new
message" and will be flushed as well.
*/
PMEXPORT int Pm_Read( PortMidiStream *stream, PmEvent *buffer, int32_t length );
/**
Pm_Poll() tests whether input is available,
returning TRUE, FALSE, or an error value.
*/
PMEXPORT PmError Pm_Poll( PortMidiStream *stream);
/**
Pm_Write() writes midi data from a buffer. This may contain:
- short messages
or
- sysex messages that are converted into a sequence of PmEvent
structures, e.g. sending data from a file or forwarding them
from midi input.
Use Pm_WriteSysEx() to write a sysex message stored as a contiguous
array of bytes.
Sysex data may contain embedded real-time messages.
*/
PMEXPORT PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, int32_t length );
/**
Pm_WriteShort() writes a timestamped non-system-exclusive midi message.
Messages are delivered in order as received, and timestamps must be
non-decreasing. (But timestamps are ignored if the stream was opened
with latency = 0.)
*/
PMEXPORT PmError Pm_WriteShort( PortMidiStream *stream, PmTimestamp when, int32_t msg);
/**
Pm_WriteSysEx() writes a timestamped system-exclusive midi message.
*/
PMEXPORT PmError Pm_WriteSysEx( PortMidiStream *stream, PmTimestamp when, unsigned char *msg);
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* PORT_MIDI_H */

View file

@ -0,0 +1,92 @@
/* porttime.h -- portable interface to millisecond timer */
/* CHANGE LOG FOR PORTTIME
10-Jun-03 Mark Nelson & RBD
boost priority of timer thread in ptlinux.c implementation
*/
/* Should there be a way to choose the source of time here? */
#ifdef WIN32
#ifndef INT32_DEFINED
// rather than having users install a special .h file for windows,
// just put the required definitions inline here. portmidi.h uses
// these too, so the definitions are (unfortunately) duplicated there
typedef int int32_t;
typedef unsigned int uint32_t;
#define INT32_DEFINED
#endif
#else
#include <stdint.h> // needed for int32_t
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef PMEXPORT
#ifdef _WINDLL
#define PMEXPORT __declspec(dllexport)
#else
#define PMEXPORT
#endif
#endif
typedef enum {
ptNoError = 0, /* success */
ptHostError = -10000, /* a system-specific error occurred */
ptAlreadyStarted, /* cannot start timer because it is already started */
ptAlreadyStopped, /* cannot stop timer because it is already stopped */
ptInsufficientMemory /* memory could not be allocated */
} PtError;
typedef int32_t PtTimestamp;
typedef void (PtCallback)( PtTimestamp timestamp, void *userData );
/*
Pt_Start() starts a real-time service.
resolution is the timer resolution in ms. The time will advance every
resolution ms.
callback is a function pointer to be called every resolution ms.
userData is passed to callback as a parameter.
return value:
Upon success, returns ptNoError. See PtError for other values.
*/
PMEXPORT PtError Pt_Start(int resolution, PtCallback *callback, void *userData);
/*
Pt_Stop() stops the timer.
return value:
Upon success, returns ptNoError. See PtError for other values.
*/
PMEXPORT PtError Pt_Stop();
/*
Pt_Started() returns true iff the timer is running.
*/
PMEXPORT int Pt_Started();
/*
Pt_Time() returns the current time in ms.
*/
PMEXPORT PtTimestamp Pt_Time();
/*
Pt_Sleep() pauses, allowing other threads to run.
duration is the length of the pause in ms. The true duration
of the pause may be rounded to the nearest or next clock tick
as determined by resolution in Pt_Start().
*/
PMEXPORT void Pt_Sleep(int32_t duration);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +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

View file

@ -0,0 +1,284 @@
/* pmutil.c -- some helpful utilities for building midi
applications that use PortMidi
*/
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "portmidi.h"
#include "pmutil.h"
#include "pminternal.h"
#ifdef WIN32
#define bzero(addr, siz) memset(addr, 0, siz)
#endif
// #define QUEUE_DEBUG 1
#ifdef QUEUE_DEBUG
#include "stdio.h"
#endif
typedef struct {
long head;
long tail;
long len;
long overflow;
int32_t msg_size; /* number of int32_t in a message including extra word */
int32_t peek_overflow;
int32_t *buffer;
int32_t *peek;
int32_t peek_flag;
} PmQueueRep;
PMEXPORT PmQueue *Pm_QueueCreate(long num_msgs, int32_t bytes_per_msg)
{
int32_t int32s_per_msg =
(int32_t) (((bytes_per_msg + sizeof(int32_t) - 1) &
~(sizeof(int32_t) - 1)) / sizeof(int32_t));
PmQueueRep *queue = (PmQueueRep *) pm_alloc(sizeof(PmQueueRep));
if (!queue) /* memory allocation failed */
return NULL;
/* need extra word per message for non-zero encoding */
queue->len = num_msgs * (int32s_per_msg + 1);
queue->buffer = (int32_t *) pm_alloc(queue->len * sizeof(int32_t));
bzero(queue->buffer, queue->len * sizeof(int32_t));
if (!queue->buffer) {
pm_free(queue);
return NULL;
} else { /* allocate the "peek" buffer */
queue->peek = (int32_t *) pm_alloc(int32s_per_msg * sizeof(int32_t));
if (!queue->peek) {
/* free everything allocated so far and return */
pm_free(queue->buffer);
pm_free(queue);
return NULL;
}
}
bzero(queue->buffer, queue->len * sizeof(int32_t));
queue->head = 0;
queue->tail = 0;
/* msg_size is in words */
queue->msg_size = int32s_per_msg + 1; /* note extra word is counted */
queue->overflow = FALSE;
queue->peek_overflow = FALSE;
queue->peek_flag = FALSE;
return queue;
}
PMEXPORT PmError Pm_QueueDestroy(PmQueue *q)
{
PmQueueRep *queue = (PmQueueRep *) q;
/* arg checking */
if (!queue || !queue->buffer || !queue->peek)
return pmBadPtr;
pm_free(queue->peek);
pm_free(queue->buffer);
pm_free(queue);
return pmNoError;
}
PMEXPORT PmError Pm_Dequeue(PmQueue *q, void *msg)
{
long head;
PmQueueRep *queue = (PmQueueRep *) q;
int i;
int32_t *msg_as_int32 = (int32_t *) msg;
/* arg checking */
if (!queue)
return pmBadPtr;
/* a previous peek operation encountered an overflow, but the overflow
* has not yet been reported to client, so do it now. No message is
* returned, but on the next call, we will return the peek buffer.
*/
if (queue->peek_overflow) {
queue->peek_overflow = FALSE;
return pmBufferOverflow;
}
if (queue->peek_flag) {
memcpy(msg, queue->peek, (queue->msg_size - 1) * sizeof(int32_t));
queue->peek_flag = FALSE;
return pmGotData;
}
head = queue->head;
/* if writer overflows, it writes queue->overflow = tail+1 so that
* when the reader gets to that position in the buffer, it can
* return the overflow condition to the reader. The problem is that
* at overflow, things have wrapped around, so tail == head, and the
* reader will detect overflow immediately instead of waiting until
* it reads everything in the buffer, wrapping around again to the
* point where tail == head. So the condition also checks that
* queue->buffer[head] is zero -- if so, then the buffer is now
* empty, and we're at the point in the msg stream where overflow
* occurred. It's time to signal overflow to the reader. If
* queue->buffer[head] is non-zero, there's a message there and we
* should read all the way around the buffer before signalling overflow.
* There is a write-order dependency here, but to fail, the overflow
* field would have to be written while an entire buffer full of
* writes are still pending. I'm assuming out-of-order writes are
* possible, but not that many.
*/
if (queue->overflow == head + 1 && !queue->buffer[head]) {
queue->overflow = 0; /* non-overflow condition */
return pmBufferOverflow;
}
/* test to see if there is data in the queue -- test from back
* to front so if writer is simultaneously writing, we don't
* waste time discovering the write is not finished
*/
for (i = queue->msg_size - 1; i >= 0; i--) {
if (!queue->buffer[head + i]) {
return pmNoData;
}
}
memcpy(msg, (char *) &queue->buffer[head + 1],
sizeof(int32_t) * (queue->msg_size - 1));
/* fix up zeros */
i = queue->buffer[head];
while (i < queue->msg_size) {
int32_t j;
i--; /* msg does not have extra word so shift down */
j = msg_as_int32[i];
msg_as_int32[i] = 0;
i = j;
}
/* signal that data has been removed by zeroing: */
bzero((char *) &queue->buffer[head], sizeof(int32_t) * queue->msg_size);
/* update head */
head += queue->msg_size;
if (head == queue->len) head = 0;
queue->head = head;
return pmGotData; /* success */
}
PMEXPORT PmError Pm_SetOverflow(PmQueue *q)
{
PmQueueRep *queue = (PmQueueRep *) q;
long tail;
/* arg checking */
if (!queue)
return pmBadPtr;
/* no more enqueue until receiver acknowledges overflow */
if (queue->overflow) return pmBufferOverflow;
tail = queue->tail;
queue->overflow = tail + 1;
return pmBufferOverflow;
}
PMEXPORT PmError Pm_Enqueue(PmQueue *q, void *msg)
{
PmQueueRep *queue = (PmQueueRep *) q;
long tail;
int i;
int32_t *src = (int32_t *) msg;
int32_t *ptr;
int32_t *dest;
int rslt;
if (!queue)
return pmBadPtr;
/* no more enqueue until receiver acknowledges overflow */
if (queue->overflow) return pmBufferOverflow;
rslt = Pm_QueueFull(q);
/* already checked above: if (rslt == pmBadPtr) return rslt; */
tail = queue->tail;
if (rslt) {
queue->overflow = tail + 1;
return pmBufferOverflow;
}
/* queue is has room for message, and overflow flag is cleared */
ptr = &queue->buffer[tail];
dest = ptr + 1;
for (i = 1; i < queue->msg_size; i++) {
int32_t j = src[i - 1];
if (!j) {
*ptr = i;
ptr = dest;
} else {
*dest = j;
}
dest++;
}
*ptr = i;
tail += queue->msg_size;
if (tail == queue->len) tail = 0;
queue->tail = tail;
return pmNoError;
}
PMEXPORT int Pm_QueueEmpty(PmQueue *q)
{
PmQueueRep *queue = (PmQueueRep *) q;
return (!queue) || /* null pointer -> return "empty" */
(queue->buffer[queue->head] == 0 && !queue->peek_flag);
}
PMEXPORT int Pm_QueueFull(PmQueue *q)
{
long tail;
int i;
PmQueueRep *queue = (PmQueueRep *) q;
/* arg checking */
if (!queue)
return pmBadPtr;
tail = queue->tail;
/* test to see if there is space in the queue */
for (i = 0; i < queue->msg_size; i++) {
if (queue->buffer[tail + i]) {
return TRUE;
}
}
return FALSE;
}
PMEXPORT void *Pm_QueuePeek(PmQueue *q)
{
PmError rslt;
int32_t temp;
PmQueueRep *queue = (PmQueueRep *) q;
/* arg checking */
if (!queue)
return NULL;
if (queue->peek_flag) {
return queue->peek;
}
/* this is ugly: if peek_overflow is set, then Pm_Dequeue()
* returns immediately with pmBufferOverflow, but here, we
* want Pm_Dequeue() to really check for data. If data is
* there, we can return it
*/
temp = queue->peek_overflow;
queue->peek_overflow = FALSE;
rslt = Pm_Dequeue(q, queue->peek);
queue->peek_overflow = temp;
if (rslt == 1) {
queue->peek_flag = TRUE;
return queue->peek;
} else if (rslt == pmBufferOverflow) {
/* when overflow is indicated, the queue is empty and the
* first message that was dropped by Enqueue (signalling
* pmBufferOverflow to its caller) would have been the next
* message in the queue. Pm_QueuePeek will return NULL, but
* remember that an overflow occurred. (see Pm_Dequeue)
*/
queue->peek_overflow = TRUE;
}
return NULL;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,129 @@
# MAKEFILE FOR PORTMIDI
# Roger B. Dannenberg
# Sep 2009
# NOTE: you can use
# make -f pm_osx/Makefile.osx configuration=Release
# to override the default Debug configuration
configuration=Release
PF=/usr/local
# For debugging, define PM_CHECK_ERRORS
ifeq ($(configuration),Release)
CONFIG = Release
else
CONFIG = Debug
endif
current: all
all: $(CONFIG)/CMakeCache.txt
cd $(CONFIG); make
$(CONFIG)/CMakeCache.txt:
rm -f CMakeCache.txt
mkdir -p $(CONFIG)
cd $(CONFIG); cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=$(CONFIG)
**** For instructions: make -f pm_mac\Makefile.osx help ****\n'
help:
echo $$'\n\n\
This is help for portmidi/pm_mac/Makefile.osx\n\n\
Installation path for dylib is $(PF)\n\
To build Release version libraries and test applications,\n \
make -f pm_mac/Makefile.osx\n\
To build Debug version libraries and test applications,\n \
make -f pm_mac/Makefile.osx configuration=Debug\n\
To install universal dynamic library,\n \
sudo make -f pm_mac/Makefile.osx install\n\
To install universal dynamic library with xcode,\n \
make -f pm_mac/Makefile.osx install-with-xcode\n\
To make PmDefaults Java application,\n \
make -f pm_mac/Makefile.osx pmdefaults\n\n \
configuration = $(configuration)\n'
clean:
rm -f *.o *~ core* */*.o */*/*.o */*~ */core* pm_test/*/pm_dll.dll
rm -f *.opt *.ncb *.plg pm_win/Debug/pm_dll.lib pm_win/Release/pm_dll.lib
rm -f pm_test/*.opt pm_test/*.ncb
rm -f pm_java/pmjni/*.o pm_java/pmjni/*~ pm_java/*.h
rm -rf Release/CMakeFiles Debug/CMakeFiles
rm -rf pm_mac/pmdefaults/lib pm_mac/pmdefaults/src
cleaner: clean
rm -rf pm_mac/build
rm -rf pm_mac/Debug pm_mac/Release pm_test/Debug pm_test/Release
rm -f Debug/*.dylib Release/*.dylib
rm -f pm_java/pmjni/Debug/*.jnilib
rm -f pm_java/pmjni/Release/*.jnilib
cleanest: cleaner
rm -f Debug/libportmidi_s.a Release/libportmidi_s.a
rm -f pm_test/Debug/test pm_test/Debug/sysex pm_test/Debug/midithread
rm -f pm_test/Debug/latency pm_test/Debug/midithru
rm -f pm_test/Debug/qtest pm_test/Debug/mm
rm -f pm_test/Release/test pm_test/Release/sysex pm_test/Release/midithread
rm -f pm_test/Release/latency pm_test/Release/midithru
rm -f pm_test/Release/qtest pm_test/Release/mm
rm -f pm_java/*/*.class
rm -f pm_java/pmjni/jportmidi_JPortMidiApi_PortMidiStream.h
backup: cleanest
cd ..; zip -r portmidi.zip portmidi
install: porttime/porttime.h pm_common/portmidi.h \
$(CONFIG)/libportmidi.dylib
install porttime/porttime.h $(PF)/include/
install pm_common/portmidi.h $(PF)/include
install $(CONFIG)/libportmidi.dylib $(PF)/lib/
# note - this uses xcode to build and install portmidi universal binaries
install-with-xcode:
sudo xcodebuild -project pm_mac/pm_mac.xcodeproj \
-configuration Release install DSTROOT=/
##### build pmdefault ######
pm_java/pmjni/jportmidi_JPortMidiApi.h: pm_java/jportmidi/JPortMidiApi.class
cd pm_java; javah jportmidi.JPortMidiApi
mv pm_java/jportmidi_JportMidiApi.h pm_java/pmjni
JAVASRC = pmdefaults/PmDefaultsFrame.java \
pmdefaults/PmDefaults.java \
jportmidi/JPortMidiApi.java jportmidi/JPortMidi.java \
jportmidi/JPortMidiException.java
# this compiles ALL of the java code
pm_java/jportmidi/JPortMidiApi.class: $(JAVASRC:%=pm_java/%)
cd pm_java; javac $(JAVASRC)
$(CONFIG)/libpmjni.dylib:
mkdir -p $(CONFIG)
cd $(CONFIG); make -f ../pm_mac/$(MAKEFILE)
pmdefaults: $(CONFIG)/libpmjni.dylib pm_java/jportmidi/JPortMidiApi.class
ifeq ($(CONFIG),Debug)
echo "Error: you cannot build pmdefaults in a Debug configuration \n\
You should use configuration=Release in the Makefile command line. "
@exit 2
endif
xcodebuild -project pm_mac/pm_mac.xcodeproj \
-configuration Release -target PmDefaults
echo "pmdefaults java application is made"
###### test plist reader #######
PLHDR = pm_mac/readbinaryplist.h
PLSRC = pm_mac/plisttest.c pm_mac/readbinaryplist.c
pm_mac/plisttest: $(PLHDR) $(PLSRC)
cc $(VFLAGS) -Ipm_mac \
-I/Developer/Headers/FlatCarbon \
-I/System/Library/Frameworks/CoreFoundation.framework/Headers \
-I/System/Library/Frameworks/CoreServices.framework/Headers \
$(PLSRC) -o pm_mac/$(CONFIG)/plisttest \
-framework CoreFoundation -framework CoreServices

View file

@ -0,0 +1,163 @@
README_MAC.txt for PortMidi
Roger Dannenberg
20 nov 2009
revised 20 Sep 2010 for Xcode 3.2.4 and CMake 8.2-2
To build PortMidi for Mac OS X, you must install Xcode and
CMake.
CMake can build either command-line Makefiles or Xcode projects.
These approaches are described in separate sections below.
==== CLEANING UP ====
(Skip this for now, but later you might want start from a clean
slate.)
Start in the portmedia/portmidi directory.
make -f pm_mac/Makefile.osx clean
will remove .o, CMakeFiles, and other intermediate files.
Using "cleaner" instead of "clean" will also remove jni-related
intermediate files.
Using "cleanest" instead of "clean" or "cleaner" will also remove
application binaries and the portmidi libraries. (It will not
uninstall anything, however.)
==== USING CMAKE (AND COMMAND LINE TOOLS) ====
Start in the portmedia/portmidi directory.
make -f pm_mac/Makefile.osx
(Begin note: make will invoke cmake to build a Makefile and then make to
build portmidi. This extra level allows you to correctly build
both Release and Debug versions. Release is the default, so to get
the Debug version, use:
make -f pm_mac/Makefile.osx configuration=Debug
)
Release version executables and libraries are now in
portmedia/portmidi/Release
Debug version executables and libraries are created in
portmedia/portmidi/Debug
The Debug versions are compiled with PM_CHECK_ERRORS which
prints an error message and aborts when an error code is returned
by PortMidi functions. This is useful for small command line
applications. Otherwise, you should check and handle error returns
in your program.
You can install portmidi as follows:
cd Release; sudo make install
This will install /usr/local/include/{portmidi.h, porttime.h}
and /usr/local/lib/{libportmidi.dylib, libportmidi_s.a, libpmjni.dylib}
You should now make the pmdefaults.app:
make -f pm_mac/Makefile.osx pmdefaults
NOTE: pmdefaults.app will be in pm_mac/Release/.
Please copy pmdefaults.app to your Applications folder or wherever
you would normally expect to find it.
==== USING CMAKE TO BUILD Xcode PROJECT ====
Before you can use Xcode, you need a portmidi.xcodeproj file.
CMake builds a location-dependent Xcode project, so unfortunately
it is not easy to provide an Xcode project that is ready to use.
Therefore, you should make your own. Once you have it, you can
use it almost like any other Xcode project, and you will not have
to go back to CMake.
(1) Install CMake if you do not have it already.
(2) Open portmedia/portmidi/CMakeLists.txt with CMake
(3) Use Configure and Generate buttons
(4) This creates portmedia/portmidi/portmidi.xcodeproj.
Note: You will also use pm_mac/pm_mac.xcodeproj, which
is not generated by CMake.
(5) Open portmidi/portmidi.xcodeproj with Xcode and
build what you need. The simplest thing is to build the
ALL_BUILD target. The default will be to build the Debug
version, but you may want to change this to Release.
NOTE: ALL_BUILD may report errors. Try simply building again
or rebuilding specific targets that fail until they build
without errors. There appears to be a race condition or
missing dependencies in the build system.
The Debug version is compiled with PM_CHECK_ERRORS, and the
Release version is not. PM_CHECK_ERRORS will print an error
message and exit your program if any error is returned from
a call into PortMidi.
CMake (currently) also creates MinSizRel and RelWithDebInfo
versions, but only because I cannot figure out how to disable
them.
You will probably want the application PmDefaults, which sets
default MIDI In and Out devices for PortMidi. You may also
want to build a Java application using PortMidi. Since I have
not figured out how to use CMake to make an OS X Java application,
use pm_mac/pm_mac.xcodeproj as follows:
(6) open pm_mac/pm_mac.xcodeproj
(7) pm_java/pmjni/portmidi_JportmidiApi.h is needed
by libpmjni.jnilib, the Java native interface library. Since
portmidi_JportmidiApi.h is included with PortMidi, you can skip
to step 8, but if you really want to rebuild everything from
scratch, build the JPortMidiHeaders project first, and continue
with step 8:
(8) If you did not build libpmjni.dylib using portmidi.xcodeproj,
do it now. (It depends on portmidi_JportmidiApi.h, and the
PmDefaults project depends on libpmjni.dylib.)
(9) Returning to pm_mac.xcodeproj, build the PmDefaults program.
(10) If you wish, copy pm_mac/build/Deployment/PmDefaults.app to
your applications folder.
(11) If you want to install libportmidi.dylib, first make it with
Xcode, then
sudo make -f pm_mac/Makefile.osx install
This command will install /usr/local/include/{porttime.h, portmidi.h}
and /usr/local/lib/libportmidi.dylib
Note that the "install" function of xcode creates portmidi/Release
and does not install the library to /usr/local/lib, so please use
the command line installer.
CHANGELOG
20-Sep-2010 Roger B. Dannenberg
Adapted to Xcode 3.2.4
20-Nov-2009 Roger B. Dannenberg
Added some install instructions
26-Sep-2009 Roger B. Dannenberg
More changes for using CMake, Makefiles, XCode
20-Sep-2009 Roger B. Dannenberg
Modifications for using CMake
14-Sep-2009 Roger B. Dannenberg
Modifications for using CMake
17-Jan-2007 Roger B. Dannenberg
Explicit instructions for Xcode
15-Jan-2007 Roger B. Dannenberg
Changed instructions because of changes to Makefile.osx
07-Oct-2006 Roger B. Dannenberg
Added directions for xcodebuild
29-aug-2006 Roger B. Dannenberg
Updated this documentation.

View file

@ -0,0 +1,57 @@
/* finddefault.c -- find_default_device() implementation
Roger Dannenberg, June 2008
*/
#include <stdlib.h>
#include <string.h>
#include "portmidi.h"
#include "pmutil.h"
#include "pminternal.h"
#include "pmmacosxcm.h"
#include "readbinaryplist.h"
/* Parse preference files, find default device, search devices --
This parses the preference file(s) once for input and once for
output, which is inefficient but much simpler to manage. Note
that using the readbinaryplist.c module, you cannot keep two
plist files (user and system) open at once (due to a simple
memory management scheme).
*/
PmDeviceID find_default_device(char *path, int input, PmDeviceID id)
/* path -- the name of the preference we are searching for
input -- true iff this is an input device
id -- current default device id
returns matching device id if found, otherwise id
*/
{
static char *pref_file = "com.apple.java.util.prefs.plist";
char *pref_str = NULL;
// read device preferences
value_ptr prefs = bplist_read_user_pref(pref_file);
if (prefs) {
value_ptr pref_val = value_dict_lookup_using_path(prefs, path);
if (pref_val) {
pref_str = value_get_asciistring(pref_val);
}
}
if (!pref_str) {
bplist_free_data(); /* look elsewhere */
prefs = bplist_read_system_pref(pref_file);
if (prefs) {
value_ptr pref_val = value_dict_lookup_using_path(prefs, path);
if (pref_val) {
pref_str = value_get_asciistring(pref_val);
}
}
}
if (pref_str) { /* search devices for match */
int i = pm_find_default_device(pref_str, input);
if (i != pmNoDevice) {
id = i;
}
}
if (prefs) {
bplist_free_data();
}
return id;
}

View file

@ -0,0 +1,594 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 44;
objects = {
/* Begin PBXAggregateTarget section */
3D634CAB1247805C0020F829 /* JPortMidiHeaders */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 3D634CAE1247807A0020F829 /* Build configuration list for PBXAggregateTarget "JPortMidiHeaders" */;
buildPhases = (
3D634CAA1247805C0020F829 /* ShellScript */,
);
dependencies = (
3D634CB0124781580020F829 /* PBXTargetDependency */,
);
name = JPortMidiHeaders;
productName = JPortMidiHeaders;
};
3DE2142D124662AA0033C839 /* CopyJavaSources */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 3DE21434124662FF0033C839 /* Build configuration list for PBXAggregateTarget "CopyJavaSources" */;
buildPhases = (
3DE2142C124662AA0033C839 /* CopyFiles */,
);
comments = "The reason for copying files here is that the Compile Java target looks in a particular place for sources. It would be much better to simply have Compile Java look in the original location for all sources, but I don't know how to do that. -RBD\n";
dependencies = (
);
name = CopyJavaSources;
productName = CopyJavaSources;
};
89D0F1C90F3B704E007831A7 /* PmDefaults */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 89D0F1D20F3B7080007831A7 /* Build configuration list for PBXAggregateTarget "PmDefaults" */;
buildPhases = (
);
dependencies = (
89D0F1D10F3B7062007831A7 /* PBXTargetDependency */,
89D0F1CD0F3B7062007831A7 /* PBXTargetDependency */,
3DE21431124662C50033C839 /* PBXTargetDependency */,
);
name = PmDefaults;
productName = pmdefaults;
};
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
3DE2137F124653FB0033C839 /* portmusic_logo.png in Resources */ = {isa = PBXBuildFile; fileRef = 3DE2137E124653FB0033C839 /* portmusic_logo.png */; };
3DE21435124663860033C839 /* PmDefaultsFrame.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE2137D124653CB0033C839 /* PmDefaultsFrame.java */; };
3DE214361246638A0033C839 /* PmDefaults.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE2137B1246538B0033C839 /* PmDefaults.java */; };
3DE214371246638F0033C839 /* JPortMidiException.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE21382124654DE0033C839 /* JPortMidiException.java */; };
3DE214381246638F0033C839 /* JPortMidiApi.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE21381124654CF0033C839 /* JPortMidiApi.java */; };
3DE214391246638F0033C839 /* JPortMidi.java in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DE21380124654BC0033C839 /* JPortMidi.java */; };
3DE216131246AC0E0033C839 /* libpmjni.dylib in Copy Java Resources */ = {isa = PBXBuildFile; fileRef = 3DE216101246ABE30033C839 /* libpmjni.dylib */; };
3DE216951246D57A0033C839 /* pmdefaults.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3DE216901246C6410033C839 /* pmdefaults.icns */; };
89C3F2920F5250A300B0048E /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 89C3F2900F5250A300B0048E /* Credits.rtf */; };
89D0F0240F392F20007831A7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 89D0F0210F392F20007831A7 /* InfoPlist.strings */; };
89D0F0410F39306C007831A7 /* JavaApplicationStub in Copy Executable */ = {isa = PBXBuildFile; fileRef = 89D0F03E0F39304A007831A7 /* JavaApplicationStub */; };
89D0F16A0F3A124E007831A7 /* pmdefaults.jar in Copy Java Resources */ = {isa = PBXBuildFile; fileRef = 89D0F15D0F3A0FF7007831A7 /* pmdefaults.jar */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
3D634CAF124781580020F829 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
proxyType = 1;
remoteGlobalIDString = 89D0F1C90F3B704E007831A7;
remoteInfo = PmDefaults;
};
3DE21430124662C50033C839 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
proxyType = 1;
remoteGlobalIDString = 3DE2142D124662AA0033C839;
remoteInfo = CopyJavaSources;
};
3DE2145D124666900033C839 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
proxyType = 1;
remoteGlobalIDString = 3DE2142D124662AA0033C839;
remoteInfo = CopyJavaSources;
};
89D0F1CC0F3B7062007831A7 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
proxyType = 1;
remoteGlobalIDString = 8D1107260486CEB800E47090;
remoteInfo = "Assemble Application";
};
89D0F1D00F3B7062007831A7 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
proxyType = 1;
remoteGlobalIDString = 89D0F0480F393A6F007831A7;
remoteInfo = "Compile Java";
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
3DE2142C124662AA0033C839 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "${PROJECT_DIR}/pmdefaults/src/java";
dstSubfolderSpec = 0;
files = (
3DE21435124663860033C839 /* PmDefaultsFrame.java in CopyFiles */,
3DE214361246638A0033C839 /* PmDefaults.java in CopyFiles */,
3DE214371246638F0033C839 /* JPortMidiException.java in CopyFiles */,
3DE214381246638F0033C839 /* JPortMidiApi.java in CopyFiles */,
3DE214391246638F0033C839 /* JPortMidi.java in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
89D0F0440F393070007831A7 /* Copy Executable */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 6;
files = (
89D0F0410F39306C007831A7 /* JavaApplicationStub in Copy Executable */,
);
name = "Copy Executable";
runOnlyForDeploymentPostprocessing = 0;
};
89D0F11F0F394189007831A7 /* Copy Java Resources */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 15;
files = (
89D0F16A0F3A124E007831A7 /* pmdefaults.jar in Copy Java Resources */,
3DE216131246AC0E0033C839 /* libpmjni.dylib in Copy Java Resources */,
);
name = "Copy Java Resources";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
3DE2137B1246538B0033C839 /* PmDefaults.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = PmDefaults.java; path = ../pm_java/pmdefaults/PmDefaults.java; sourceTree = SOURCE_ROOT; };
3DE2137D124653CB0033C839 /* PmDefaultsFrame.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = PmDefaultsFrame.java; path = ../pm_java/pmdefaults/PmDefaultsFrame.java; sourceTree = SOURCE_ROOT; };
3DE2137E124653FB0033C839 /* portmusic_logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = portmusic_logo.png; path = ../pm_java/pmdefaults/portmusic_logo.png; sourceTree = SOURCE_ROOT; };
3DE21380124654BC0033C839 /* JPortMidi.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = JPortMidi.java; path = ../pm_java/jportmidi/JPortMidi.java; sourceTree = SOURCE_ROOT; };
3DE21381124654CF0033C839 /* JPortMidiApi.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = JPortMidiApi.java; path = ../pm_java/jportmidi/JPortMidiApi.java; sourceTree = SOURCE_ROOT; };
3DE21382124654DE0033C839 /* JPortMidiException.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = JPortMidiException.java; path = ../pm_java/jportmidi/JPortMidiException.java; sourceTree = SOURCE_ROOT; };
3DE213841246555A0033C839 /* CoreMIDI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = /System/Library/Frameworks/CoreMIDI.framework; sourceTree = "<absolute>"; };
3DE21390124655760033C839 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
3DE213BE1246557F0033C839 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = "<absolute>"; };
3DE216101246ABE30033C839 /* libpmjni.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpmjni.dylib; path = ../Release/libpmjni.dylib; sourceTree = SOURCE_ROOT; };
3DE216901246C6410033C839 /* pmdefaults.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = pmdefaults.icns; path = ../pm_java/pmdefaults/pmdefaults.icns; sourceTree = SOURCE_ROOT; };
89C3F2910F5250A300B0048E /* English */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = English; path = English.lproj/Credits.rtf; sourceTree = "<group>"; };
89D0F0220F392F20007831A7 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
89D0F0230F392F20007831A7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
89D0F03E0F39304A007831A7 /* JavaApplicationStub */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = JavaApplicationStub; path = /System/Library/Frameworks/JavaVM.framework/Versions/A/Resources/MacOS/JavaApplicationStub; sourceTree = "<absolute>"; };
89D0F0840F394066007831A7 /* JavaNativeFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaNativeFoundation.framework; path = /System/Library/Frameworks/JavaVM.framework/Versions/A/Frameworks/JavaNativeFoundation.framework; sourceTree = "<absolute>"; };
89D0F1390F3948A9007831A7 /* pmdefaults/make */ = {isa = PBXFileReference; lastKnownFileType = folder; path = pmdefaults/make; sourceTree = "<group>"; };
89D0F15D0F3A0FF7007831A7 /* pmdefaults.jar */ = {isa = PBXFileReference; lastKnownFileType = archive.jar; name = pmdefaults.jar; path = build/Release/pmdefaults.jar; sourceTree = SOURCE_ROOT; };
89D0F1860F3A2442007831A7 /* JavaVM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaVM.framework; path = /System/Library/Frameworks/JavaVM.framework; sourceTree = "<absolute>"; };
8D1107320486CEB800E47090 /* PmDefaults.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PmDefaults.app; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXGroup section */
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
isa = PBXGroup;
children = (
3DE213841246555A0033C839 /* CoreMIDI.framework */,
3DE21390124655760033C839 /* CoreFoundation.framework */,
3DE213BE1246557F0033C839 /* CoreAudio.framework */,
89D0F1860F3A2442007831A7 /* JavaVM.framework */,
89D0F0840F394066007831A7 /* JavaNativeFoundation.framework */,
);
name = "Linked Frameworks";
sourceTree = "<group>";
};
1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
isa = PBXGroup;
children = (
);
name = "Other Frameworks";
sourceTree = "<group>";
};
19C28FACFE9D520D11CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
89D0F15D0F3A0FF7007831A7 /* pmdefaults.jar */,
8D1107320486CEB800E47090 /* PmDefaults.app */,
);
name = Products;
sourceTree = "<group>";
};
29B97314FDCFA39411CA2CEA /* pmdefaults */ = {
isa = PBXGroup;
children = (
3DE216101246ABE30033C839 /* libpmjni.dylib */,
89D0F0260F392F48007831A7 /* Source */,
89D0F0200F392F20007831A7 /* Resources */,
89D0F1390F3948A9007831A7 /* pmdefaults/make */,
29B97323FDCFA39411CA2CEA /* Frameworks */,
19C28FACFE9D520D11CA2CBB /* Products */,
);
name = pmdefaults;
sourceTree = "<group>";
};
29B97323FDCFA39411CA2CEA /* Frameworks */ = {
isa = PBXGroup;
children = (
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
);
name = Frameworks;
sourceTree = "<group>";
};
3DE2136A124652E20033C839 /* pm_java */ = {
isa = PBXGroup;
children = (
3DE21379124653150033C839 /* pmdefaults */,
3DE2137A1246531D0033C839 /* jportmidi */,
);
name = pm_java;
path = ..;
sourceTree = "<group>";
};
3DE21379124653150033C839 /* pmdefaults */ = {
isa = PBXGroup;
children = (
3DE2137D124653CB0033C839 /* PmDefaultsFrame.java */,
3DE2137B1246538B0033C839 /* PmDefaults.java */,
);
name = pmdefaults;
sourceTree = "<group>";
};
3DE2137A1246531D0033C839 /* jportmidi */ = {
isa = PBXGroup;
children = (
3DE21382124654DE0033C839 /* JPortMidiException.java */,
3DE21381124654CF0033C839 /* JPortMidiApi.java */,
3DE21380124654BC0033C839 /* JPortMidi.java */,
);
name = jportmidi;
sourceTree = "<group>";
};
89D0F0200F392F20007831A7 /* Resources */ = {
isa = PBXGroup;
children = (
3DE216901246C6410033C839 /* pmdefaults.icns */,
3DE2137E124653FB0033C839 /* portmusic_logo.png */,
89C3F2900F5250A300B0048E /* Credits.rtf */,
89D0F0230F392F20007831A7 /* Info.plist */,
89D0F0210F392F20007831A7 /* InfoPlist.strings */,
89D0F03E0F39304A007831A7 /* JavaApplicationStub */,
);
name = Resources;
path = pmdefaults/resources;
sourceTree = "<group>";
};
89D0F0260F392F48007831A7 /* Source */ = {
isa = PBXGroup;
children = (
3DE2136A124652E20033C839 /* pm_java */,
);
name = Source;
path = pmdefaults/src;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXLegacyTarget section */
89D0F0480F393A6F007831A7 /* Compile Java */ = {
isa = PBXLegacyTarget;
buildArgumentsString = "-e -f \"${SRCROOT}/make/build.xml\" -debug \"$ACTION\"";
buildConfigurationList = 89D0F04B0F393AB7007831A7 /* Build configuration list for PBXLegacyTarget "Compile Java" */;
buildPhases = (
);
buildToolPath = /usr/bin/ant;
buildWorkingDirectory = "";
dependencies = (
3DE2145E124666900033C839 /* PBXTargetDependency */,
);
name = "Compile Java";
passBuildSettingsInEnvironment = 1;
productName = "Compile Java";
};
/* End PBXLegacyTarget section */
/* Begin PBXNativeTarget section */
8D1107260486CEB800E47090 /* Assemble Application */ = {
isa = PBXNativeTarget;
buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Assemble Application" */;
buildPhases = (
89D0F0440F393070007831A7 /* Copy Executable */,
89D0F11F0F394189007831A7 /* Copy Java Resources */,
8D1107290486CEB800E47090 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "Assemble Application";
productInstallPath = "$(HOME)/Applications";
productName = pmdefaults;
productReference = 8D1107320486CEB800E47090 /* PmDefaults.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "pm_mac" */;
compatibilityVersion = "Xcode 3.0";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
English,
Japanese,
French,
German,
);
mainGroup = 29B97314FDCFA39411CA2CEA /* pmdefaults */;
projectDirPath = "";
projectRoot = "";
targets = (
3D634CAB1247805C0020F829 /* JPortMidiHeaders */,
89D0F1C90F3B704E007831A7 /* PmDefaults */,
3DE2142D124662AA0033C839 /* CopyJavaSources */,
89D0F0480F393A6F007831A7 /* Compile Java */,
8D1107260486CEB800E47090 /* Assemble Application */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
8D1107290486CEB800E47090 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3DE216951246D57A0033C839 /* pmdefaults.icns in Resources */,
89D0F0240F392F20007831A7 /* InfoPlist.strings in Resources */,
89C3F2920F5250A300B0048E /* Credits.rtf in Resources */,
3DE2137F124653FB0033C839 /* portmusic_logo.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3D634CAA1247805C0020F829 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo BUILT_PRODUCTS_DIR is ${BUILT_PRODUCTS_DIR}\njavah -classpath \"${BUILT_PRODUCTS_DIR}/pmdefaults.jar\" -force -o \"${BUILT_PRODUCTS_DIR}/jportmidi_JportMidiApi.h\" \"jportmidi.JPortMidiApi\"\nmv \"${BUILT_PRODUCTS_DIR}/jportmidi_JportMidiApi.h\" ../pm_java/pmjni/\necho \"Created ../pm_java/pmjni/jportmidi_JportMidiApi.h\"\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXTargetDependency section */
3D634CB0124781580020F829 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 89D0F1C90F3B704E007831A7 /* PmDefaults */;
targetProxy = 3D634CAF124781580020F829 /* PBXContainerItemProxy */;
};
3DE21431124662C50033C839 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 3DE2142D124662AA0033C839 /* CopyJavaSources */;
targetProxy = 3DE21430124662C50033C839 /* PBXContainerItemProxy */;
};
3DE2145E124666900033C839 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 3DE2142D124662AA0033C839 /* CopyJavaSources */;
targetProxy = 3DE2145D124666900033C839 /* PBXContainerItemProxy */;
};
89D0F1CD0F3B7062007831A7 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 8D1107260486CEB800E47090 /* Assemble Application */;
targetProxy = 89D0F1CC0F3B7062007831A7 /* PBXContainerItemProxy */;
};
89D0F1D10F3B7062007831A7 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 89D0F0480F393A6F007831A7 /* Compile Java */;
targetProxy = 89D0F1D00F3B7062007831A7 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
89C3F2900F5250A300B0048E /* Credits.rtf */ = {
isa = PBXVariantGroup;
children = (
89C3F2910F5250A300B0048E /* English */,
);
name = Credits.rtf;
sourceTree = "<group>";
};
89D0F0210F392F20007831A7 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
89D0F0220F392F20007831A7 /* English */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
3D634CAC1247805C0020F829 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
PRODUCT_NAME = JPortMidiHeaders;
};
name = Debug;
};
3D634CAD1247805C0020F829 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_FIX_AND_CONTINUE = NO;
PRODUCT_NAME = JPortMidiHeaders;
ZERO_LINK = NO;
};
name = Release;
};
3DE2142E124662AB0033C839 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
PRODUCT_NAME = CopyJavaSources;
};
name = Debug;
};
3DE2142F124662AB0033C839 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_FIX_AND_CONTINUE = NO;
PRODUCT_NAME = CopyJavaSources;
ZERO_LINK = NO;
};
name = Release;
};
89D0F0490F393A6F007831A7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = pmdefaults;
SRCROOT = ./pmdefaults;
};
name = Debug;
};
89D0F04A0F393A6F007831A7 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = pmdefaults;
SRCROOT = ./pmdefaults;
};
name = Release;
};
89D0F1CA0F3B704F007831A7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = pmdefaults;
};
name = Debug;
};
89D0F1CB0F3B704F007831A7 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = pmdefaults;
};
name = Release;
};
C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CONFIGURATION_BUILD_DIR = "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)";
COPY_PHASE_STRIP = NO;
INFOPLIST_FILE = pmdefaults/resources/Info.plist;
INSTALL_PATH = "$(HOME)/Applications";
PRODUCT_NAME = pmdefaults;
WRAPPER_EXTENSION = app;
};
name = Debug;
};
C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CONFIGURATION_BUILD_DIR = "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
INFOPLIST_FILE = pmdefaults/resources/Info.plist;
INSTALL_PATH = "$(HOME)/Applications";
PRODUCT_NAME = PmDefaults;
WRAPPER_EXTENSION = app;
};
name = Release;
};
C01FCF4F08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)";
ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;
};
name = Debug;
};
C01FCF5008A954540054247B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)";
ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
3D634CAE1247807A0020F829 /* Build configuration list for PBXAggregateTarget "JPortMidiHeaders" */ = {
isa = XCConfigurationList;
buildConfigurations = (
3D634CAC1247805C0020F829 /* Debug */,
3D634CAD1247805C0020F829 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
3DE21434124662FF0033C839 /* Build configuration list for PBXAggregateTarget "CopyJavaSources" */ = {
isa = XCConfigurationList;
buildConfigurations = (
3DE2142E124662AB0033C839 /* Debug */,
3DE2142F124662AB0033C839 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
89D0F04B0F393AB7007831A7 /* Build configuration list for PBXLegacyTarget "Compile Java" */ = {
isa = XCConfigurationList;
buildConfigurations = (
89D0F0490F393A6F007831A7 /* Debug */,
89D0F04A0F393A6F007831A7 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
89D0F1D20F3B7080007831A7 /* Build configuration list for PBXAggregateTarget "PmDefaults" */ = {
isa = XCConfigurationList;
buildConfigurations = (
89D0F1CA0F3B704F007831A7 /* Debug */,
89D0F1CB0F3B704F007831A7 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Assemble Application" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C01FCF4B08A954540054247B /* Debug */,
C01FCF4C08A954540054247B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C01FCF4E08A954540054247B /* Build configuration list for PBXProject "pm_mac" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C01FCF4F08A954540054247B /* Debug */,
C01FCF5008A954540054247B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:pm_mac.xcodeproj">
</FileRef>
</Workspace>

View file

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0460"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8D1107260486CEB800E47090"
BuildableName = "PmDefaults.app"
BlueprintName = "Assemble Application"
ReferencedContainer = "container:pm_mac.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8D1107260486CEB800E47090"
BuildableName = "PmDefaults.app"
BlueprintName = "Assemble Application"
ReferencedContainer = "container:pm_mac.xcodeproj">
</BuildableReference>
</MacroExpansion>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8D1107260486CEB800E47090"
BuildableName = "PmDefaults.app"
BlueprintName = "Assemble Application"
ReferencedContainer = "container:pm_mac.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8D1107260486CEB800E47090"
BuildableName = "PmDefaults.app"
BlueprintName = "Assemble Application"
ReferencedContainer = "container:pm_mac.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0460"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "89D0F0480F393A6F007831A7"
BuildableName = "Compile Java"
BlueprintName = "Compile Java"
ReferencedContainer = "container:pm_mac.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
</Testables>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0460"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "3DE2142D124662AA0033C839"
BuildableName = "CopyJavaSources"
BlueprintName = "CopyJavaSources"
ReferencedContainer = "container:pm_mac.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
</Testables>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0460"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "3D634CAB1247805C0020F829"
BuildableName = "JPortMidiHeaders"
BlueprintName = "JPortMidiHeaders"
ReferencedContainer = "container:pm_mac.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
</Testables>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0460"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "89D0F1C90F3B704E007831A7"
BuildableName = "PmDefaults"
BlueprintName = "PmDefaults"
ReferencedContainer = "container:pm_mac.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
</Testables>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>Assemble Application.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>4</integer>
</dict>
<key>Compile Java.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
</dict>
<key>CopyJavaSources.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
</dict>
<key>JPortMidiHeaders.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
<key>PmDefaults.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>3D634CAB1247805C0020F829</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>3DE2142D124662AA0033C839</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>89D0F0480F393A6F007831A7</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>89D0F1C90F3B704E007831A7</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>8D1107260486CEB800E47090</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="pmdefaults" default="jar" basedir="..">
<!-- Global Properties -->
<property environment="env"/>
<!-- building in Xcode -->
<condition property="product" value="${env.PRODUCT_NAME}">
<isset property="env.PRODUCT_NAME"/>
</condition>
<condition property="src" value="${env.SRCROOT}/src">
<isset property="env.SRCROOT"/>
</condition>
<condition property="obj" value="${env.OBJECT_FILE_DIR}">
<isset property="env.OBJECT_FILE_DIR"/>
</condition>
<condition property="dst" value="${env.BUILT_PRODUCTS_DIR}">
<isset property="env.BUILT_PRODUCTS_DIR"/>
</condition>
<!-- building from the command line -->
<condition property="src" value="src">
<not>
<isset property="src"/>
</not>
</condition>
<condition property="obj" value="build/obj">
<not>
<isset property="obj"/>
</not>
</condition>
<condition property="dst" value="build">
<not>
<isset property="dst"/>
</not>
</condition>
<condition property="product" value="pmdefaults">
<not>
<isset property="product"/>
</not>
</condition>
<!-- Targets -->
<target name="init" description="Create build directories">
<mkdir dir="${obj}/${product}"/>
<mkdir dir="${dst}"/>
</target>
<target name="compile" depends="init" description="Compile">
<javac destdir="${obj}/${product}" deprecation="on" source="1.5" target="1.5" fork="true" debug="true" debuglevel="lines,source">
<src path="${src}/java"/>
<classpath path="${src}/../lib/eawt-stubs.jar"/>
</javac>
</target>
<target name="copy" depends="init" description="Copy resources">
</target>
<target name="jar" depends="compile, copy" description="Assemble Jar file">
<jar jarfile="${dst}/${product}.jar" basedir="${obj}/${product}" manifest="resources/Manifest" index="true"/>
</target>
<target name="install" depends="jar" description="Alias for 'jar'">
<!-- sent by Xcode -->
</target>
<target name="clean" description="Removes build directories">
<!-- sent by Xcode -->
<delete dir="${obj}/${product}"/>
<delete file="${dst}/${product}.jar"/>
</target>
<target name="installhdrs" description="">
<!-- sent by Xcode -->
<echo>"Nothing to do for install-headers phase"</echo>
</target>
</project>

View file

@ -0,0 +1,31 @@
#!/bin/sh
# Prints all class references made by all classes in a Jar file
# Depends on the output formatting of javap
# create a temporary working directory
dir=`mktemp -d $TMPDIR/classrefs.XXXXXX`
asm_dump="$dir/asm_dump"
all_classes="$dir/all_classes"
# for each class in a Jar file, dump the full assembly
javap -c -classpath "$1" `/usr/bin/jar tf "$1" | grep "\.class" | sort | xargs | sed -e 's/\.class//g'` > $asm_dump
# dump the initial list of all classes in the Jar file
/usr/bin/jar tf $1 | grep "\.class" | sed -e 's/\.class//g' >> $all_classes
# dump all static class references
cat $asm_dump | grep //class | awk -F"//class " '{print $2}' | sort | uniq >> $all_classes
# dump all references to classes made in methods
cat $asm_dump | grep //Method | awk -F"//Method " '{print $2}' | sort | uniq | grep "\." | awk -F"." '{print $1}' | sort | uniq >> $all_classes
# dump all references to classes by direct field access
cat $asm_dump | grep //Field | awk -F"//Field " '{print $2}' | sort | uniq | grep "\:L" | awk -F"\:L" '{print $2}' | sort | uniq | awk -F"\;" '{print $1}' >> $all_classes
# sort and reformat
sort $all_classes | uniq | grep -v "\"" | sed -e 's/\//\./g'
# cleanup
rm -rf $dir

View file

@ -0,0 +1,14 @@
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf320
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
\f0\b\fs24 \cf0 Author:
\b0 \
Roger B. Dannenberg\
\
\b With special thanks to:
\b0 \
National Science Foundation\
}

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>JavaApplicationStub</string>
<key>CFBundleIconFile</key>
<string>pmdefaults.icns</string>
<key>CFBundleIdentifier</key>
<string></string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>PmDefaults</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>Java</key>
<dict>
<key>ClassPath</key>
<string>$JAVAROOT/pmdefaults.jar</string>
<key>JVMVersion</key>
<string>1.5+</string>
<key>MainClass</key>
<string>pmdefaults.PmDefaults</string>
<key>Properties</key>
<dict>
<key>apple.laf.useScreenMenuBar</key>
<string>true</string>
</dict>
</dict>
</dict>
</plist>

View file

@ -0,0 +1 @@
Main-Class: pmdefaults/PmDefaults

View file

@ -0,0 +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); }

View file

@ -0,0 +1,4 @@
/* pmmac.h */
extern PmDeviceID pm_default_input_device_id;
extern PmDeviceID pm_default_output_device_id;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +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);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,88 @@
/* readbinaryplist.h -- header to read preference files
Roger B. Dannenberg, Jun 2008
*/
#include <stdint.h> /* for uint8_t ... */
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define MAX_KEY_SIZE 256
enum
{
// Object tags (high nybble)
kTAG_SIMPLE = 0x00, // Null, true, false, filler, or invalid
kTAG_INT = 0x10,
kTAG_REAL = 0x20,
kTAG_DATE = 0x30,
kTAG_DATA = 0x40,
kTAG_ASCIISTRING = 0x50,
kTAG_UNICODESTRING = 0x60,
kTAG_UID = 0x80,
kTAG_ARRAY = 0xA0,
kTAG_DICTIONARY = 0xD0,
// "simple" object values
kVALUE_NULL = 0x00,
kVALUE_FALSE = 0x08,
kVALUE_TRUE = 0x09,
kVALUE_FILLER = 0x0F,
kVALUE_FULLDATETAG = 0x33 // Dates are tagged with a whole byte.
};
typedef struct pldata_struct {
uint8_t *data;
size_t len;
} pldata_node, *pldata_ptr;
typedef struct array_struct {
struct value_struct **array;
uint64_t length;
} array_node, *array_ptr;
// a dict_node is a list of <key, value> pairs
typedef struct dict_struct {
struct value_struct *key;
struct value_struct *value;
struct dict_struct *next;
} dict_node, *dict_ptr;
// an value_node is a value with a tag telling the type
typedef struct value_struct {
int tag;
union {
int64_t integer;
uint64_t uinteger;
double real;
char *string;
pldata_ptr data;
array_ptr array;
struct dict_struct *dict;
};
} value_node, *value_ptr;
value_ptr bplist_read_file(char *filename);
value_ptr bplist_read_user_pref(char *filename);
value_ptr bplist_read_system_pref(char *filename);
void bplist_free_data();
/*************** functions for accessing values ****************/
char *value_get_asciistring(value_ptr v);
value_ptr value_dict_lookup_using_string(value_ptr v, char *key);
value_ptr value_dict_lookup_using_path(value_ptr v, char *path);
/*************** functions for debugging ***************/
void plist_print(value_ptr v);

View file

@ -0,0 +1,143 @@
/* pmwin.c -- PortMidi os-dependent code */
/* This file only needs to implement:
pm_init(), which calls various routines to register the
available midi devices,
Pm_GetDefaultInputDeviceID(), and
Pm_GetDefaultOutputDeviceID().
This file must
be separate from the main portmidi.c file because it is system
dependent, and it is separate from, say, pmwinmm.c, because it
might need to register devices for winmm, directx, and others.
*/
#include "stdlib.h"
#include "portmidi.h"
#include "pmutil.h"
#include "pminternal.h"
#include "pmwinmm.h"
#ifdef DEBUG
#include "stdio.h"
#endif
#include <windows.h>
/* pm_exit is called when the program exits.
It calls pm_term to make sure PortMidi is properly closed.
If DEBUG is on, we prompt for input to avoid losing error messages.
*/
static void pm_exit(void) {
pm_term();
#ifdef DEBUG
#define STRING_MAX 80
{
char line[STRING_MAX];
printf("Type ENTER...\n");
/* note, w/o this prompting, client console application can not see one
of its errors before closing. */
fgets(line, STRING_MAX, stdin);
}
#endif
}
/* pm_init is the windows-dependent initialization.*/
void pm_init(void)
{
atexit(pm_exit);
#ifdef DEBUG
printf("registered pm_exit with atexit()\n");
#endif
pm_winmm_init();
/* initialize other APIs (DirectX?) here */
}
void pm_term(void) {
pm_winmm_term();
}
static PmDeviceID pm_get_default_device_id(int is_input, char *key) {
HKEY hkey;
#define PATTERN_MAX 256
char pattern[PATTERN_MAX];
long pattern_max = PATTERN_MAX;
DWORD dwType;
/* Find first input or device -- this is the default. */
PmDeviceID id = pmNoDevice;
int i, j;
Pm_Initialize(); /* make sure descriptors exist! */
for (i = 0; i < pm_descriptor_index; i++) {
if (descriptors[i].pub.input == is_input) {
id = i;
break;
}
}
/* Look in registry for a default device name pattern. */
if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &hkey) !=
ERROR_SUCCESS) {
return id;
}
if (RegOpenKeyEx(hkey, "JavaSoft", 0, KEY_READ, &hkey) !=
ERROR_SUCCESS) {
return id;
}
if (RegOpenKeyEx(hkey, "Prefs", 0, KEY_READ, &hkey) !=
ERROR_SUCCESS) {
return id;
}
if (RegOpenKeyEx(hkey, "/Port/Midi", 0, KEY_READ, &hkey) !=
ERROR_SUCCESS) {
return id;
}
if (RegQueryValueEx(hkey, key, NULL, &dwType, pattern, &pattern_max) !=
ERROR_SUCCESS) {
return id;
}
/* decode pattern: upper case encoded with "/" prefix */
i = j = 0;
while (pattern[i]) {
if (pattern[i] == '/' && pattern[i + 1]) {
pattern[j++] = toupper(pattern[++i]);
} else {
pattern[j++] = tolower(pattern[i]);
}
i++;
}
pattern[j] = 0; /* end of string */
/* now pattern is the string from the registry; search for match */
i = pm_find_default_device(pattern, is_input);
if (i != pmNoDevice) {
id = i;
}
return id;
}
PmDeviceID Pm_GetDefaultInputDeviceID() {
return pm_get_default_device_id(TRUE,
"/P/M_/R/E/C/O/M/M/E/N/D/E/D_/I/N/P/U/T_/D/E/V/I/C/E");
}
PmDeviceID Pm_GetDefaultOutputDeviceID() {
return pm_get_default_device_id(FALSE,
"/P/M_/R/E/C/O/M/M/E/N/D/E/D_/O/U/T/P/U/T_/D/E/V/I/C/E");
}
#include "stdio.h"
void *pm_alloc(size_t s) {
return malloc(s);
}
void pm_free(void *ptr) {
free(ptr);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,5 @@
/* midiwin32.h -- system-specific definitions */
void pm_winmm_init( void );
void pm_winmm_term( void );

View file

@ -0,0 +1,131 @@
/* ptmacosx.c -- portable timer implementation for mac os x */
#include <stdlib.h>
#include <stdio.h>
#include <CoreAudio/HostTime.h>
#import <mach/mach.h>
#import <mach/mach_error.h>
#import <mach/mach_time.h>
#import <mach/clock.h>
#include <unistd.h>
#include "porttime.h"
#include "sys/time.h"
#include "pthread.h"
#define NSEC_PER_MSEC 1000000
#define THREAD_IMPORTANCE 30
static int time_started_flag = FALSE;
static UInt64 start_time;
static pthread_t pt_thread_pid;
/* note that this is static data -- we only need one copy */
typedef struct {
int id;
int resolution;
PtCallback *callback;
void *userData;
} pt_callback_parameters;
static int pt_callback_proc_id = 0;
static void *Pt_CallbackProc(void *p)
{
pt_callback_parameters *parameters = (pt_callback_parameters *) p;
int mytime = 1;
kern_return_t error;
thread_extended_policy_data_t extendedPolicy;
thread_precedence_policy_data_t precedencePolicy;
extendedPolicy.timeshare = 0;
error = thread_policy_set(mach_thread_self(), THREAD_EXTENDED_POLICY,
(thread_policy_t)&extendedPolicy,
THREAD_EXTENDED_POLICY_COUNT);
if (error != KERN_SUCCESS) {
mach_error("Couldn't set thread timeshare policy", error);
}
precedencePolicy.importance = THREAD_IMPORTANCE;
error = thread_policy_set(mach_thread_self(), THREAD_PRECEDENCE_POLICY,
(thread_policy_t)&precedencePolicy,
THREAD_PRECEDENCE_POLICY_COUNT);
if (error != KERN_SUCCESS) {
mach_error("Couldn't set thread precedence policy", error);
}
/* to kill a process, just increment the pt_callback_proc_id */
/* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id, parameters->id); */
while (pt_callback_proc_id == parameters->id) {
/* wait for a multiple of resolution ms */
UInt64 wait_time;
int delay = mytime++ * parameters->resolution - Pt_Time();
PtTimestamp timestamp;
if (delay < 0) delay = 0;
wait_time = AudioConvertNanosToHostTime((UInt64)delay * NSEC_PER_MSEC);
wait_time += AudioGetCurrentHostTime();
error = mach_wait_until(wait_time);
timestamp = Pt_Time();
(*(parameters->callback))(timestamp, parameters->userData);
}
free(parameters);
return NULL;
}
PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
{
if (time_started_flag) return ptAlreadyStarted;
start_time = AudioGetCurrentHostTime();
if (callback) {
int res;
pt_callback_parameters *parms;
parms = (pt_callback_parameters *) malloc(sizeof(pt_callback_parameters));
if (!parms) return ptInsufficientMemory;
parms->id = pt_callback_proc_id;
parms->resolution = resolution;
parms->callback = callback;
parms->userData = userData;
res = pthread_create(&pt_thread_pid, NULL, Pt_CallbackProc, parms);
if (res != 0) return ptHostError;
}
time_started_flag = TRUE;
return ptNoError;
}
PtError Pt_Stop()
{
/* printf("Pt_Stop called\n"); */
pt_callback_proc_id++;
pthread_join(pt_thread_pid, NULL);
time_started_flag = FALSE;
return ptNoError;
}
int Pt_Started()
{
return time_started_flag;
}
PtTimestamp Pt_Time()
{
UInt64 clock_time, nsec_time;
clock_time = AudioGetCurrentHostTime() - start_time;
nsec_time = AudioConvertHostTimeToNanos(clock_time);
return (PtTimestamp)(nsec_time / NSEC_PER_MSEC);
}
void Pt_Sleep(int32_t duration)
{
usleep(duration * 1000);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,379 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __libardour_waves_audiobackend_h__
#define __libardour_waves_audiobackend_h__
#include <string>
#include <vector>
#include <list>
#include <stdint.h>
#include <stdlib.h>
#include <boost/function.hpp>
#include "ardour/types.h"
#include "ardour/audio_backend.h"
#include "waves_midi_device_manager.h"
#ifdef __MACOS__
#include <WCMRCoreAudioDeviceManager.h>
class ArdourAudioDeviceManager : public WCMRCoreAudioDeviceManager
{
public:
ArdourAudioDeviceManager (WCMRAudioDeviceManagerClient *client) : WCMRCoreAudioDeviceManager (client, eFullDuplexDevices, true, eCABS_Simple, false) {};
};
#elif defined (_WINDOWS)
#include <WCMRPortAudioDeviceManager.h>
class ArdourAudioDeviceManager : public WCMRPortAudioDeviceManager
{
public:
ArdourAudioDeviceManager (WCMRAudioDeviceManagerClient *client) : WCMRPortAudioDeviceManager (client, eFullDuplexDevices, paASIO) {};
};
#endif
namespace ARDOUR {
class AudioEngine;
class PortEngine;
class PortManager;
class WavesAudioBackend;
class WavesDataPort;
class WavesAudioPort;
class WavesMidiPort;
class WavesAudioBackend : public AudioBackend, WCMRAudioDeviceManagerClient
{
public:
WavesAudioBackend (AudioEngine& e);
virtual ~WavesAudioBackend ();
/* AUDIOBACKEND API */
virtual std::string name () const;
virtual bool is_realtime () const;
virtual bool requires_driver_selection () const;
virtual std::vector<std::string> enumerate_drivers () const;
virtual int set_driver (const std::string& /*drivername*/);
virtual std::vector<DeviceStatus> enumerate_devices () const;
virtual std::vector<float> available_sample_rates (const std::string& device) const;
virtual float default_sample_rate () const;
virtual std::vector<uint32_t> available_buffer_sizes (const std::string& device) const;
virtual uint32_t available_input_channel_count (const std::string& device) const;
virtual uint32_t available_output_channel_count (const std::string& device) const;
virtual bool can_change_sample_rate_when_running () const;
virtual bool can_change_buffer_size_when_running () const;
virtual int set_device_name (const std::string& name);
virtual int set_sample_rate (float);
virtual int set_buffer_size (uint32_t);
virtual int set_sample_format (SampleFormat);
virtual int set_interleaved (bool yn);
virtual int set_input_channels (uint32_t);
virtual int set_output_channels (uint32_t);
virtual int set_systemic_input_latency (uint32_t);
virtual int set_systemic_output_latency (uint32_t);
virtual std::string device_name () const;
virtual float sample_rate () const;
virtual uint32_t buffer_size () const;
virtual SampleFormat sample_format () const;
virtual bool interleaved () const;
virtual uint32_t input_channels () const;
virtual uint32_t output_channels () const;
virtual uint32_t systemic_input_latency () const;
virtual uint32_t systemic_output_latency () const;
virtual std::string control_app_name () const;
virtual void launch_control_app ();
virtual std::vector<std::string> enumerate_midi_options () const;
virtual int set_midi_option (const std::string& option);
virtual std::string midi_option () const;
virtual int _start (bool for_latency_measurement);
virtual int stop ();
virtual int freewheel (bool start_stop);
virtual float dsp_load () const ;
virtual void transport_start ();
virtual void transport_stop ();
virtual TransportState transport_state () const;
virtual void transport_locate (framepos_t pos);
virtual framepos_t transport_frame () const;
virtual int set_time_master (bool yn);
virtual int usecs_per_cycle () const;
virtual size_t raw_buffer_size (DataType data_type);
virtual pframes_t sample_time ();
virtual pframes_t sample_time_at_cycle_start ();
virtual pframes_t samples_since_cycle_start ();
virtual bool get_sync_offset (pframes_t& offset) const;
virtual int create_process_thread (boost::function<void ()> func);
virtual int join_process_threads ();
virtual bool in_process_thread ();
virtual uint32_t process_thread_count ();
virtual void update_latencies ();
virtual bool speed_and_position (double& speed, framepos_t& position) {
speed = 0.0;
position = 0;
return false;
}
/* PORTENGINE API */
virtual void* private_handle () const;
virtual const std::string& my_name () const;
virtual bool available () const;
virtual uint32_t port_name_size () const;
virtual int set_port_name (PortHandle port_handle, const std::string& port_name);
virtual std::string get_port_name (PortHandle port_handle ) const;
virtual PortHandle get_port_by_name (const std::string& port_name) const;
virtual int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>& port_handles) const;
virtual DataType port_data_type (PortHandle port_handle) const;
virtual PortHandle register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags);
virtual void unregister_port (PortHandle port_handle);
virtual int connect (const std::string& src, const std::string& dst);
virtual int disconnect (const std::string& src, const std::string& dst);
virtual int connect (PortHandle port_handle, const std::string& port_name);
virtual int disconnect (PortHandle port_handle, const std::string& port_name);
virtual int disconnect_all (PortHandle port_handle);
virtual bool connected (PortHandle port_handle, bool process_callback_safe);
virtual bool connected_to (PortHandle port_handle, const std::string& port_name, bool process_callback_safe);
virtual bool physically_connected (PortHandle port_handle, bool process_callback_safe);
virtual int get_connections (PortHandle port_handle, std::vector<std::string>&, bool process_callback_safe);
virtual int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index);
virtual int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size);
virtual uint32_t get_midi_event_count (void* port_buffer);
virtual void midi_clear (void* port_buffer);
virtual bool can_monitor_input () const;
virtual int request_input_monitoring (PortHandle port_handle, bool);
virtual int ensure_input_monitoring (PortHandle port_handle, bool);
virtual bool monitoring_input (PortHandle port_handle);
virtual void set_latency_range (PortHandle port_handle, bool for_playback, LatencyRange);
virtual LatencyRange get_latency_range (PortHandle port_handle, bool for_playback);
virtual bool port_is_physical (PortHandle port_handle) const;
virtual void get_physical_outputs (DataType type, std::vector<std::string>& port_names);
virtual void get_physical_inputs (DataType type, std::vector<std::string>& port_names);
virtual ChanCount n_physical_outputs () const;
virtual ChanCount n_physical_inputs () const;
virtual void* get_buffer (PortHandle port_handle, pframes_t frames);
static AudioBackendInfo& backend_info () { return __backend_info; }
virtual void AudioDeviceManagerNotification (NotificationReason reason, void* pParam);
private:
//ArdourAudioDeviceManagerClient _audio_device_manager_client;
ArdourAudioDeviceManager _audio_device_manager;
WavesMidiDeviceManager _midi_device_manager;
WCMRAudioDevice *_device;
SampleFormat _sample_format;
bool _interleaved;
static std::string __instantiated_name;
uint32_t _input_channels;
uint32_t _max_input_channels;
uint32_t _output_channels;
uint32_t _max_output_channels;
float _sample_rate;
uint32_t _buffer_size;
uint32_t _systemic_input_latency;
uint32_t _systemic_output_latency;
bool _call_thread_init_callback;
std::vector<pthread_t> _backend_threads;
static const size_t __max_raw_midi_buffer_size;
static const std::vector<std::string> __available_midi_options;
bool _use_midi;
struct ThreadData {
WavesAudioBackend* engine;
boost::function<void ()> f;
size_t stacksize;
ThreadData (WavesAudioBackend* e, boost::function<void ()> fp, size_t stacksz)
: engine (e) , f (fp) , stacksize (stacksz) {}
};
static boost::shared_ptr<AudioBackend> __waves_backend_factory (AudioEngine& e);
static int __instantiate (const std::string& arg1, const std::string& arg2);
static int __deinstantiate ();
static bool __already_configured ();
static void* __start_process_thread (void*);
static uint64_t __get_time_nanos ();
static size_t __thread_stack_size ();
void _audio_device_callback (const float* input_audio_buffer,
float* output_buffer,
unsigned long nframes,
pframes_t sample_time,
uint64_t cycle_start_time_nanos);
void _changed_midi_devices ();
int _register_system_audio_ports ();
int _register_system_midi_ports ();
int _read_midi_data_from_devices ();
int _write_midi_data_to_devices (pframes_t);
pframes_t _ms_to_sample_time (int32_t time_ms) const;
int32_t _sample_time_to_ms (pframes_t sample_time) const ;
void _read_audio_data_from_device (const float* input_buffer, pframes_t nframes);
void _write_audio_data_to_device (float* output_buffer, pframes_t nframes);
void _unregister_system_audio_ports ();
void _unregister_system_midi_ports ();
WavesDataPort* _register_port (const std::string& port_name, ARDOUR::DataType type, ARDOUR::PortFlags flags);
inline bool _registered (PortHandle port_handle) const
{
return std::find (_ports.begin (), _ports.end (), (WavesDataPort*)port_handle) != _ports.end ();
}
WavesDataPort* _find_port (const std::string& port_name) const;
void _freewheel_thread ();
std::vector<WavesAudioPort*> _physical_audio_inputs;
std::vector<WavesAudioPort*> _physical_audio_outputs;
std::vector<WavesMidiPort*> _physical_midi_inputs;
std::vector<WavesMidiPort*> _physical_midi_outputs;
std::vector<WavesDataPort*> _ports;
static AudioBackendInfo __backend_info;
#if defined (_WINDOWS)
static uint64_t __performance_counter_frequency;
#endif
uint64_t _cycle_start_time_nanos;
pframes_t _sample_time_at_cycle_start;
bool _freewheeling;
bool _freewheel_thread_active;
friend class WavesMidiDeviceManager;
std::list<uint64_t> _dsp_load_history;
size_t _dsp_load_history_length;
uint64_t _dsp_load_accumulator;
float _audio_cycle_period_nanos;
void _init_dsp_load_history();
};
} // namespace
#endif /* __libardour_waves_audiobackend_h__ */

View file

@ -0,0 +1,90 @@
/*
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);
}

View file

@ -0,0 +1,354 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <boost/assign/list_of.hpp>
#include "waves_audiobackend.h"
#include "waves_midiport.h"
#include "waves_midi_event.h"
#include "waves_midi_buffer.h"
using namespace ARDOUR;
#ifdef __MACOS__
const std::vector<std::string> WavesAudioBackend::__available_midi_options = boost::assign::list_of ("None") ("CoreMIDI");
#elif _WINDOWS
const std::vector<std::string> WavesAudioBackend::__available_midi_options = boost::assign::list_of ("None") ("Multimedia Extensions");
#endif
std::vector<std::string>
WavesAudioBackend::enumerate_midi_options () const
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::enumerate_midi_options ()" << std::endl;
return __available_midi_options;
}
int
WavesAudioBackend::set_midi_option (const std::string& option)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_midi_option ( " << option << " )" << std::endl;
if (option == __available_midi_options[0]) {
_use_midi = false;
// COMMENTED DBG LOGS */ std::cout << "\tNO MIDI system used)" << std::endl;
}
else if (option == __available_midi_options[1]) {
_use_midi = true;
// COMMENTED DBG LOGS */ std::cout << "\tNO MIDI system used)" << std::endl;
}
else {
std::cerr << "WavesAudioBackend::set_midi_option (): Invalid MIDI option!" << std::endl;
return -1;
}
return 0;
}
std::string
WavesAudioBackend::midi_option () const
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::midi_option ():" << std::endl;
return * (__available_midi_options.begin () + (_use_midi?1:0));
}
int
WavesAudioBackend::midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buffer, void* port_buffer, uint32_t event_index)
{
// COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::midi_event_get ():" << std::endl;
if (buffer == NULL) {
std::cerr << "WavesAudioBackend::midi_event_get () : NULL in the 'buffer' argument!\n";
return -1;
}
if (port_buffer == NULL) {
std::cerr << "WavesAudioBackend::midi_event_get () : NULL in the 'port_buffer' argument!\n";
return -1;
}
WavesMidiBuffer& source = * (WavesMidiBuffer*)port_buffer;
if (event_index >= source.size ()) {
std::cerr << "WavesAudioBackend::midi_event_get () : 'event_index' is out of the number of events stored in 'port_buffer'!\n";
return -1;
}
WavesMidiEvent* waves_midi_event = source[event_index];
timestamp = waves_midi_event->timestamp ();
size = waves_midi_event->size ();
*buffer = waves_midi_event->data ();
return 0;
}
int
WavesAudioBackend::midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size)
{
// COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::midi_event_put ():" << std::endl;
if (buffer == NULL) {
std::cerr << "WavesAudioBackend::midi_event_put () : NULL in the 'buffer' argument!\n";
return -1;
}
if (port_buffer == NULL) {
std::cerr << "WavesAudioBackend::midi_event_put () : NULL in the 'port_buffer' argument!\n";
return -1;
}
WavesMidiBuffer& target = * (WavesMidiBuffer*)port_buffer;
// COMMENTED FREQUENT DBG LOGS */ std::cout << "\t [" << target.name () << "]"<< std::endl;
if (target.size () && (pframes_t)target.back ()->timestamp () > timestamp) {
std::cerr << "WavesAudioBackend::midi_event_put (): The MIDI Event to put is a bit late!" << std::endl;
std::cerr << "\tprev timestamp is " << (pframes_t)target.back ()->timestamp () << " as the current one is " << timestamp << std::endl;
return -1;
}
target.push_back (new WavesMidiEvent (timestamp, buffer, size));
return 0;
}
uint32_t
WavesAudioBackend::get_midi_event_count (void* port_buffer)
{
// COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::get_midi_event_count (): " << std::endl;
if (port_buffer == NULL) {
std::cerr << "WavesAudioBackend::get_midi_event_count () : NULL in the 'port_buffer' argument!\n";
return -1;
}
// COMMENTED FREQUENT DBG LOGS */ std::cout << "\tcount = " << (* (WavesMidiBuffer*)port_buffer).size () << std::endl;
return (* (WavesMidiBuffer*)port_buffer).size ();
}
void
WavesAudioBackend::midi_clear (void* port_buffer)
{
// COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::midi_clear (): " << std::endl;
if (port_buffer == NULL) {
std::cerr << "WavesAudioBackend::midi_clear () : NULL in the 'port_buffer' argument!\n";
return;
}
(* (WavesMidiBuffer*)port_buffer).clear ();
}
void
WavesAudioBackend::_changed_midi_devices ()
{
if (_midi_device_manager.stream (false)) {
std::cerr << "WavesAudioBackend::_changed_midi_devices (): _midi_device_manager.stream (false) failed!" << std::endl;
return;
}
_midi_device_manager.stop ();
if (_midi_device_manager.start () != 0) {
std::cerr << "WavesAudioBackend::_changed_midi_devices (): _midi_device_manager.start () failed!" << std::endl;
return;
}
if (_register_system_midi_ports () != 0) {
std::cerr << "WavesAudioBackend::_changed_midi_devices (): _register_system_midi_ports () failed!" << std::endl;
return;
}
manager.registration_callback ();
if (_midi_device_manager.stream (true)) {
std::cerr << "WavesAudioBackend::_changed_midi_devices (): _midi_device_manager.stream (true) failed!" << std::endl;
return;
}
}
void
WavesAudioBackend::_unregister_system_midi_ports ()
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::_unregister_system_midi_ports ()" << std::endl;
std::vector<WavesMidiPort*> physical_midi_ports = _physical_midi_inputs;
physical_midi_ports.insert (physical_midi_ports.begin (), _physical_midi_outputs.begin (), _physical_midi_outputs.end ());
for (std::vector<WavesMidiPort*>::const_iterator it = physical_midi_ports.begin (); it != physical_midi_ports.end (); ++it) {
std::vector<WavesDataPort*>::iterator port_iterator = std::find (_ports.begin (), _ports.end (), *it);
if (port_iterator == _ports.end ()) {
std::cerr << "WavesAudioBackend::_unregister_system_midi_ports (): Failed to find port [" << (*it)->name () << "]!" << std::endl;
}
else
_ports.erase (port_iterator);
delete *it;
}
_physical_midi_inputs.clear ();
_physical_midi_outputs.clear ();
}
int
WavesAudioBackend::_register_system_midi_ports ()
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::_register_system_midi_ports ()" << std::endl;
LatencyRange lr = {0,0};
lr.min = lr.max = _buffer_size;
for (size_t i = 0; i<_ports.size ();) {
WavesMidiPort* midi_port = dynamic_cast<WavesMidiPort*> (_ports[i]);
if (!midi_port || !midi_port->is_physical () || !midi_port->is_terminal ()) {
++i;
continue;
}
if ((midi_port->is_input () && !midi_port->midi_device ()->is_output ()) ||
(midi_port->is_output () && !midi_port->midi_device ()->is_input ())) {
disconnect_all (midi_port);
unregister_port (midi_port);
continue; // to be here for further additions in the end of this loop
}
++i;
}
const std::vector<WavesMidiDevice *>& devices = _midi_device_manager.devices ();
for (std::vector<WavesMidiDevice*>::const_iterator it = devices.begin (); it != devices.end (); ++it) {
if ((*it)->is_input ()) {
std::string port_name = "system_midi:" + (*it)->name () + " capture";
WavesDataPort* port = _find_port (port_name);
WavesMidiPort* midi_port = dynamic_cast<WavesMidiPort*> (port);
if (midi_port && (midi_port->type () != DataType::MIDI ||
midi_port->midi_device () != *it ||
!midi_port->is_output () ||
!midi_port->is_physical () ||
!midi_port->is_terminal ())) {
std::cerr << "WavesAudioBackend::_register_system_midi_ports (): the port [" << midi_port->name () << "] is inconsystently constructed!" << std::endl;
disconnect_all (midi_port);
unregister_port (midi_port);
port = NULL;
}
if (port == NULL) {
port = _register_port ( port_name, DataType::MIDI , static_cast<ARDOUR::PortFlags> (IsOutput | IsPhysical | IsTerminal));
if (port == NULL) {
return -1;
}
((WavesMidiPort*)port)->set_midi_device (*it);
}
port->set_latency_range (lr, false);
}
if ((*it)->is_output ()) {
std::string port_name = "system_midi:" + (*it)->name () + " playback";
WavesDataPort* port = _find_port (port_name);
WavesMidiPort* midi_port = dynamic_cast<WavesMidiPort*> (port);
if (midi_port && (midi_port->type () != DataType::MIDI ||
midi_port->midi_device () != *it ||
!midi_port->is_input () ||
!midi_port->is_physical () ||
!midi_port->is_terminal ())) {
std::cerr << "WavesAudioBackend::_register_system_midi_ports (): the port [" << midi_port->name () << "] is inconsystently constructed!" << std::endl;
disconnect_all (midi_port);
unregister_port (midi_port);
}
if (port == NULL) {
port = _register_port (port_name,
DataType::MIDI,
static_cast<ARDOUR::PortFlags> (IsInput | IsPhysical | IsTerminal));
if (port == NULL) {
return -1;
}
}
((WavesMidiPort*)port)->set_midi_device ((*it));
port->set_latency_range (lr, true);
}
}
return 0;
}
int
WavesAudioBackend::_read_midi_data_from_devices ()
{
// COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::_read_midi_data_from_devices ():" << std::endl;
if (!_midi_device_manager.is_streaming ())
return 0;
_midi_device_manager.do_read ();
for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_inputs.begin (); it != _physical_midi_inputs.end (); ++it) {
WavesMidiDevice* midi_device = (*it)->midi_device ();
WavesMidiBuffer& waves_midi_buffer = (*it)->buffer ();
waves_midi_buffer.clear ();
while (WavesMidiEvent *waves_midi_event = midi_device->dequeue_input_waves_midi_event ()) {
int32_t timestamp_st = _buffer_size - (_sample_time_at_cycle_start - waves_midi_event->timestamp ());
if (timestamp_st < 0) {
timestamp_st = 0;
}
else if (timestamp_st >= (int32_t)_buffer_size) {
timestamp_st = _buffer_size - 1;
}
waves_midi_event->set_timestamp (timestamp_st);
waves_midi_buffer.push_back (waves_midi_event);
}
}
return 0;
}
int
WavesAudioBackend::_write_midi_data_to_devices (pframes_t nframes)
{
if (!_midi_device_manager.is_streaming ())
return 0;
for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_outputs.begin (); it != _physical_midi_outputs.end (); ++it) {
WavesMidiDevice* midi_device = (*it)->midi_device ();
WavesMidiBuffer &waves_midi_buffer = * (WavesMidiBuffer*) (*it)->get_buffer (nframes);
for (WavesMidiBufferIterator it = waves_midi_buffer.begin (); it != waves_midi_buffer.end ();) {
WavesMidiEvent* waves_midi_event = *it;
waves_midi_buffer.erase (it);
waves_midi_event->set_timestamp (_sample_time_at_cycle_start + waves_midi_event->timestamp () + nframes);
midi_device->enqueue_output_waves_midi_event (waves_midi_event);
}
}
_midi_device_manager.do_write ();
return 0;
}

View file

@ -0,0 +1,654 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "waves_audiobackend.h"
#include "waves_audioport.h"
#include "waves_midiport.h"
#include "waves_midi_event.h"
using namespace ARDOUR;
uint32_t
WavesAudioBackend::port_name_size () const
{
return 256+64;
}
int
WavesAudioBackend::set_port_name (PortHandle port_handle, const std::string& port_name)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_port_name (): [" << std::hex << port_handle << std::dec << "], [" << port_name << "]" << std::endl;
if (!_registered (port_handle)) {
std::cerr << "WavesAudioBackend::set_port_name (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
return -1;
}
return ((WavesAudioPort*)port_handle)->set_name (__instantiated_name + ":" + port_name);
}
std::string
WavesAudioBackend::get_port_name (PortHandle port_handle) const
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::get_port_name (): [" << std::hex << port_handle << std::dec << "]" << std::endl;
if (!_registered (port_handle)) {
std::cerr << "WavesAudioBackend::get_port_name (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
return std::string ();
}
// COMMENTED DBG LOGS */ else std::cout << "\t[" << ((WavesAudioPort*)port_handle)->name () << "]" << std::endl;
return ((WavesAudioPort*)port_handle)->name ();
}
PortEngine::PortHandle
WavesAudioBackend::get_port_by_name (const std::string& port_name) const
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::get_port_by_name (): [" << port_name << "]" << std::endl;
PortHandle port_handle = (PortHandle)_find_port (port_name);
if (!port_handle) {
std::cerr << "WavesAudioBackend::get_port_by_name (): Failed to find port [" << port_name << "]!" << std::endl;
}
return port_handle;
}
WavesDataPort*
WavesAudioBackend::_find_port (const std::string& port_name) const
{
for (std::vector<WavesDataPort*>::const_iterator it = _ports.begin (); it != _ports.end (); ++it) {
if ((*it)->name () == port_name) {
return *it;
}
}
return NULL;
}
int
WavesAudioBackend::get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>& port_names) const
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::get_ports (): \n\tPattern: [" << port_name_pattern << "]\n\tType: " << type << "\n\tFlags: " << flags << endl;
unsigned found_ports =0;
for (size_t i = 0; i < _ports.size (); ++i) {
WavesDataPort* port = _ports[i];
if ((port->type () == type) && (port->flags () & flags)) {
port_names.push_back (port->name ());
found_ports++;
}
}
return found_ports;
}
DataType
WavesAudioBackend::port_data_type (PortHandle port_handle) const
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::port_data_type" << std::endl;
if (!_registered (port_handle)) {
std::cerr << "WavesAudioBackend::port_data_type (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
return DataType::NIL;
}
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::port_data_type: " << endl;
return ((WavesAudioPort*)port_handle)->type ();
}
PortEngine::PortHandle
WavesAudioBackend::register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::register_port (): " << type.to_string () << " [" << shortname << "]" << std::endl;
if (shortname.size () == 0) {
std::cerr << "WavesAudioBackend::register_port (): Invalid (empty) port name!" << std::endl;
return NULL;
}
if (flags & IsPhysical) {
std::cerr << "WavesAudioBackend::register_port (): Unexpected attribute for port [" << shortname << "]! The port must not be physical!";
return NULL;
}
return (PortEngine::PortHandle)_register_port (__instantiated_name + ":" + shortname, type, flags);
}
WavesDataPort*
WavesAudioBackend::_register_port (const std::string& port_name, ARDOUR::DataType type, ARDOUR::PortFlags flags)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::_register_port (): [" << port_name << "]" << std::endl;
if (_find_port (port_name) != NULL) {
std::cerr << "WavesAudioBackend::register_port () : Port [" << port_name << "] is already registered!" << std::endl;
return NULL;
}
WavesDataPort* port = NULL;
switch (type) {
case ARDOUR::DataType::AUDIO: {
WavesAudioPort* audio_port = new WavesAudioPort (port_name, flags);
if (flags & IsPhysical)
{
if (flags & IsOutput)
{
_physical_audio_inputs.push_back (audio_port);
// COMMENTED DBG LOGS */ std::cout << "\t\t" << port_name << " added to physical AUDIO Inputs !" << std::endl;
}
else if (flags & IsInput)
{
_physical_audio_outputs.push_back (audio_port);
// COMMENTED DBG LOGS */ std::cout << "\t\t" << port_name << " added to physical AUDIO Outputs !" << std::endl;
}
}
port = audio_port;
} break;
case ARDOUR::DataType::MIDI: {
WavesMidiPort* midi_port = new WavesMidiPort (port_name, flags);
if (flags & IsPhysical)
{
if (flags & IsOutput)
{
_physical_midi_inputs.push_back (midi_port);
// COMMENTED DBG LOGS */ std::cout << "\t\t" << port_name << " added to physical MIDI Inputs !" << std::endl;
}
else if (flags & IsInput)
{
_physical_midi_outputs.push_back (midi_port);
// COMMENTED DBG LOGS */ std::cout << "\t\t" << port_name << " added to physical MIDI Outputs !" << std::endl;
}
}
port = midi_port;
} break;
default:
std::cerr << "WavesAudioBackend::register_port () : Invalid data type (" << (uint32_t)type << ") applied to port [" << port_name << "]!" << std::endl;
return NULL;
}
_ports.push_back (port);
return port;
}
void
WavesAudioBackend::unregister_port (PortHandle port_handle)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::unregister_port ():" << std::hex << port_handle << std::dec << std::endl;
// so far we suppose all disconnections will be done prior to unregistering.
WavesDataPort* port = (WavesDataPort*)port_handle;
std::vector<WavesDataPort*>::iterator port_iterator = std::find (_ports.begin (), _ports.end (), (WavesDataPort*)port_handle);
if (port_iterator == _ports.end ()) {
std::cerr << "WavesAudioBackend::unregister_port (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
return;
}
// COMMENTED DBG LOGS */ std::cout << "\t[" << ((WavesDataPort*)port_handle)->name () << "]" << std::endl;
_ports.erase (port_iterator);
if (port->is_physical ()) {
if (port->is_output ()) {
switch (port->type ()) {
case ARDOUR::DataType::AUDIO: {
std::vector<WavesAudioPort*>::iterator audio_port_iterator = std::find (_physical_audio_inputs.begin (), _physical_audio_inputs.end (), port);
if (audio_port_iterator == _physical_audio_inputs.end ()) {
std::cerr << "WavesAudioBackend::unregister_port (): Failed to find port [" << port->name () << "] in the list of registered physical audio inputs!" << std::endl;
return;
}
_physical_audio_inputs.erase (audio_port_iterator);
}
break;
case ARDOUR::DataType::MIDI: {
std::vector<WavesMidiPort*>::iterator midi_port_iterator = std::find (_physical_midi_inputs.begin (), _physical_midi_inputs.end (), port);
if (midi_port_iterator == _physical_midi_inputs.end ()) {
std::cerr << "WavesAudioBackend::unregister_port (): Failed to find port [" << port->name () << "] in the list of registered physical midi inputs!" << std::endl;
return;
}
_physical_midi_inputs.erase (midi_port_iterator);
}
break;
default:
std::cerr << "WavesAudioBackend::unregister_port (): Invalid type (" << port->type () << " applied to [" << port->name () << "]!" << std::endl;
break;
}
}
else if (port->flags () & IsInput) {
switch (port->type ()) {
case ARDOUR::DataType::AUDIO: {
std::vector<WavesAudioPort*>::iterator audio_port_iterator = std::find (_physical_audio_outputs.begin (), _physical_audio_outputs.end (), port);
if (audio_port_iterator == _physical_audio_outputs.end ())
{
std::cerr << "WavesAudioBackend::unregister_port: Failed to find port [" << port->name () << std::dec << "] in the list of registered physical audio outputs!\n";
return;
}
_physical_audio_outputs.erase (audio_port_iterator);
}
break;
case ARDOUR::DataType::MIDI: {
std::vector<WavesMidiPort*>::iterator midi_port_iterator = std::find (_physical_midi_outputs.begin (), _physical_midi_outputs.end (), port);
if (midi_port_iterator == _physical_midi_outputs.end ())
{
std::cerr << "WavesAudioBackend::unregister_port: Failed to find port [" << port->name () << std::dec << "] in the list of registered physical midi outputs!\n";
return;
}
_physical_midi_outputs.erase (midi_port_iterator);
}
break;
default:
std::cerr << "WavesAudioBackend::unregister_port (): Invalid type (" << port->type () << " applied to [" << port->name () << "]!" << std::endl;
break;
}
}
}
delete port;
}
int
WavesAudioBackend::connect (const std::string& src_port_name, const std::string& dst_port_name)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::connect (" << src_port_name << ", " << dst_port_name << "):" << std::endl;
WavesDataPort* src_port = _find_port (src_port_name);
if (src_port == NULL) {
std::cerr << "WavesAudioBackend::connect: Failed to find source port " << src_port_name << " !" << std::endl;
return -1;
}
WavesDataPort* dst_port = _find_port (dst_port_name);
if (dst_port == NULL) {
std::cerr << "WavesAudioBackend::connect: Failed to find destination port " << dst_port_name << " !" << std::endl;
return -1;
}
// COMMENTED DBG LOGS */ std::cout << "\t\t (" << src_port << ", " << dst_port << "):" << std::endl;
return src_port->connect (dst_port);
}
int
WavesAudioBackend::connect (PortHandle src_port_handle, const std::string& dst_port_name)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::connect ():" << std::endl;
if (!_registered (src_port_handle)) {
std::cerr << "WavesAudioBackend::connect: Failed to find source port [" << std::hex << src_port_handle << std::dec << "]!" << std::endl;
return -1;
}
// COMMENTED DBG LOGS */ std::cout << "\t[" << std::hex << src_port_handle << std::dec << "]" << std::endl;
// COMMENTED DBG LOGS */ std::cout << "\t[" << dst_port_name << "]" << std::endl;
WavesDataPort* dst_port = _find_port (dst_port_name);
if (dst_port == NULL) {
std::cerr << "WavesAudioBackend::connect (): Failed to find destination port [" << dst_port_name << "]!" << std::endl;
return -1;
}
return ((WavesDataPort*)src_port_handle)->connect (dst_port);
}
int
WavesAudioBackend::disconnect (PortHandle src_port_handle, const std::string& dst_port_name)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::disconnect (" << src_port_handle << ", " << dst_port_name << "):" << std::endl;
if (!_registered (src_port_handle)) {
std::cerr << "WavesAudioBackend::disconnect (): Failed to find source port [" << std::hex << src_port_handle << std::dec << "]!" << std::endl;
return -1;
}
// COMMENTED DBG LOGS */ std::cout << "\t[" << std::hex << src_port_handle << std::dec << "]" << std::endl;
// COMMENTED DBG LOGS */ std::cout << "\t[" << dst_port_name << "]" << std::endl;
WavesDataPort* dst_port = _find_port (dst_port_name);
if (dst_port == NULL) {
std::cerr << "WavesAudioBackend::disconnect (): Failed to find destination port [" << dst_port_name << "]!" << std::endl;
return -1;
}
return ((WavesDataPort*)src_port_handle)->disconnect (dst_port);
}
int
WavesAudioBackend::disconnect_all (PortHandle port_handle)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::disconnect_all ():" << std::endl;
if (!_registered (port_handle)) {
std::cerr << "WavesAudioBackend::disconnect_all : Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
return -1;
}
((WavesDataPort*)port_handle)->disconnect_all ();
return 0;
}
int
WavesAudioBackend::disconnect (const std::string& src_port_name, const std::string& dst_port_name)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::disconnect (" << src_port_name << ", " << dst_port_name << "):" << std::endl;
WavesDataPort* src_port = _find_port (src_port_name);
if (src_port == NULL) {
std::cerr << "WavesAudioBackend::disconnect : Failed to find source port!\n";
return -1;
}
WavesDataPort* dst_port = _find_port (dst_port_name);
if (dst_port == NULL) {
std::cerr << "WavesAudioBackend::disconnect : Failed to find destination port!\n";
return -1;
}
return dst_port->disconnect (src_port);
}
bool
WavesAudioBackend::connected (PortHandle port_handle, bool process_callback_safe)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::connected ():" << std::endl;
if (!_registered (port_handle)) {
std::cerr << "WavesAudioBackend::connected (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
return false;
}
return ((WavesDataPort*)port_handle)->is_connected ();
}
bool
WavesAudioBackend::connected_to (PortHandle src_port_handle, const std::string& dst_port_name, bool process_callback_safe)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::connected_to (" << src_port_handle << ", " << dst_port_name << ")" << std::endl;
if (!_registered (src_port_handle)) {
std::cerr << "WavesAudioBackend::connected_to : Failed to find source port!" << std::endl;
return false;
}
WavesDataPort* dst_port = _find_port (dst_port_name);
if (dst_port == NULL) {
std::cerr << "WavesAudioBackend::connected_to : Failed to find destination port!" << std::endl;
return -1;
}
// COMMENTED DBG LOGS */ std::cout << "\t return " << ((((WavesDataPort*)src_port_handle)->is_connected (dst_port)) ? "YES":"NO") << ", " << dst_port_name << ")" << std::endl;
return ((WavesDataPort*)src_port_handle)->is_connected (dst_port);
}
bool
WavesAudioBackend::physically_connected (PortHandle port_handle, bool process_callback_safe)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::physically_connected ():" << std::endl;
if (!_registered (port_handle)) {
std::cerr << "WavesAudioBackend::physically_connected (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
return false;
}
return ((WavesDataPort*)port_handle)->is_physically_connected ();
}
int
WavesAudioBackend::get_connections (PortHandle port_handle, std::vector<std::string>& names, bool process_callback_safe)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::get_connections ()" << std::endl;
if (!_registered (port_handle)) {
std::cerr << "WavesAudioBackend::get_connections (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
return -1;
}
if (names.size ()) {
std::cerr << "WavesAudioBackend::get_connections () : Parameter 'names' is not empty!\n";
return -1;
}
const std::vector<WavesDataPort*>& connected_ports = ((WavesDataPort*)port_handle)->get_connections ();
for (std::vector<WavesDataPort*>::const_iterator it = connected_ports.begin (); it != connected_ports.end (); ++it) {
names.push_back ((*it)->name ());
}
return (int)names.size ();
}
int
WavesAudioBackend::request_input_monitoring (PortHandle, bool)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::request_input_monitoring: " << std::endl;
return 0;
}
int
WavesAudioBackend::ensure_input_monitoring (PortHandle, bool)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::ensure_input_monitoring: " << std::endl;
return 0;
}
bool
WavesAudioBackend::monitoring_input (PortHandle)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::monitoring_input: " << std::endl;
return false;
}
bool
WavesAudioBackend::port_is_physical (PortHandle port_handle) const
{
if (!_registered (port_handle)) {
std::cerr << "WavesAudioBackend::port_is_physical (): Failed to find port [" << std::hex << port_handle << std::dec << "]!" << std::endl;
return -1;
}
return (((WavesAudioPort*)port_handle)->flags () & IsPhysical) != 0;
}
void
WavesAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>& names)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::get_physical_outputs ():" << std::endl << "\tdatatype = " << type << std::endl;
switch (type) {
case ARDOUR::DataType::AUDIO: {
for (std::vector<WavesAudioPort*>::iterator it = _physical_audio_outputs.begin (); it != _physical_audio_outputs.end (); ++it) {
// COMMENTED DBG LOGS */ std::cout << "\t" << (*it)->name () << std::endl;
names.push_back ((*it)->name ());
}
} break;
case ARDOUR::DataType::MIDI: {
for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_outputs.begin (); it != _physical_midi_outputs.end (); ++it) {
// COMMENTED DBG LOGS */ std::cout << "\t" << (*it)->name () << std::endl;
names.push_back ((*it)->name ());
}
} break;
default:
break;
}
}
void
WavesAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>& names)
{
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::get_physical_inputs ():" << std::endl << "\tdatatype = " << type << std::endl;
switch (type) {
case ARDOUR::DataType::AUDIO: {
for (std::vector<WavesAudioPort*>::iterator it = _physical_audio_inputs.begin (); it != _physical_audio_inputs.end (); ++it) {
// COMMENTED DBG LOGS */ std::cout << "\t" << (*it)->name () << std::endl;
names.push_back ((*it)->name ());
}
} break;
case ARDOUR::DataType::MIDI: {
for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_inputs.begin (); it != _physical_midi_inputs.end (); ++it) {
// COMMENTED DBG LOGS */ std::cout << "\t" << (*it)->name () << std::endl;
names.push_back ((*it)->name ());
}
} break;
default:
break;
}
}
ChanCount
WavesAudioBackend::n_physical_outputs () const
{
ChanCount chan_count;
chan_count.set (DataType::AUDIO, _physical_audio_outputs.size ());
chan_count.set (DataType::MIDI, _physical_midi_outputs.size ());
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::n_physical_outputs ():" << std::endl << "\ttotal = " << chan_count.n_total () << std::endl;
return chan_count;
}
ChanCount
WavesAudioBackend::n_physical_inputs () const
{
ChanCount chan_count;
chan_count.set (DataType::AUDIO, _physical_audio_inputs.size ());
chan_count.set (DataType::MIDI, _physical_midi_inputs.size ());
// COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::n_physical_outputs ():" << std::endl << "\ttotal = " << chan_count.n_total () << std::endl;
return chan_count;
}
void*
WavesAudioBackend::get_buffer (PortHandle port_handle, pframes_t nframes)
{
// Here we would check if the port is registered. However, we will not do it as
// it's relatively VERY SLOW operation. So let's count on consistency
// of the caller as get_buffer normally is called hundreds of "kilotimes" per second.
if (port_handle == NULL) {
std::cerr << "WavesAudioBackend::get_buffer : Invalid port handler <NULL>!" << std::endl;
return NULL;
}
return ((WavesAudioPort*)port_handle)->get_buffer (nframes);
}
int
WavesAudioBackend::_register_system_audio_ports ()
{
if (!_device) {
std::cerr << "WavesAudioBackend::_register_system_audio_ports (): No device is set!" << std::endl;
return -1;
}
std::vector<std::string> input_channels = _device->InputChannels ();
_max_input_channels = input_channels.size ();
uint32_t channels = (_input_channels ? _input_channels : input_channels.size ());
uint32_t port_number = 0;
LatencyRange lr = {0,0};
// Get latency for capture
lr.min = lr.max = _device->GetLatency (false) + _device->CurrentBufferSize () + _systemic_input_latency;
for (std::vector<std::string>::iterator it = input_channels.begin ();
(port_number < channels) && (it != input_channels.end ());
++it) {
std::ostringstream port_name;
port_name << "capture_" << ++port_number;
WavesDataPort* port = _register_port ("system:" + port_name.str (), DataType::AUDIO , static_cast<PortFlags> (IsOutput | IsPhysical | IsTerminal));
if (port == NULL) {
std::cerr << "WavesAudioBackend::_create_system_audio_ports (): Failed registering port [" << port_name << "] for [" << _device->DeviceName () << "]" << std::endl;
return-1;
}
set_latency_range (port, false, lr);
}
std::vector<std::string> output_channels = _device->OutputChannels ();
_max_output_channels = output_channels.size ();
channels = (_output_channels ? _output_channels : _max_output_channels);
port_number = 0;
// Get latency for playback
lr.min = lr.max = _device->GetLatency (true) + _device->CurrentBufferSize () + _systemic_output_latency;
for (std::vector<std::string>::iterator it = output_channels.begin ();
(port_number < channels) && (it != output_channels.end ());
++it) {
std::ostringstream port_name;
port_name << "playback_" << ++port_number;
WavesDataPort* port = _register_port ("system:" + port_name.str (), DataType::AUDIO , static_cast<PortFlags> (IsInput| IsPhysical | IsTerminal));
if (port == NULL) {
std::cerr << "WavesAudioBackend::_create_system_audio_ports (): Failed registering port ]" << port_name << "] for [" << _device->DeviceName () << "]" << std::endl;
return-1;
}
set_latency_range (port, true, lr);
}
return 0;
}
void
WavesAudioBackend::_unregister_system_audio_ports ()
{
std::vector<WavesAudioPort*> physical_audio_ports = _physical_audio_inputs;
physical_audio_ports.insert (physical_audio_ports.begin (), _physical_audio_outputs.begin (), _physical_audio_outputs.end ());
for (std::vector<WavesAudioPort*>::const_iterator it = physical_audio_ports.begin (); it != physical_audio_ports.end (); ++it) {
std::vector<WavesDataPort*>::iterator port_iterator = std::find (_ports.begin (), _ports.end (), *it);
if (port_iterator == _ports.end ()) {
std::cerr << "WavesAudioBackend::_unregister_system_audio_ports (): Failed to find port [" << (*it)->name () << "]!" << std::endl;
}
else {
_ports.erase (port_iterator);
}
delete *it;
}
_physical_audio_inputs.clear ();
_physical_audio_outputs.clear ();
}

View file

@ -0,0 +1,62 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "waves_audioport.h"
using namespace ARDOUR;
WavesAudioPort::WavesAudioPort (const std::string& port_name, PortFlags flags)
: WavesDataPort (port_name, flags)
{
memset (_buffer, 0, sizeof (_buffer));
}
void* WavesAudioPort::get_buffer (pframes_t nframes)
{
if (is_input ()) {
std::vector<WavesDataPort*>::const_iterator it = get_connections ().begin ();
if (it != get_connections ().end ()) {
/* In fact, the static casting to (const WavesAudioPort*) is not that safe.
* However, mixing the buffers is assumed in the time critical conditions.
* Base class WavesDataPort takes is supposed to provide enough consistentcy
* of the connections.
*/
for (memcpy (_buffer, ((const WavesAudioPort*)*it)->const_buffer (), nframes * sizeof (Sample)), ++it;
it != get_connections ().end ();
++it) {
Sample* tgt = buffer ();
const Sample* src = ((const WavesAudioPort*)*it)->const_buffer ();
for (uint32_t frame = 0; frame < nframes; ++frame, ++tgt, ++src) {
*tgt += *src;
}
}
}
}
return _buffer;
}
void
WavesAudioPort::_wipe_buffer()
{
memset (_buffer, 0, sizeof (_buffer));
}

View file

@ -0,0 +1,58 @@
/*
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__ */

View file

@ -0,0 +1,142 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "waves_dataport.h"
using namespace ARDOUR;
WavesDataPort::WavesDataPort (const std::string& inport_name, PortFlags inflags)
: _name (inport_name)
, _flags (inflags)
{
_capture_latency_range.min =
_capture_latency_range.max =
_playback_latency_range.min =
_playback_latency_range.max = 0;
}
WavesDataPort::~WavesDataPort ()
{
disconnect_all ();
}
int WavesDataPort::connect (WavesDataPort *port)
{
if (!port) {
std::cerr << "WavesDataPort::connect (): invalid (null) port to connect to!" << std::endl;
return -1;
}
if (type () != port->type ()) {
std::cerr << "WavesDataPort::connect (): wrong type of the port to connect to!" << std::endl;
return -1;
}
if (is_output () && port->is_output ()) {
std::cerr << "WavesDataPort::connect (): attempt to connect output port to output port!" << std::endl;
return -1;
}
if (is_input () && port->is_input ()) {
std::cerr << "WavesDataPort::connect (): attempt to connect input port to input port!" << std::endl;
return -1;
}
if (this == port) {
std::cerr << "WavesDataPort::connect (): attempt to connect port to itself!" << std::endl;
return -1;
}
if (is_connected (port)) {
std::cerr << "WavesDataPort::connect (): the ports are already connected!" << std::endl;
return -1;
}
_connect (port, true);
return 0;
}
void WavesDataPort::_connect (WavesDataPort *port, bool api_call)
{
_connections.push_back (port);
if (api_call) {
port->_connect (this, false);
}
}
int WavesDataPort::disconnect (WavesDataPort *port)
{
if (port == NULL) {
std::cerr << "WavesDataPort::disconnect (): invalid (null) port to disconnect from!" << std::endl;
return -1;
}
if (!is_connected (port)) {
std::cerr << "WavesDataPort::disconnect (): the ports are not connected!" << std::endl;
return -1;
}
_disconnect (port, true);
return 0;
}
void WavesDataPort::_disconnect (WavesDataPort *port, bool api_call)
{
std::vector<WavesDataPort*>::iterator it = std::find (_connections.begin (), _connections.end (), port);
if (it != _connections.end ()) { // actually, it's supposed to be always true.
_connections.erase (it);
}
if (api_call) {
port->_disconnect (this, false);
}
if (is_input() && _connections.empty())
{
_wipe_buffer();
}
}
void WavesDataPort::disconnect_all ()
{
while (!_connections.empty ()) {
_connections.back ()->_disconnect (this, false);
_connections.pop_back ();
}
}
bool WavesDataPort::is_physically_connected () const
{
for (std::vector<WavesDataPort*>::const_iterator it = _connections.begin (); it != _connections.end (); ++it) {
if ((*it)->is_physical ()) {
return true;
}
}
return false;
}

View file

@ -0,0 +1,115 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __libardour_waves_dataport_h__
#define __libardour_waves_dataport_h__
#include "ardour/types.h"
#include "memory.h"
namespace ARDOUR {
class WavesDataPort {
public:
virtual ~WavesDataPort ();
inline const std::string& name () const
{
return _name;
}
int set_name (const std::string &name)
{
_name = name;
return 0;
}
virtual DataType type () const = 0;
inline PortFlags flags () const
{
return _flags;
}
inline bool is_input () { return flags () & IsInput; }
inline bool is_output () { return flags () & IsOutput; }
inline bool is_physical () { return flags () & IsPhysical; }
inline bool is_terminal () { return flags () & IsTerminal; }
inline operator void* () { return (void*)this; }
inline const LatencyRange& latency_range (bool for_playback) const
{
return for_playback ? _playback_latency_range : _capture_latency_range;
}
inline void set_latency_range (const LatencyRange &latency_range, bool for_playback)
{
if (for_playback)
{
_playback_latency_range = latency_range;
}
else
{
_capture_latency_range = latency_range;
}
}
int connect (WavesDataPort *port);
int disconnect (WavesDataPort *port);
void disconnect_all ();
bool inline is_connected (const WavesDataPort *port) const
{
return std::find (_connections.begin (), _connections.end (), port) != _connections.end ();
}
bool inline is_connected () const
{
return _connections.size () != 0;
}
bool is_physically_connected () const;
inline const std::vector<WavesDataPort *>& get_connections () const { return _connections; }
virtual void* get_buffer (pframes_t nframes) = 0;
protected:
WavesDataPort (const std::string& inport_name, PortFlags inflags);
virtual void _wipe_buffer() = 0;
private:
std::string _name;
const PortFlags _flags;
LatencyRange _capture_latency_range;
LatencyRange _playback_latency_range;
std::vector<WavesDataPort*> _connections;
void _connect (WavesDataPort* port, bool api_call);
void _disconnect (WavesDataPort* port, bool api_call);
};
} // namespace
#endif /* __libardour_waves_dataport_h__ */

View file

@ -0,0 +1,50 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "waves_midi_buffer.h"
#include "waves_midi_event.h"
using namespace ARDOUR;
WavesMidiBuffer::WavesMidiBuffer (std::string name)
: std::vector<WavesMidiEvent*> ()
, _name (name)
{
}
WavesMidiBuffer::~WavesMidiBuffer ()
{
clear ();
}
void WavesMidiBuffer::clear ()
{
for (WavesMidiBufferIterator it = begin (); it != end (); ++it)
delete *it;
std::vector<WavesMidiEvent*>::clear ();
}
WavesMidiBuffer& WavesMidiBuffer::operator += (const WavesMidiBuffer& source)
{
for (WavesMidiBufferConstIterator it = source.begin (); it != source.end (); ++it) {
push_back (new WavesMidiEvent (**it));
}
return *this;
}

View file

@ -0,0 +1,47 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __libardour_waves_midi_buffer_h__
#define __libardour_waves_midi_buffer_h__
#include "ardour/types.h"
namespace ARDOUR {
class WavesMidiEvent;
class WavesMidiBuffer : public std::vector<WavesMidiEvent*>
{
public:
WavesMidiBuffer (std::string name);
~WavesMidiBuffer ();
void clear ();
WavesMidiBuffer& operator += (const WavesMidiBuffer& source);
inline const std::string name () { return _name; } // for DBG purpouses;
private:
const std::string _name;
};
typedef std::vector<WavesMidiEvent*>::iterator WavesMidiBufferIterator;
typedef std::vector<WavesMidiEvent*>::const_iterator WavesMidiBufferConstIterator;
} // namespace
#endif /* __libardour_waves_midi_buffer_h__ */

View file

@ -0,0 +1,268 @@
/*
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;
}

View file

@ -0,0 +1,72 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __libardour_waves_midi_device_h__
#define __libardour_waves_midi_device_h__
#include <portmidi/portmidi.h>
#include <portmidi/pmutil.h>
#include <portmidi/porttime.h>
#include "ardour/types.h"
namespace ARDOUR {
class WavesMidiEvent;
class WavesMidiDevice {
public:
WavesMidiDevice (const std::string& name);
~WavesMidiDevice ();
inline const std::string& name () const { return _name; }
int open (PmTimeProcPtr time_proc, void* time_info);
void close ();
void do_io ();
void read_midi ();
void write_midi ();
int enqueue_output_waves_midi_event (const WavesMidiEvent* waves_midi_event);
WavesMidiEvent* dequeue_input_waves_midi_event ();
inline bool is_input () const { return _pm_input_id != pmNoDevice; };
inline bool is_output () const { return _pm_output_id != pmNoDevice; };
void validate ();
private:
PmDeviceID _pm_input_id;
PmDeviceID _pm_output_id;
const std::string _name;
/* shared queues */
PmQueue* _input_queue;
PmQueue* _output_queue;
PmStream* _input_pm_stream;
PmStream* _output_pm_stream;
WavesMidiEvent *_incomplete_waves_midi_event;
};
} // namespace
#endif /* __libardour_waves_midi_device_h__ */

View file

@ -0,0 +1,242 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "waves_midi_device_manager.h"
#include "waves_audiobackend.h"
#ifdef __WINDOWS__
#include "windows.h"
#include "mmsystem.h"
#elif __MACOS__
#include <CoreMIDI/MIDIServices.h>
#define midiInGetNumDevs MIDIGetNumberOfSources
#define midiOutGetNumDevs MIDIGetNumberOfDestinations
#endif
using namespace ARDOUR;
WavesMidiDeviceManager::WavesMidiDeviceManager (WavesAudioBackend& audiobackend)
: _active (false)
, _streaming (false)
, _input_device_count (0)
, _output_device_count (0)
, _audiobackend (audiobackend)
{
}
WavesMidiDeviceManager::~WavesMidiDeviceManager ()
{
}
int
WavesMidiDeviceManager::start ()
{
// COMMENTED DBG LOGS */ std::cout << "WavesMidiDeviceManager::stream ():" << std::endl;
if ( _active == true ) {
return -1;
}
if (Pm_Initialize () != pmNoError) {
return -1;
}
_create_devices ();
_input_device_count = midiInGetNumDevs ();
_output_device_count = midiOutGetNumDevs ();
_active = true;
return 0;
}
int
WavesMidiDeviceManager::stream (bool yn)
{
// COMMENTED DBG LOGS */ std::cout << "WavesMidiDeviceManager::stream ():" << std::endl;
if (!_active) {
std::cerr << "WavesMidiDeviceManager::stream (): the midi device manager is not started up !" << std::endl;
return -1;
}
if (_streaming == yn) {
return 0;
}
if (yn) {
if ( Pt_Start (1, __portmidi_callback, this) != ptNoError) {
std::cerr << "WavesMidiDeviceManager::stream (): Pt_Start () failed!" << std::endl;
return -1;
}
}
else {
if (Pt_Stop () != ptNoError) {
std::cerr << "WavesMidiDeviceManager::stream (): Pt_Stop () failed!" << std::endl;
return -1;
}
}
_streaming = yn;
return 0;
}
int
WavesMidiDeviceManager::stop ()
{
// COMMENTED DBG LOGS */ std::cout << "WavesMidiDeviceManager::stop ():" << std::endl;
if ( _active == false )
return 0;
stream (false);
_close_devices ();
_active = false;
if (Pm_Terminate () != pmNoError) {
std::cerr << "WavesMidiDeviceManager::stop (): Pt_Terminate () failed!" << std::endl;
return -1;
}
return 0;
}
void
WavesMidiDeviceManager::__portmidi_callback (PtTimestamp timestamp, void * userData)
{
// COMMENTED DBG LOGS */ std::cout << "WavesMidiDeviceManager::__portmidi_callback ():" << std::endl;
WavesMidiDeviceManager *dm = (WavesMidiDeviceManager *)userData;
if (dm == NULL) {
return;
}
dm->_portmidi_callback (timestamp);
}
void
WavesMidiDeviceManager::_portmidi_callback (PtTimestamp timestamp)
{
if ((!_active) || (!_streaming)) {
return;
}
if ((_input_device_count != midiInGetNumDevs ()) || (_output_device_count != midiOutGetNumDevs ())) {
_audiobackend._changed_midi_devices ();
return;
}
}
void WavesMidiDeviceManager::do_read ()
{
for (std::vector<WavesMidiDevice *>::const_iterator it = _devices.begin (); it != _devices.end (); ++it) {
(*it)->read_midi ();
}
}
void WavesMidiDeviceManager::do_write ()
{
for (std::vector<WavesMidiDevice *>::const_iterator it = _devices.begin (); it != _devices.end (); ++it) {
(*it)->write_midi ();
}
}
PmTimestamp
WavesMidiDeviceManager::__get_time_ms (void *time_info)
{
return ((WavesAudioBackend*)time_info)->sample_time ();
}
WavesMidiDevice* WavesMidiDeviceManager::_get_device (const std::string& name)
{
for (size_t i = 0; i < _devices.size (); i++) {
if (name == _devices[i]->name ()) {
return _devices[i];
}
}
return NULL;
}
int
WavesMidiDeviceManager::_create_devices ()
{
int count = Pm_CountDevices ();
for (int i = 0; i < count; i++) {
const PmDeviceInfo* pm_device_info = Pm_GetDeviceInfo (i);
if (pm_device_info == NULL) {
std::cerr << "WavesMidiDeviceManager::_create_devices (): Pm_GetDeviceInfo (" << i << ") failed!" << std::endl;
continue;
}
WavesMidiDevice *device = _get_device (pm_device_info->name);
if (device) {
device->validate ();
}
else
{
device = new WavesMidiDevice (pm_device_info->name);
_devices.push_back (device);
}
if (device->open (__get_time_ms, (void*)&_audiobackend)) {
std::cerr << "WavesMidiDeviceManager::_create_devices (): [" << device->name () << "]->open () failed!" << std::endl;
}
}
return 0;
}
int
WavesMidiDeviceManager::_delete_devices ()
{
// COMMENTED DBG LOGS */ std::cout << "WavesMidiDeviceManager::_delete_devices ():" << std::endl;
while (!_devices.empty ()) {
WavesMidiDevice * device = _devices.back ();
_devices.pop_back ();
delete device;
}
return 0;
}
void
WavesMidiDeviceManager::_close_devices ()
{
// COMMENTED DBG LOGS */ std::cout << "WavesMidiDeviceManager::_delete_devices ():" << std::endl;
for (size_t i = 0; i < _devices.size (); i++) {
_devices[i]->close ();
}
}

View file

@ -0,0 +1,77 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __libardour_waves_midi_device_manager_h__
#define __libardour_waves_midi_device_manager_h__
#include "waves_midi_device.h"
namespace ARDOUR {
class WavesAudioBackend;
class WavesMidiDeviceManager {
public:
WavesMidiDeviceManager (WavesAudioBackend& audiobackend);
~WavesMidiDeviceManager ();
inline const std::vector<WavesMidiDevice *>& devices () const
{
return _devices;
}
int start ();
int stop ();
int stream (bool yn);
int is_streaming () { return _streaming; }
void do_read ();
void do_write ();
private:
int _create_devices ();
void _close_devices ();
int _delete_devices ();
static void __portmidi_callback (PtTimestamp timestamp, void * userData);
void _portmidi_callback (PtTimestamp timestamp);
/** __get_time_ms is given to Pm_Open functions (see WavesMidiDevice.cc)
* to provide the time in milliseconds using the time of audio
* transport.
* time_info is a pointer on the backend instance, which agregates the
* audio and miditransports. It's not checked for correctness to consume
* no time.
*/
static PmTimestamp __get_time_ms (void *time_info);
WavesMidiDevice* _get_device (const std::string& name);
std::vector<WavesMidiDevice*> _devices; // Vector for midi devices
bool _active;
bool _streaming;
size_t _input_device_count;
size_t _output_device_count;
WavesAudioBackend& _audiobackend;
};
} // namespace
#endif /* __libardour_waves_midi_device_manager_h__ */

View file

@ -0,0 +1,161 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "memory.h"
#include "waves_midi_event.h"
using namespace ARDOUR;
WavesMidiEvent::WavesMidiEvent (PmTimestamp timestamp)
: _size (0)
, _timestamp (timestamp)
, _data (NULL)
, _state (INCOMPLETE)
{
}
WavesMidiEvent::WavesMidiEvent (PmTimestamp timestamp, const uint8_t* data, size_t datalen)
: _size (datalen)
, _timestamp (timestamp)
, _data (data && datalen ? new uint8_t[ (datalen < sizeof (PmMessage)) ? sizeof (PmMessage) : datalen] : NULL)
, _state (data && datalen ? COMPLETE : BROKEN)
{
// COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::WavesMidiEvent (const WavesMidiEvent& source) : Size=" << _size << "---" << datalen << std::endl;
if (_state == COMPLETE) {
// COMMENTED DBG LOGS */ std::cout << "\t\t\t Allocated Size=" << ((datalen < sizeof (PmMessage)) ? sizeof (PmMessage) : datalen) << std::endl;
memcpy (_data, data, datalen);
}
}
WavesMidiEvent::WavesMidiEvent (const WavesMidiEvent& source)
: _size (source.size ())
, _timestamp (source.timestamp ())
, _data ((source.size () && source.const_data ()) ? new uint8_t[ (source.size () < sizeof (PmMessage)) ? sizeof (PmMessage) : source.size ()] : NULL)
, _state (source.state () )
{
// COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::WavesMidiEvent (const WavesMidiEvent& source) : Size=" << _size << "---" << source.size () << std::endl;
// COMMENTED DBG LOGS */ std::cout << "\t\t\t Allocated Size=" << ((source.size () < sizeof (PmMessage)) ? sizeof (PmMessage) : source.size ()) << std::endl;
if (_data && source.const_data ()) {
memcpy (_data, source.const_data (), source.size ());
}
}
WavesMidiEvent::~WavesMidiEvent ()
{
delete _data;
}
WavesMidiEvent *WavesMidiEvent::append_data (const PmEvent &midi_event)
{
switch ( _state ) {
case INCOMPLETE:
break;
default:
// COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::append_data (): NO case INCOMPLETE" << std::endl;
_state = BROKEN;
return NULL;
}
size_t message_size = _midi_message_size (midi_event.message);
uint8_t message_status = Pm_MessageStatus (midi_event.message);
if (_data == NULL) { // This is a first event to add
bool sysex = (message_status == SYSEX);
_data = new unsigned char [sysex ? PM_DEFAULT_SYSEX_BUFFER_SIZE : sizeof (PmMessage)];
if (!sysex)
{
// COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::append_data (): SHORT MSG" << std::endl;
* (PmMessage*)_data = 0;
switch (message_size) {
case 1:
case 3:
_size = message_size;
// COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::append_data (): size = " << _size << std::endl;
break;
default:
// COMMENTED DBG LOGS */ std::cout << "WavesMidiEvent::append_data (): WRONG MESSAGE SIZE (" << message_size << ") in the message: ";
// COMMENTED DBG LOGS */ std::cout << std::hex << (int) ((unsigned char*)&midi_event)[0] << " " << (int) ((unsigned char*)&midi_event)[1] << " " << (int) ((unsigned char*)&midi_event)[2] << " " << (int) ((unsigned char*)&midi_event)[3] << std::dec << std::endl;
_state = BROKEN;
return NULL;
}
// COMMENTED DBG LOGS */ std::cout << "\t size = " << _size << std::endl;
memcpy (_data, &midi_event.message, _size);
// COMMENTED DBG LOGS */ std::cout << "\t\t size = " << _size << std::endl;
_state = COMPLETE;
// COMMENTED DBG LOGS */ std::cout << "\t\t\t size = " << _size << std::endl;
return NULL;
}
}
// Now let's parse to sysex msg
if (message_status >= REAL_TIME_FIRST) { // Nested Real Time MIDI event
WavesMidiEvent *waves_midi_message = new WavesMidiEvent (midi_event.timestamp);
waves_midi_message->append_data (midi_event);
return waves_midi_message;
}
if (message_status >= STATUS_FIRST && (message_status != EOX) && _size) { // Certainly it's a broken SYSEX case
WavesMidiEvent *waves_midi_message = new WavesMidiEvent (midi_event.timestamp);
waves_midi_message->append_data (midi_event);
return waves_midi_message;
}
const uint8_t* source_data ((uint8_t*)&midi_event.message);
for (size_t i = 0; i < sizeof (midi_event.message); ++i) {
_data[_size] = source_data[i];
_size++;
if (source_data[i] == EOX) { // Ended SYSEX message
_state = COMPLETE;
return NULL;
}
}
return NULL;
}
size_t WavesMidiEvent::_midi_message_size (PmMessage midi_message)
{
static int high_lengths[] = {
1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 through 0x70 */
3, 3, 3, 3, 2, 2, 3, 1 /* 0x80 through 0xf0 */
};
static int low_lengths[] = {
1, 2, 3, 2, 1, 1, 1, 1, /* 0xf0 through 0xf7 */
1, 1, 1, 1, 1, 1, 1, 1 /* 0xf8 through 0xff */
};
int midi_message_status = Pm_MessageStatus (midi_message);
if (midi_message_status < STATUS_FIRST) {
return sizeof (midi_message);
}
int high = midi_message_status >> 4;
int low = midi_message_status & 0xF;
return (high != 0xF) ? high_lengths[high] : low_lengths[low];
}

View file

@ -0,0 +1,75 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __libardour_waves_midi_event_h__
#define __libardour_waves_midi_event_h__
#include <stdlib.h>
#include <portmidi/portmidi.h>
#include "ardour/types.h"
namespace ARDOUR {
class WavesMidiEvent
{
public:
enum State {
INCOMPLETE,
BROKEN,
COMPLETE
};
WavesMidiEvent (PmTimestamp timestamp);
WavesMidiEvent (PmTimestamp timestamp, const uint8_t* data, size_t datalen);
WavesMidiEvent (const WavesMidiEvent& source);
~WavesMidiEvent ();
WavesMidiEvent *append_data (const PmEvent &midi_event);
inline State state () const { return _state; };
inline size_t size () const { return _size; };
inline PmTimestamp timestamp () const { return _timestamp; };
inline void set_timestamp (PmTimestamp time_stamp) { _timestamp = time_stamp; };
inline const unsigned char* const_data () const { return _data; };
inline unsigned char* data () { return _data; };
inline bool operator< (const WavesMidiEvent &other) const { return timestamp () < other.timestamp (); };
inline bool sysex () const { return _data && (*_data == SYSEX); };
private:
enum
{
SYSEX = 0xF0,
EOX = 0xF7,
REAL_TIME_FIRST = 0xF8,
STATUS_FIRST = 0x80
};
size_t _size;
PmTimestamp _timestamp;
uint8_t *_data;
State _state;
static size_t _midi_message_size (PmMessage midi_message);
};
} // namespace
#endif /* __libardour_waves_midi_event_h__ */

View file

@ -0,0 +1,61 @@
/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "waves_midiport.h"
#include "waves_midi_event.h"
using namespace ARDOUR;
WavesMidiPort::WavesMidiPort (const std::string& port_name, PortFlags flags)
: WavesDataPort (port_name, flags)
, _midi_device (NULL)
, _waves_midi_buffer (port_name)
{
}
void*
WavesMidiPort::get_buffer (pframes_t nframes)
{
if (is_input ()) {
std::vector<WavesDataPort*>::const_iterator cit = get_connections ().begin ();
if (cit != get_connections ().end ()) {
_waves_midi_buffer.clear ();
WavesMidiBuffer& target = _waves_midi_buffer;
do {
/* In fact, the static casting to (const WavesMidiPort*) is not that safe.
* However, mixing the buffers is assumed in the time critical conditions.
* Base class WavesDataPort is supposed to provide enough consistentcy
* of the connections.
*/
target += ((const WavesMidiPort*)*cit)->const_buffer ();
}while((++cit) != get_connections ().end ());
std::sort (target.begin (), target.end ());
}
}
return &_waves_midi_buffer;
}
void
WavesMidiPort::_wipe_buffer()
{
_waves_midi_buffer.clear ();
}

View file

@ -0,0 +1,64 @@
/*
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__ */

View file

@ -0,0 +1,212 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __WCFourCC_h__
#define __WCFourCC_h__
/* Copy to include
#include "BasicTypes/WCFourCC.h"
*/
//#include "BasicTypes/WTByteOrder.h"
#include "WCFixedString.h"
// These are preprocessor macros rather than inline functions because most compilers can't
// resolve functions at compile-time.
#if _BYTEORDER_BIG_ENDIAN==1
#define FOURCC_BIG(a, b, c, d) ((uint32_t(a)<<24)|(uint32_t(b)<<16)|(uint32_t(c)<< 8)|(uint32_t(d)<< 0))
#define FOURCC_LITTLE(a, b, c, d) ((uint32_t(a)<< 0)|(uint32_t(b)<< 8)|(uint32_t(c)<<16)|(uint32_t(d)<<24))
#define FOURCC_COMPILER(a, b, c, d) FOURCC_BIG(a,b,c,d)
#elif _BYTEORDER_BIG_ENDIAN==0
#define FOURCC_BIG(a, b, c, d) ((uint32_t(a)<< 0)|(uint32_t(b)<< 8)|(uint32_t(c)<<16)|(uint32_t(d)<<24))
#define FOURCC_LITTLE(a, b, c, d) ((uint32_t(a)<<24)|(uint32_t(b)<<16)|(uint32_t(c)<< 8)|(uint32_t(d)<< 0))
#define FOURCC_COMPILER(a, b, c, d) FOURCC_LITTLE(a,b,c,d)
#else
#error _BYTEORDER_BIG_ENDIAN not defined proparly
#endif // _BYTEORDER_HPP_BIG_ENDIAN
typedef uint32_t WTFourCharCode;
#ifndef kEnableWCFourCCDebug
#define kEnableWCFourCCDebug 0 // set to 1 to enable debug members
#endif
class WCFourCC
{
private:
template<class _iter>
static WTFourCharCode stored_from_iter(_iter& i)
{
return s_stored_byte_order==wvNS::wvBO::byte_order_big_endian ? FOURCC_BIG(i[0], i[1], i[2], i[3]) : FOURCC_LITTLE(i[0], i[1], i[2], i[3]);
}
public:
// static const WCFourCC kDefaultFourCC_prv;
static WCFourCC kDefaultFourCC_prv() { return WCFourCC(); }
// change this line will change the byte order in which WCFourCC keeps the four char code
static const wvNS::wvBO::byte_order_type s_stored_byte_order = wvNS::wvBO::compiler_byte_order;
WCFourCC(const char a, const char b, const char c, const char d) :
m_stored_value(s_stored_byte_order==wvNS::wvBO::compiler_byte_order ? FOURCC_BIG(a,b,c,d) : FOURCC_LITTLE(a,b,c,d))
{
#if kEnableWCFourCCDebug == 1
m_c_str_stored_value[sizeof(WTFourCharCode)] = '\0';
#endif
}
WCFourCC() :
m_stored_value(FOURCC_BIG('?','?','?','?')) // since the four chars are the same, there is no need to choose between big & little
{
#if kEnableWCFourCCDebug == 1
m_c_str_stored_value[sizeof(WTFourCharCode)] = '\0';
#endif
}
WCFourCC(const WTFourCharCode in_fourCharCode, const wvNS::wvBO::byte_order_type in_byteOrder = wvNS::wvBO::compiler_byte_order) :
m_stored_value(in_byteOrder==s_stored_byte_order ? in_fourCharCode : wvNS::wvBO::swap32(in_fourCharCode))
{
#if kEnableWCFourCCDebug == 1
m_c_str_stored_value[sizeof(WTFourCharCode)] = '\0';
#endif
}
explicit WCFourCC(const char* in_source_string) :
m_stored_value(stored_from_iter(in_source_string))
{
#if kEnableWCFourCCDebug == 1
m_c_str_stored_value[sizeof(WTFourCharCode)] = '\0';
#endif
}
explicit WCFourCC(const WCFixedStringBase& in_source_string) :
m_stored_value(stored_from_iter(in_source_string))
{
#if kEnableWCFourCCDebug == 1
m_c_str_stored_value[sizeof(WTFourCharCode)] = '\0';
#endif
}
WTFourCharCode GetAsSomeEndian(const wvNS::wvBO::byte_order_type in_byteOrder) const
{
return s_stored_byte_order==in_byteOrder ? m_stored_value : wvNS::wvBO::swap32(m_stored_value);
}
WTFourCharCode GetAsBigEndian() const
{
return s_stored_byte_order==wvNS::wvBO::byte_order_big_endian ? m_stored_value : wvNS::wvBO::swap32(m_stored_value);
}
WTFourCharCode GetAsLittleEndian() const
{
return s_stored_byte_order==wvNS::wvBO::byte_order_little_endian ? m_stored_value : wvNS::wvBO::swap32(m_stored_value);
}
WTFourCharCode GetAsCompilerEndian() const
{
return s_stored_byte_order==wvNS::wvBO::compiler_byte_order ? m_stored_value : wvNS::wvBO::swap32(m_stored_value);
}
WTFourCharCode GetAsStored() const
{
return m_stored_value;
}
char operator[](const unsigned int in_character_index) const
{
return char(m_stored_value >> (8 * (s_stored_byte_order==wvNS::wvBO::compiler_byte_order ? 3-in_character_index : in_character_index)));
}
char& operator[](const unsigned int in_character_index)
{
return reinterpret_cast<char*>(&m_stored_value)[s_stored_byte_order==wvNS::wvBO::byte_order_little_endian ? 3-in_character_index : in_character_index];
}
static size_t size()
{
return sizeof(WTFourCharCode);
}
static size_t max_size()
{
return size();
}
static size_t capacity()
{
return size();
}
WCFixedString4 GetString() const
{
WCFixedString4 retVal;
retVal << operator[](0) << operator[](1) << operator[](2) << operator[](3);
return retVal;
}
#if kEnableWCFourCCDebug == 1
const char* c_str() const
{
return m_c_str_stored_value;
}
#endif
protected:
private:
#if kEnableWCFourCCDebug == 1
union
{
#endif
WTFourCharCode m_stored_value;
#if kEnableWCFourCCDebug == 1
char m_c_str_stored_value[sizeof(WTFourCharCode)+1];
};
#endif
WCFourCC& operator=(const WTFourCharCode); // we want initialization from literal to be dome through the constructor
};
inline bool operator<(const WCFourCC in_left, const WCFourCC in_right)
{
return in_left.GetAsSomeEndian(WCFourCC::s_stored_byte_order) < in_right.GetAsSomeEndian(WCFourCC::s_stored_byte_order);
}
inline bool operator==(const WCFourCC in_left, const WCFourCC in_right)
{
return in_left.GetAsSomeEndian(WCFourCC::s_stored_byte_order) == in_right.GetAsSomeEndian(WCFourCC::s_stored_byte_order);
}
inline bool operator!=(const WCFourCC in_left, const WCFourCC in_right)
{
return ! operator==(in_left, in_right);
}
#define kDefaultFourCC WCFourCC::kDefaultFourCC_prv()
static const WCFourCC kZeroFourCC(0, wvNS::wvBO::compiler_byte_order);
#endif //#if !defined(__WCFourCC_h__)

View file

@ -0,0 +1,222 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(__WTByteOrder_h__)
#define __WTByteOrder_h__
/* Copy to include
#include "BasicTypes/WTByteOrder.h"
*/
#include "WavesPublicAPI/wstdint.h"
#include "BasicTypes/WUDefines.h"
// Stuff concerning little/big endian and the conversion between them.
// most of the code here was copied from NetShell with some modifications
// Written by Udi on Nov-2005
// Adjusted to Cross platform by Shai Mar-2006
// Macros to determine endian. __BIG_ENDIAN__ & __LITTLE_ENDIAN__ should come from the compiler.
// We try to set the macro _BYTEORDER_BIG_ENDIAN to 1 if big-endian or to 0 if little-endian.
// if the compiler properly has set either __BIG_ENDIAN__ or __LITTLE_ENDIAN__
#if defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__)
#if defined(__BIG_ENDIAN__) && defined(__LITTLE_ENDIAN__) //if both defined, check them as booleans
#if __BIG_ENDIAN__ && !__LITTLE_ENDIAN__
#define _BYTEORDER_BIG_ENDIAN 1
#elif !__BIG_ENDIAN__ && __LITTLE_ENDIAN__
#define _BYTEORDER_BIG_ENDIAN 0
#else
#error I am confused. Is this big-endian or little-endian?
#endif // stupid compiler defines both __LITTLE_ENDIAN__ and __BIG_ENDIAN__
#elif defined(__BIG_ENDIAN__)
#define _BYTEORDER_BIG_ENDIAN 1
#else
#define _BYTEORDER_BIG_ENDIAN 0
#endif // big/little switch
#else // if the compiler proparly has NOT set either __BIG_ENDIAN__ or __LITTLE_ENDIAN__
// http://msdn.microsoft.com/en-us/library/b0084kay.aspx for all preprocessor defs. _M_X64: 64 bit. _M_IA64: Itanium 64bit
#if defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(__INTEL__) || defined(__x86_64__) || defined(_M_X64) || defined(_M_IA64)
#define _BYTEORDER_BIG_ENDIAN 0
#elif defined(_M_PPC) || defined(__POWERPC__ ) || defined(__ppc__)
#define _BYTEORDER_BIG_ENDIAN 1
#else
#error Cannot detect compiler byte-order. Please add a test for your compiler appropriate symbol to this header file.
#endif // symbol search
#endif // standard preprocessor symbol found
// code to determine which assembly code we can use
#if defined(_MSC_VER) && defined(_M_IX86)
#define _BYTEORDER_ASM_MSVC_I386 1 // Windows
#elif defined(__GNUC__) && defined(__i386__)
#define _BYTEORDER_ASM_GNUC_I386 1 // Linux, or MacOS with MacIntel on Xcode
#define _BYTEORDER_ASM_NONE 1 // Currently we have no assebley for GNU i386, so use the C version
#elif defined(__GNUC__) && defined(__POWERPC__)
#define _BYTEORDER_ASM_GNUC_PPC 1 // MacOS with PPC on Xcode
#define _BYTEORDER_ASM_NONE 1 // Currently we have no assebley for GNU PPC, so use the C version
#else
#define _BYTEORDER_ASM_NONE 1 // don't know the compiler and processor, use C implementation
#endif
namespace wvNS {
namespace wvBO // namespace Waves::ByteOrder
{
typedef int byte_order_type; // we use int rather than enum because some compilers cannot resolve enum constants at compile-time. There are only two options anyway :-)
static const byte_order_type byte_order_little_endian = 0;
static const byte_order_type byte_order_big_endian = 1;
// We try to use this static const rather than preprocessor symbols in our code wherever possible.
#if _BYTEORDER_BIG_ENDIAN == 1
static const byte_order_type compiler_byte_order = byte_order_big_endian;
#else
static const byte_order_type compiler_byte_order = byte_order_little_endian;
#endif
//---------------------------------------------------------------------------------
// swap functions - best if implemented in inline assembly code
// The following are very slow swappers when compiled, do not use in loops
#if _BYTEORDER_ASM_MSVC_I386
// assembly implementation for Intel386 on Visual Studio
inline uint16_t swap16(uint16_t x)
{
__asm MOV AX,x;
__asm XCHG AL,AH;
__asm MOV x,AX;
return x;
}
inline uint32_t swap32(uint32_t x)
{
__asm MOV EAX,x;
__asm BSWAP EAX;
__asm MOV x,EAX;
return x;
}
inline uint64_t swap64(uint64_t x) // TODO: To be replaced
{
return
((x>>7*8)&0xFF)<<0*8 | ((x>>6*8)&0xFF)<<1*8 | ((x>>5*8)&0xFF)<<2*8 | ((x>>4*8)&0xFF)<<3*8 |
((x>>3*8)&0xFF)<<4*8 | ((x>>2*8)&0xFF)<<5*8 | ((x>>1*8)&0xFF)<<6*8 | ((x>>0*8)&0xFF)<<7*8 ;
}
/* the ASM code for swap64 does not compile
inline uint64_t swap64(uint64_t x)
{
__asm MOV EBX, OFFSET x;
__asm MOV EAX, [EBX];
__asm MOV EDX, [EBX+4];
__asm BSWAP EAX;
__asm BSWAP EDX;
__asm MOV [EBX],EDX;
__asm MOV [EBX+4],EAX;
return x;
}
*/
#endif // _BYTEORDER_ASM_MSVC_I386
#if _BYTEORDER_ASM_GNUC_I386
// assembly implementation for Intel386 on GCC (Linux)
// TODO
#endif // _BYTEORDER_ASM_GNUC_I386
#if _BYTEORDER_ASM_GNUC_PPC
// assembly implementation for PowerPC on GCC (XCode)
// TODO
#endif // _BYTEORDER_ASM_GNUC_PPC
#if _BYTEORDER_ASM_NONE
inline uint16_t swap16(uint16_t x) { return (x>>8) | ((x&0xFF)<<8); }
inline uint32_t swap32(uint32_t x) { return (x&0xFF)<<24 | (x&0xFF00)<<8 | (x&0xFF0000)>>8 | (x&0xFF000000)>>24; }
inline uint64_t swap64(uint64_t x)
{
return
((x>>7*8)&0xFF)<<0*8 | ((x>>6*8)&0xFF)<<1*8 | ((x>>5*8)&0xFF)<<2*8 | ((x>>4*8)&0xFF)<<3*8 |
((x>>3*8)&0xFF)<<4*8 | ((x>>2*8)&0xFF)<<5*8 | ((x>>1*8)&0xFF)<<6*8 | ((x>>0*8)&0xFF)<<7*8 ;
}
#endif // _BYTEORDER_ASM_NONE
//---------------------------------------------------------------------------------
// order conversion functions
// may want to overload for float and double as well.
// overload for signed ints is ambiguous and should be done only if no other choice exists.
// - - - - - - - - - - - - - - - - - - - -
inline uint16_t compiler_to_big_16(uint16_t x)
{
return compiler_byte_order==byte_order_big_endian ? x : swap16(x);
}
inline uint16_t big_to_compiler_16(uint16_t x)
{
return compiler_byte_order==byte_order_big_endian ? x : swap16(x);
}
inline uint16_t compiler_to_little_16(uint16_t x)
{
return compiler_byte_order==byte_order_little_endian ? x : swap16(x);
}
inline uint16_t little_to_compiler_16(uint16_t x)
{
return compiler_byte_order==byte_order_little_endian ? x : swap16(x);
}
// - - - - - - - - - - - - - - - - - - - -
inline uint32_t compiler_to_big_32(uint32_t x)
{
return compiler_byte_order==byte_order_big_endian ? x : swap32(x);
}
inline uint32_t big_to_compiler_32(uint32_t x)
{
return compiler_byte_order==byte_order_big_endian ? x : swap32(x);
}
inline uint32_t compiler_to_little_32(uint32_t x)
{
return compiler_byte_order==byte_order_little_endian ? x : swap32(x);
}
inline uint32_t little_to_compiler_32(uint32_t x)
{
return compiler_byte_order==byte_order_little_endian ? x : swap32(x);
}
// - - - - - - - - - - - - - - - - - - - -
inline uint64_t compiler_to_big_64(uint64_t x)
{
return compiler_byte_order==byte_order_big_endian ? x : swap64(x);
}
inline uint64_t big_to_compiler_64(uint64_t x)
{
return compiler_byte_order==byte_order_big_endian ? x : swap64(x);
}
inline uint64_t compiler_to_little_64(uint64_t x)
{
return compiler_byte_order==byte_order_little_endian ? x : swap64(x);
}
inline uint64_t little_to_compiler_64(uint64_t x)
{
return compiler_byte_order==byte_order_little_endian ? x : swap64(x);
}
} // namespace wvBO
} // namespace wvNS {
#endif // #if !defined(__WTByteOrder_h__)

View file

@ -0,0 +1,117 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __WUComPtr_h__
#define __WUComPtr_h__
/* Copy to include
#include "BasicTypes/WUComPtr.h"
*/
#include "WavesPublicAPI/wstdint.h"
typedef int32_t wvComPtr[2];
// ConvertDPtr has the exact format of a vfp callback function, but it is a local function, native only.
// It converts a pointer in either 32 bits or 64 bits to a place-holder of 64 bits in coefs/states/external memory.
// pData is expected to point to a pre-allocate space enough for storing a pointer (posibly two single-precision coefs).
// Since pointers are not transferable between hardwares, at preset time no need for a shell callback.
// We keep this as a cALGORITHM for compatibility with the rest of the convert functions
//================================================================================
inline uint32_t vfpConvertDPtr(const void* InPointer, void* pData)
//================================================================================
{
uint64_t *pL = (uint64_t *)pData;
*pL = (uint64_t)InPointer;
return (uint32_t)sizeof(uint64_t);
}
/*
{
// data in that struct must be the same type of the Coefs/States type!
int32_t LSW; // Least significant word
int32_t MSW; // Most significant word
};
inline wvComPtr PackToComPtr(const intptr_t in_PtrToPack)
// take ptr that hosted in intptr_t type
// and pack it to wvComPtr container type (MSW and LSW of 32bit each)
{
wvComPtr retVal;
int64_t t_PtrToPack = static_cast<int64_t>(in_PtrToPack);
// This packing is xPlatform coding for x32 and x64
// #ifdef for x64 - intptr_t is 64 bit
retVal.LSW = static_cast<int32_t>(t_PtrToPack & intptr_t(0xFFFFFFFF));
retVal.MSW = (static_cast<int32_t>(t_PtrToPack>>32));
// #ifdef for x32 - intptr_t is 32 bit
// retVal.LSW = int32_t(in_PtrToPack);
// retVal.MSW = 0;
return retVal;
}
inline intptr_t UnpackComPtr( const wvComPtr in_ComPtrToUnpack)
// take wvComPtr with MSW and LSW of 32bit each
// and unpack it to intptr_t type
{
intptr_t retVal;
// This unpacking is xPlatform coding for x32 and x64
// #ifdef for x64 - intptr_t is 64 bit so use intptr_t instead of int64_t
int64_t PtrAt64 = static_cast<int64_t>(in_ComPtrToUnpack.MSW);
PtrAt64 <<= 32;
PtrAt64 |= static_cast<int64_t>(in_ComPtrToUnpack.LSW);
retVal = static_cast<intptr_t>(PtrAt64);
// #ifdef for x32 - intptr_t is 32 bit
// retVal = static_cast<intptr_t>(retVal.LSW);
return retVal;
}
//////////////////////////////////////////////////////////////////////////
inline uint32_t ComPtr_to_DSP( const intptr_t PtrToConvert, char* pDataStruct )
{
*(reinterpret_cast<wvComPtr *>(pDataStruct)) = PackToComPtr(PtrToConvert);
return uint32_t(sizeof(wvComPtr));
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
inline uint32_t DSP_to_ComPtr( const char* pDataStruct, intptr_t *ThePtr)
// pDataStruct is pointing to wvComPtr in the Coefs/States
// the function reconstruct the pointer into ThePtr
{
*ThePtr = UnpackComPtr(*(reinterpret_cast<const wvComPtr *>(pDataStruct)));
return uint32_t(sizeof(wvComPtr));
}
//////////////////////////////////////////////////////////////////////////
*/
#endif //#if !defined(__WUComPtr_h__)

View file

@ -0,0 +1,175 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __WUDefines_h__
#define __WUDefines_h__
/*Copy to include
#include "BasicTypes/WUDefines.h"
*/
#include "1.0/WavesPublicAPI_Defines.h"
// When changing wvNS value also do the same change in Objective_C_MangledNames.h
// because CWSAUCocoaViewFactoryAsString is hard coded there
#define wvNS wvWavesV9_3
#ifdef __MACOS__
#define ObjCNameSpace(__className__) wvWavesV9_3_ ## __className__
#endif
#ifdef INSIDE_NETSHELL
#define DllExport
#else
#define DllExport WPAPI_DllExport
#endif
#define __CDECL __WPAPI_CDECL
#define __STDCALL __WPAPI_STDCALL
#ifndef NULL
#define NULL (0)
#endif
#ifndef nil
#define nil NULL
#endif
#define PASCAL_MAC_ONLY #error do not use PASCAL_MAC_ONLY. See defintions in WavesFTT.h for replacment.
#define CALLCON #error do not use CALLCON. See defintions in WavesFTT.h for replacment.
#define FUNCEXP #error do not use FUNCEXP. See defintions in WavesFTT.h for replacment.
#define WUNUSED_PARAM(__SOME_UNUSED_PARAM__) ((void)__SOME_UNUSED_PARAM__)
#ifdef __MACOS__
const char* const OS_NAME = "Mac";
#define WIN_ONLY(__Something_only_for_windows__)
#define MAC_ONLY(__Something_only_for_mac__) __Something_only_for_mac__
#if defined(i386) || defined(__i386) || defined(__i386__)
#define kNumArchBits 32
#endif
#if defined(__x86_64) || defined(__x86_64__)
#define kNumArchBits 64
#endif
#if (__i386 || __x86_64) && !defined(__LITTLE_ENDIAN__)
#define __LITTLE_ENDIAN__
#endif
#if !(__i386 || __x86_64) && !defined(__BIG_ENDIAN__)
#define __BIG_ENDIAN__
#endif
#ifdef __GNUC__
#define STD_EXCEPT_WIN std
#define FAR
#define PASCAL
// #define HINSTANCE void*
#define WINAPI
#else
#define DllExport_WinOnly
#define STD_EXCEPT_WIN std
#define FAR
#define PASCAL // windows' pascal
#define HINSTANCE void*
#define WINAPI
#endif
#define THROW_SPEC(THROW_OBJ) throw (THROW_OBJ)
#define WUNUSED_PARAM_ON_MAC(__SOME_UNUSED_PARAM__) WUNUSED_PARAM(__SOME_UNUSED_PARAM__)
#define WUNUSED_PARAM_ON_WIN(__SOME_UNUSED_PARAM__)
#endif
#ifdef _WINDOWS
const char* const OS_NAME = "Win";
#define WIN_ONLY(__Something_only_for_windows__) __Something_only_for_windows__
#define MAC_ONLY(__Something_only_for_mac__)
#if defined(_M_X64)
#define kNumArchBits 64
#else // not sure what are the VisualStudio macros for 32 bits
#define kNumArchBits 32
#endif
#define DllExport_WinOnly DllExport // help solve window specific link errors
#define STD_EXCEPT_WIN
#if !defined(__MINGW64__)
#define round(x) (floor(x+0.5))
#endif
#define __LITTLE_ENDIAN__
#define THROW_SPEC(THROW_OBJ) throw (...)
#define WUNUSED_PARAM_ON_MAC(__SOME_UNUSED_PARAM__)
#define WUNUSED_PARAM_ON_WIN(__SOME_UNUSED_PARAM__) WUNUSED_PARAM(__SOME_UNUSED_PARAM__)
#endif
#ifdef __linux__
const char* const OS_NAME = "Linux";
#define WIN_ONLY(__Something_only_for_windows__)
#define MAC_ONLY(__Something_only_for_mac__)
#define DllExport_WinOnly
#define STD_EXCEPT_WIN std
#define FAR
#define PASCAL
// #define HINSTANCE void*
#define WINAPI
#if __i386 && !defined(__LITTLE_ENDIAN__)
#define __LITTLE_ENDIAN__
#endif
#if !__i386 && !defined(__BIG_ENDIAN__)
#define __BIG_ENDIAN__
#endif
#define THROW_SPEC(THROW_OBJ) throw (THROW_OBJ)
#if defined(__x86_64) || defined(__LP64__)
#error "64 bit not suported yet on linux"
#else
#define kNumArchBits 32
#endif
#endif
#ifndef _WU_DECL
#define _WU_DECL __CDECL // the default is calling model is cdecl, but you can also set this macro from the outside to something different
#endif
#ifndef _XML_DECL
#define _XML_DECL __CDECL // the default is calling model is cdecl, but you can also set this macro from the outside to something different
#endif
#ifndef kNumArchBits
#error Macro kNumArchBits was not defined
#endif
#if kNumArchBits == 64
const char* const kNumArchBits_c_str = "64";
#endif
#if kNumArchBits == 32
const char* const kNumArchBits_c_str = "32";
#endif
#endif //__WUDefines_h__

View file

@ -0,0 +1,47 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __WUMathConsts_h__
#define __WUMathConsts_h__
/* Copy to include:
#include "BasicTypes/WUMathConsts.h"
*/
const float kfPI = 3.1415926535898f; // PI, single precision
const double kdPI = 3.1415926535897932384626433832795; // PI, double precision
const float kf2PI = 6.2831853071796f; // 2*PI
const double kd2PI = 6.283185307179586476925286766559; // 2*PI
const float kfhalfPI = 1.5707963267949f; // 0.5*PI
const double kdhalfPI = 1.57079632679489661923; // 0.5*PI
const double kdLn2 = 0.69314718055994530942; // natural log(2.0)
const double kdOneOverLn2 = 1.4426950408889634073599246810019; // natural (1.0/log(2.0)) - for multiply log() to get it as with base 2
const double kdLog2 = 0.301029995663981; // log10(2.0)
const double kdOneOverLog2 = 3.321928094887363; // (1.0/log10(2.0)) - for multiply log() to get it as with base 2
const double kdExponent = 2.718281828459045235360287471352; // e
const double kdSqrt2 = 1.41421356237309504880; // sqrt(2)
#endif //__WUMathConsts_h__

View file

@ -0,0 +1,265 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __WUTypes_h__
#define __WUTypes_h__
/* Copy to include:
#include "BasicTypes/WUTypes.h"
*/
#include "WavesPublicAPI/WTErr.h"
#include "WavesPublicAPI/wstdint.h"
#include "BasicTypes/WUDefines.h"
#include "BasicTypes/WCFourCC.h" // declares WTFourCharCode & WCFourCC
#include "BasicTypes/WUComPtr.h" // Communication Ptr for x64 compatibility
#include "WCFixedString.h"
#include <ctime>
#include <vector>
/********************************************************************************
Atoms
*********************************************************************************/
#define WTSInt64 "WTSInt64 is obsolete, please use int64_t instead";
#define WTUInt64 "WTUInt64 is obsolete, please use uint64_t instead";
#define WTSInt32 "WTSInt32 is obsolete, please use int32_t instead";
#define WTUInt32 "WTUInt32 is obsolete, please use uint32_t instead";
#define WTSInt16 "WTSInt16 is obsolete, please use int16_t instead";
#define WTUInt16 "WTUInt16 is obsolete, please use uint16_t instead";
#define WTSInt8 "WTSInt8 is obsolete, please use int8_t instead";
#define WTUInt8 "WTUInt8 is obsolete, please use uint8_t instead";
#define WTFloat32 "WTFloat32 is obsolete, please use float instead";
#define WTByte "WTByte is obsolete, please use uint8_t instead";
/********************************************************************************
Consts
*********************************************************************************/
//#define PI 3.1415926535897 // ... Was moved to WUMathConsts.h under the name kPI
const uint32_t kDefaultCircleSlices = 100;
/********************************************************************************
Utilities
*********************************************************************************/
// SCOPED_ENUM is a macro that defines an enum inside a class with a given name, thus declaring the enum values
// inside a named scope. This allows declaring:
// SCOPED_ENUM(SomeType)
// {
// Val1,
// Val2,
// Val3
// }
// SCOPED_ENUM_END
// And then you can reference SomeType::Val1, SomeType::Val2, SomeType::Val3 for the various values, unlike
// a regular enum on which Val1, Val2 and Val3 would become global names.
// Additionally, you get SomeType::Type to specify the type of the whole enum in case you want to transfer it to
// a function.
// Don't forget to close the enum with SCOPED_ENUM_END, otherwise you'll get bogus compilation errors.
// This requirement can probably be removed some day, but it will make the SCOPED_ENUM macro much less readable...
#define SCOPED_ENUM(name) \
class name \
{ \
public: enum Type
#define SCOPED_ENUM_END ;};
//********************************************************************************
// Files
//! file (and resource container) opening permissions
// Note: When opening with eFMWriteOnly on existing file, writing to the file will append, not overwrite, Shai, 9/8/2007.
enum WEPermitions{ eFMReadOnly, eFMWriteOnly, eFMReadWrite};
// File cursor positions
enum WEPositionMode{eFMFileBegin, eFMFileCurrent, eFMFileEnd};
// File creation types
enum WECreateFlags {
eFMCreateFile_DontOverrideIfAlreadyExists, // Create a new file , If the file exists leaves the existing data intact
eFMCreateFile_FailIfAlreadyExists, // Attempt to create a new file, if file already exists - fail.
eFMCreateFile_OverrideIfAlreadyExists // Create a new file , If the file exists, overwrite the file and clear the existing data
};
enum WEFoldersDomain{
eSystemDomain,
eLocalDomain,
eUserDomain,
eNumberOfFoldersDomains
};
enum WEArchBits{
e32Bits,
e64Bits,
eNumberOfArchBits
};
enum WESystemFolders{
eSystemFolder,
eDesktopFolder,
ePreferencesFolder,
eWavesPreferencesFolder, //deprecated use eWavesPreferencesFolder2
eTemporaryFolder,
eTrashFolder,
eCurrentFolder,
eRootFolder,
eLibrariesFolder,
eAudioComponentsFolder, // MacOS only
eCacheFolder,
eWavesCacheFolder,
eAppDataFolder,
eWavesAppDataFolder,
eSharedUserDataFolder,
eWavesSharedUserDataFolder,
eWavesScanViewFolder,
eWavesPreferencesFolder2, // Mac: "/Users/username/Library/Preferences/Waves Audio"
// Win: "C:\Users\username\AppData\Roaming\Waves Audio\Preferences"
eNumberOfSystemFolders
};
//********************************************************************************
// Process
#ifdef __MACOS__
typedef uint32_t WTProcessID; // actually pid_t which is __darwin_pid_t which is __uint32_t
#endif
#ifdef _WINDOWS
typedef int WTProcessID;
#endif
#ifdef __linux__
typedef uint32_t WTProcessID;
#endif
enum WEManagerInitOptions
{
eUnknown_ManagerInitOption,
eMacOS_Carbon_Runtime,
eMacOS_Cocoa_Runtime,
eLinuxOS_gtk_Runtime,
eLinuxOS_X_Runtime,
eWindowsOS_GoodOld_Runtime, // good old windows API
eWindowsOS_DotNET_Runtime,
eVerticalFliped_Graphics,
eInit_RM,
eInit_GMConfig,
eInit_PVM,
eInit_UM,
eInit_BKG
};
#ifdef __MACOS__
#if __LP64__ || NS_BUILD_32_LIKE_64 // in 64bit (or when NS_BUILD_32_LIKE_64 is specified) we decline Carbon implementation.
const WEManagerInitOptions eDefaultRuntime = eMacOS_Cocoa_Runtime;
#else
const WEManagerInitOptions eDefaultRuntime = eMacOS_Carbon_Runtime;
#endif
#endif
#ifdef _WINDOWS
const WEManagerInitOptions eDefaultRuntime = eWindowsOS_GoodOld_Runtime;
#endif
#ifdef __linux__
const WEManagerInitOptions eDefaultRuntime = eLinuxOS_gtk_Runtime;
#endif
//********************************************************************************
// Files
const uint32_t kMaxPathLength = 1023; // maximum length of a path
const uint32_t kMaxFileNameLength = 255; // maximum length of a file name including extension
typedef WCFixedString<kMaxPathLength> WTPathString;
typedef WCFixedString<kMaxFileNameLength> WTFileNameString;
typedef uint64_t WTFileSize;
const WTFileSize kIllegalFileSize = (WTFileSize)-1;
typedef off_t WTFileOffset;
typedef std::time_t WTFileTime;
const WTFileTime kIllegalFileTime = (WTFileTime)-1;
typedef struct WTPathType* WTPathRef; // represents a path, path need not exists
typedef struct WTOpenFileType* WTOpenFileRef; // represents a real, open file
typedef struct WTNativeDLLRefType* WTNativeDLLRef; // define WTNativeDLLRef as a unique type CFBundleRef on Mac, HINSTANCE on Windows
const WTNativeDLLRef kIllegalNativeDLLRef = 0;
//********************************************************************************
// Resources
const size_t kMaxResTypeLength = 31;
typedef WCFixedString31 WTResType;
typedef short WTResID;
const WTResID kIllegalResID = -1;
typedef struct WTResContainerType* WTResContainerRef;
typedef struct WTResourceType* WTResRef;
const WTResContainerRef kIllegalContainerRef = 0;
const WTResRef kIllegalResourceRef = 0;
#ifdef __MACOS__
typedef struct WTNativeResourceType* WTNativeResourceRef; // for use when need to have access to the native resource without going though resource manager caching anf conversion.
const WTNativeResourceRef kIllegalNativeResourceRef = 0;
#endif
#ifdef _WINDOWS
typedef struct WTNativeResourceType* WTNativeResourceRef; //HGLOBAL // for use when need to have access to the native resource without going though resource manager caching anf conversion.
const WTNativeResourceRef kIllegalNativeResourceRef = 0;
#endif
#ifdef __linux__
typedef void* WTNativeResourceRef; // WTOpenFileRef // for use when need to have access to the native resource without going though resource manager caching anf conversion.
const WTNativeResourceRef kIllegalNativeResourceRef = 0;
#endif
//********************************************************************************
// OpenGL
typedef struct WCOGLContext* WCOGLContextRef;
typedef struct WCOGLTexture* WCOGLTextureRef;
typedef struct WSPluginView* WCPluginViewRef;
typedef struct WSMenu* WCMenuRef;
typedef struct WCPluginNativeView* WCPluginNativeViewRef;
const WCOGLContextRef kIllegalOGLContextRef = 0;
const WCOGLTextureRef kIllegalOGLTextureRef = 0;
const WCPluginViewRef kIllegalPluginViewRef = 0;
const WCMenuRef kIllegalWCMenuRef = 0;
const intptr_t kIllegalTexturesMaster = -1;
typedef unsigned int WTTextureRef;
const WTTextureRef kIllegalTextureRef = 0;
// type for storing pointer to functions. Used to avoid warning such as "C++ forbids conversion between pointer to function and pointer to object"
typedef void (*DUMMY_FUNC_PTR)(void);
// type for a generic callback function with one parameter
typedef intptr_t (*CALLBACK_1_PARAM_FUNC_PTR)(intptr_t);
//////////////////////////////////////////////////////////////
// Timer
typedef intptr_t WTTimerRef;
const WTTimerRef kIllegalTimerRef = 0;
typedef void (*WTTimerCallback)(intptr_t);
// generic type for OS native pointer
typedef void* WTPtr;
#endif //__WUTypes_h__

View file

@ -0,0 +1,53 @@
/*
* basics.hpp
* Akupara
*
* Created by Udi on 12/19/06.
* Copyright 2006 __MyCompanyName__. All rights reserved.
*
*/
#if !defined(_AKUPARA_BASICS_HPP__INCLUDED_)
#define _AKUPARA_BASICS_HPP__INCLUDED_
#include "WavesPublicAPI/wstdint.h"
namespace Akupara
{
// The ultimate nothingness
// This is useful for writing constructors that nullify their object, and for testing nullness
struct null_type
{
null_type() {}
null_type(const null_type *) {} // this allows 0 to be implicitly converted to null_type
};
inline null_type null() { return null_type(); }
// This is a byte, guaranteed to be unsigned regardless of your compiler's char signedness
typedef uint8_t byte_type;
// derive from this if your class needs to be noncopyable
class noncopyable_type
{
private:
noncopyable_type(const noncopyable_type &);
noncopyable_type &operator=(const noncopyable_type &);
public:
noncopyable_type() {}
};
} // namespace Akupara
#if defined(__GNUC__)
#define AKUPARA_EXPECT_FALSE(x) __builtin_expect(x,false)
#define AKUPARA_EXPECT_TRUE(x) __builtin_expect(x,true )
#else
#define AKUPARA_EXPECT_FALSE(x) x
#define AKUPARA_EXPECT_TRUE(x) x
#endif // __GNUC__
#endif // _AKUPARA_BASICS_HPP__INCLUDED_

View file

@ -0,0 +1,205 @@
/*
* compiletime_functions.hpp
* Akupara
*
* Created by Udi on 12/19/06.
*
*/
#if !defined(_AKUPARA_COMPILETIME_FUNCTIONS_HPP__INCLUDED_)
#define _AKUPARA_COMPILETIME_FUNCTIONS_HPP__INCLUDED_
//#include "WavesPublicAPIs/wstdint.h"
namespace Akupara
{
// For templates that "return" a value, use template_name<arguments>::value
// For templates that "return" a type, use template_name<arguments>::type
// Integer log2 functions
//------------------------------------------------------------------------
template<unsigned int n>
struct compiletime_bit_count_to_represent { static const unsigned int value = 1+compiletime_bit_count_to_represent<(n>>1)>::value; };
template<>
struct compiletime_bit_count_to_represent<0> { static const unsigned int value = 0; };
//------------------------------------------------------------------------
template<unsigned int n>
struct compiletime_log2_ceiling { static const unsigned int value=compiletime_bit_count_to_represent<n-1>::value; };
template<>
struct compiletime_log2_ceiling<0> {}; // no value for 0 argument
//------------------------------------------------------------------------
template<unsigned int n>
struct compiletime_log2_floor { static const unsigned int value=compiletime_bit_count_to_represent<n>::value-1; };
template<>
struct compiletime_log2_floor<0> {}; // no value for 0 argument
//------------------------------------------------------------------------
// Assertion - accessing 'value' will generate a compile-time error if the argument evaluates to false
//------------------------------------------------------------------------
template<bool>
struct compiletime_assert;
template<>
struct compiletime_assert<true> { static const bool value=true; };
template<>
struct compiletime_assert<false> {}; // no value member for false assertion -> compile time error
//------------------------------------------------------------------------
// Select type - selects one of two types based on a boolean
//------------------------------------------------------------------------
template<bool, typename, typename>
struct compiletime_select_type;
template<typename _true_type, typename _false_type>
struct compiletime_select_type<true, _true_type, _false_type> { typedef _true_type type; };
template<typename _true_type, typename _false_type>
struct compiletime_select_type<false, _true_type, _false_type> { typedef _false_type type; };
//------------------------------------------------------------------------
// Integer types by byte count
//------------------------------------------------------------------------
namespace detail
{
template<unsigned int _size, bool _signed>
struct integer_with_byte_count_base;
template<>
struct integer_with_byte_count_base<1,true> { typedef int8_t type; };
template<>
struct integer_with_byte_count_base<2,true> { typedef int16_t type; };
template<>
struct integer_with_byte_count_base<4,true> { typedef int32_t type; };
template<>
struct integer_with_byte_count_base<8,true> { typedef int64_t type; };
template<>
struct integer_with_byte_count_base<1,false> { typedef uint8_t type; };
template<>
struct integer_with_byte_count_base<2,false> { typedef uint16_t type; };
template<>
struct integer_with_byte_count_base<4,false> { typedef uint32_t type; };
template<>
struct integer_with_byte_count_base<8,false> { typedef uint64_t type; };
} // namespace detail
//------------------------------------------------------------------------
template<unsigned int _size, bool _signed=true>
struct integer_with_byte_count : public detail::integer_with_byte_count_base<_size,_signed>
{
typedef typename detail::integer_with_byte_count_base<_size,_signed>::type type; // not required but makes the statement below less messy
static const bool s_correct_size = compiletime_assert<sizeof(type)==_size>::value; // if you get a compilation error here then integer_with_byte_count is not defined correctly
};
//------------------------------------------------------------------------
template<unsigned int _size>
struct signed_integer_with_byte_count : public integer_with_byte_count<_size,true> {};
template<unsigned int _size>
struct unsigned_integer_with_byte_count : public integer_with_byte_count<_size,false> {};
//------------------------------------------------------------------------
// The following are TR1 compatible, until we get decent TR1 library support on all platforms
//------------------------------------------------------------------------
template<typename _T, _T _v>
struct integral_constant
{
static const _T value = _v;
typedef _T value_type;
typedef integral_constant<_T, _v> type;
}; // struct integral_constant
typedef integral_constant<bool, false> false_type;
typedef integral_constant<bool, true > true_type;
//------------------------------------------------------------------------
template<typename _T, typename _U> struct is_same : public false_type {};
template<typename _T> struct is_same<_T,_T> : public true_type {};
//------------------------------------------------------------------------
// These are NOT TR1 but make use of some TR1 stuff
//------------------------------------------------------------------------
namespace detail
{
struct no_type; // if you end up getting this type, it means that you asked for something that doesn't exist
template<unsigned int _pair_index> struct signed_unsigned_pair;
#define AKUPARA_SIGNED_UNSIGNED_INTEGER_PAIR(index, base_type_name) \
template<> struct signed_unsigned_pair<index> { typedef signed base_type_name signed_type; typedef unsigned base_type_name unsigned_type; };
#define AKUPARA_SIGNED_UNSIGNED_FLOAT_PAIR(index, type_name) \
template<> struct signed_unsigned_pair<index> { typedef type_name signed_type; typedef no_type unsigned_type; };
AKUPARA_SIGNED_UNSIGNED_INTEGER_PAIR(1, char )
AKUPARA_SIGNED_UNSIGNED_INTEGER_PAIR(2, short )
AKUPARA_SIGNED_UNSIGNED_INTEGER_PAIR(3, int )
//AKUPARA_SIGNED_UNSIGNED_INTEGER_PAIR(4, int32_t )// 64BitConversion
template<>
struct
signed_unsigned_pair<4>
{
typedef int32_t signed_type;
typedef uint32_t unsigned_type;
};
AKUPARA_SIGNED_UNSIGNED_INTEGER_PAIR(5, long long)
AKUPARA_SIGNED_UNSIGNED_FLOAT_PAIR (6, float )
AKUPARA_SIGNED_UNSIGNED_FLOAT_PAIR (7, double )
AKUPARA_SIGNED_UNSIGNED_FLOAT_PAIR (8, long double)
const unsigned int k_signed_unsigned_pair_count = 8;
// eliminate the no_type type
template<typename _T> struct filtered_type { typedef _T type; };
template<> struct filtered_type<no_type> {}; // no type defined
// search for _T in signed type list
template<unsigned int _index, typename _T> struct find_in_signed_type_list_from_index
{
static const unsigned int value = is_same< _T, typename signed_unsigned_pair<_index>::signed_type >::value ? _index : find_in_signed_type_list_from_index<_index-1,_T>::value;
};
template<typename _T> struct find_in_signed_type_list_from_index<0, _T> { static const unsigned int value = 0; };
template<typename _T> struct find_in_signed_type_list : public find_in_signed_type_list_from_index<k_signed_unsigned_pair_count, _T> {};
// search for _T in unsigned type list
template<unsigned int _index, typename _T> struct find_in_unsigned_type_list_from_index
{
static const unsigned int value = is_same< _T, typename signed_unsigned_pair<_index>::unsigned_type >::value ? _index : find_in_unsigned_type_list_from_index<_index-1,_T>::value;
};
template<typename _T> struct find_in_unsigned_type_list_from_index<0, _T> { static const unsigned int value = 0; };
template<typename _T> struct find_in_unsigned_type_list : public find_in_unsigned_type_list_from_index<k_signed_unsigned_pair_count, _T> {};
template<bool _is_signed, bool _is_unsigned, typename _T> struct equivalent_signed_type;
template<typename _T> struct equivalent_signed_type <true, false, _T> { typedef _T type; };
template<typename _T> struct equivalent_signed_type <false, true, _T> { typedef typename filtered_type< typename signed_unsigned_pair< find_in_unsigned_type_list<_T>::value >::signed_type >::type type; };
template<bool _is_signed, bool _is_unsigned, typename _T> struct equivalent_unsigned_type;
template<typename _T> struct equivalent_unsigned_type<true, false, _T> { typedef typename filtered_type< typename signed_unsigned_pair< find_in_signed_type_list<_T>::value >::unsigned_type >::type type; };
template<typename _T> struct equivalent_unsigned_type<false, true, _T> { typedef _T type; };
} // namespace detail
//------------------------------------------------------------------------
template<typename _T> struct is_signed { static const bool value = detail::find_in_signed_type_list <_T>::value != 0; };
template<typename _T> struct is_unsigned { static const bool value = detail::find_in_unsigned_type_list<_T>::value != 0; };
//------------------------------------------------------------------------
template<typename _T> struct equivalent_signed_type : public detail::equivalent_signed_type < is_signed<_T>::value, is_unsigned<_T>::value, _T > {};
template<typename _T> struct equivalent_unsigned_type : public detail::equivalent_unsigned_type< is_signed<_T>::value, is_unsigned<_T>::value, _T > {};
//------------------------------------------------------------------------
} // namespace Akupara
#endif // _AKUPARA_COMPILETIME_FUNCTIONS_HPP__INCLUDED_

View file

@ -0,0 +1,388 @@
/*
* Akupara/threading/atomic_ops.hpp
*
*
* Created by Udi Barzilai on 06/06.
* Copyright 2006 __MyCompanyName__. All rights reserved.
*
*/
#if !defined(_AKUPARA_THREADING_ATOMIC_OPS_HPP__INCLUDED_)
#define _AKUPARA_THREADING_ATOMIC_OPS_HPP__INCLUDED_
#include "Akupara/basics.hpp" // for EXPECT macro
#include "Akupara/compiletime_functions.hpp" // for TR1 stuff, signed/unsigned stuff
namespace Akupara
{
namespace threading
{
namespace atomic
{
namespace machine
{
// Machine capabilities
// The following templates are specialized by the machine-specific headers to indicate
// the capabilities of the machine being compiled for. A true 'value' member for a given
// byte count means that there is an implementation of the corresponding atomic operation.
//-------------------------------------
template<unsigned int _byte_count> struct implements_load : public false_type {}; // simple assignment from memory (assumes naturally aligned address)
template<unsigned int _byte_count> struct implements_store : public false_type {}; // simple assignment to memory (assumes naturally aligned address)
template<unsigned int _byte_count> struct implements_CAS : public false_type {}; // compare_and_store()
template<unsigned int _byte_count> struct implements_LL_SC : public false_type {}; // load_linked(), store_conditional()
template<unsigned int _byte_count> struct implements_add : public false_type {}; // add(), subtract()
template<unsigned int _byte_count> struct implements_fetch_and_add : public false_type {}; // fetch_and_add(), fetch_and_subtract()
template<unsigned int _byte_count> struct implements_add_and_fetch : public false_type {}; // add_and_fetch(), subtract_and_fetch()
//-------------------------------------
//-------------------------------------
// functions in this namespace may or may not be implemented, for any integer types, as specified by the machine capabilities templates above
template<typename _integer_type> bool compare_and_store(volatile _integer_type * operand_address, const _integer_type & expected_value, const _integer_type & value_to_store);
template<typename _integer_type> _integer_type load_linked(volatile _integer_type * operand_address);
template<typename _integer_type> bool store_conditional(volatile _integer_type * operand_address, const _integer_type & value_to_store);
template<typename _integer_type> void add(volatile _integer_type * operand_address, const _integer_type & addend);
template<typename _integer_type> void subtract(volatile _integer_type * operand_address, const _integer_type & subtrahend);
template<typename _integer_type> _integer_type fetch_and_add(volatile _integer_type * operand_address, const _integer_type & addend);
template<typename _integer_type> _integer_type fetch_and_subtract(volatile _integer_type * operand_address, const _integer_type & subtrahend);
template<typename _integer_type> _integer_type add_and_fetch(volatile _integer_type * operand_address, const _integer_type & addend);
template<typename _integer_type> _integer_type subtract_and_fetch(volatile _integer_type * operand_address, const _integer_type & subtrahend);
void memory_barrier_read();
void memory_barrier_write();
void memory_barrier_readwrite();
//-------------------------------------
} // namespace machine
} // namespace atomic
} // namespace threading
} // namespace Akupara
// Include the machine-specific implementations; these only implement the templates above for some of the _signed_ integer types
#if defined(__GNUC__) && defined(__POWERPC__)
#include "atomic_ops_gcc_ppc.hpp"
#endif // defined(__GNUC__) && defined(__POWERPC__)
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
#include "atomic_ops_gcc_x86.hpp"
#endif // defined(__GNUC__) && defined(__i386__)
#if defined(_MSC_VER) && defined(_M_IX86)
#include "atomic_ops_msvc_x86.hpp"
#endif // defined(_MSC_VER) && defined(_M_IX86)
#if defined(_MSC_VER) && defined(_M_X64)
#include "atomic_ops_msvc_x86_64.hpp"
#endif // defined(_MSC_VER) && defined(_M_X64)
namespace Akupara
{
namespace threading
{
namespace atomic
{
// Select the most convenient atomic integer type based on the machine's ability to load/store atomically
// The definition below selects that largest atomically accessible integer up to the size of int
//----------------------------------------------------------------------------------------
namespace detail
{
template<unsigned int _byte_count>
struct largest_atomic_byte_count_upto
{
static const unsigned int value =
machine::implements_load<_byte_count>::value && machine::implements_store<_byte_count>::value ?
_byte_count :
largest_atomic_byte_count_upto<_byte_count/2>::value;
};
template<>
struct largest_atomic_byte_count_upto<0> { static const unsigned int value = 0; };
const unsigned int k_byte_count_best_atomic = largest_atomic_byte_count_upto<sizeof(int)>::value;
}
typedef signed_integer_with_byte_count< detail::k_byte_count_best_atomic >::type signed_integer_type;
typedef unsigned_integer_with_byte_count< detail::k_byte_count_best_atomic >::type unsigned_integer_type;
typedef signed_integer_type integer_type;
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
// These need to be implemented by all machines
using machine::memory_barrier_read;
using machine::memory_barrier_write;
using machine::memory_barrier_readwrite;
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
// These may or may not be implemented, but if they aren't, we can't help much
using machine::load_linked;
using machine::store_conditional;
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
// CAS implementation
namespace detail
{
template<
typename _integer_type,
bool _implements_CAS = machine::implements_CAS <sizeof(_integer_type)>::value,
bool _implements_LL_SC = machine::implements_LL_SC<sizeof(_integer_type)>::value>
struct implementation_CAS
{
static const bool s_exists = false;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specialization for native CAS support
template<typename _integer_type, bool _implements_LL_SC>
struct implementation_CAS<_integer_type, true, _implements_LL_SC>
{
static const bool s_exists = true;
static inline bool compare_and_store(volatile _integer_type * operand_address, const _integer_type & expected_value, const _integer_type & value_to_store)
{
return machine::compare_and_store(operand_address, expected_value, value_to_store);
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specialization for cases with no CAS but with LL/SC
template<typename _integer_type>
struct implementation_CAS<_integer_type, false, true>
{
static const bool s_exists = true;
static inline bool compare_and_store(volatile _integer_type * operand_address, const _integer_type & expected_value, const _integer_type & value_to_store)
{
while (machine::load_linked(operand_address) == expected_value)
if (AKUPARA_EXPECT_TRUE(machine::store_conditional(operand_address, value_to_store)))
return true;
return false;
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
} // namespace detail
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template<typename _integer_type>
inline bool compare_and_store(volatile _integer_type * operand_address, const _integer_type & expected_value, const _integer_type & value_to_store)
{
// if your compiler can't find the function to call here then there is no implementation available for your machine
return detail::implementation_CAS<_integer_type>::compare_and_store(operand_address, expected_value, value_to_store);
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
// fetch_and_add
namespace detail
{
template<
typename _integer_type,
bool _0 = machine::implements_fetch_and_add<sizeof(_integer_type)>::value,
bool _1 = machine::implements_add_and_fetch<sizeof(_integer_type)>::value,
bool _2 = machine::implements_LL_SC <sizeof(_integer_type)>::value,
bool _3 = machine::implements_CAS <sizeof(_integer_type)>::value>
struct implementation_FAA
{
static const bool s_exists = false;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specialization for native support
template<typename _integer_type, bool _1, bool _2, bool _3>
struct implementation_FAA<_integer_type, true, _1, _2, _3>
{
static const bool s_exists = true;
static inline _integer_type fetch_and_add(volatile _integer_type * operand_address, const _integer_type & addend)
{
return machine::fetch_and_add(operand_address, addend);
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specialization using add_and_fetch
template<typename _integer_type, bool _2, bool _3>
struct implementation_FAA<_integer_type, false, true, _2, _3>
{
static const bool s_exists = true;
static inline _integer_type fetch_and_add(volatile _integer_type * operand_address, const _integer_type & addend)
{
return machine::add_and_fetch(operand_address, addend) - addend;
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specialization using LL/SC
template<typename _integer_type, bool _3>
struct implementation_FAA<_integer_type, false, false, true, _3>
{
static const bool s_exists = true;
static inline _integer_type fetch_and_add(volatile _integer_type * operand_address, const _integer_type & addend)
{
_integer_type old_value;
do
old_value = machine::load_linked(operand_address);
while (!machine::store_conditional(operand_address, old_value+addend));
return old_value;
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specialization using CAS
template<typename _integer_type>
struct implementation_FAA<_integer_type, false, false, false, true>
{
static const bool s_exists = true;
static inline _integer_type fetch_and_add(volatile _integer_type * operand_address, const _integer_type & addend)
{
_integer_type old_value;
do
old_value = *operand_address;
while (!machine::compare_and_store(operand_address, old_value, old_value+addend));
return old_value;
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
} // namespace detail
template<typename _integer_type>
inline _integer_type fetch_and_add(volatile _integer_type * operand_address, const _integer_type & addend)
{
// if your compiler can't find the function to call here then there is no implementation available for your machine
return detail::implementation_FAA<_integer_type>::fetch_and_add(operand_address, addend);
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
// add_and_fetch
namespace detail
{
template<
typename _integer_type,
bool _0 = machine::implements_add_and_fetch<sizeof(_integer_type)>::value,
bool _1 = machine::implements_fetch_and_add<sizeof(_integer_type)>::value,
bool _2 = machine::implements_LL_SC <sizeof(_integer_type)>::value,
bool _3 = machine::implements_CAS <sizeof(_integer_type)>::value>
struct implementation_AAF
{
static const bool s_exists = false;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specialization for native support
template<typename _integer_type, bool _1, bool _2, bool _3>
struct implementation_AAF<_integer_type, true, _1, _2, _3>
{
static const bool s_exists = true;
static inline _integer_type add_and_fetch(volatile _integer_type * operand_address, const _integer_type & addend)
{
return machine::add_and_fetch(operand_address, addend);
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specialization using add_and_fetch
template<typename _integer_type, bool _2, bool _3>
struct implementation_AAF<_integer_type, false, true, _2, _3>
{
static const bool s_exists = true;
static inline _integer_type add_and_fetch(volatile _integer_type * operand_address, const _integer_type & addend)
{
return machine::fetch_and_add(operand_address, addend) + addend;
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specialization using LL/SC
template<typename _integer_type, bool _3>
struct implementation_AAF<_integer_type, false, false, true, _3>
{
static const bool s_exists = true;
static inline _integer_type add_and_fetch(volatile _integer_type * operand_address, const _integer_type & addend)
{
_integer_type new_value;
do
new_value = machine::load_linked(operand_address)+addend;
while (!machine::store_conditional(operand_address, new_value));
return new_value;
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// specialization using CAS
template<typename _integer_type>
struct implementation_AAF<_integer_type, false, false, false, true>
{
static const bool s_exists = true;
static inline _integer_type add_and_fetch(volatile _integer_type * operand_address, const _integer_type & addend)
{
_integer_type old_value, new_value;
do
old_value = *operand_address, new_value = old_value + addend;
while (!machine::compare_and_store(operand_address, old_value, new_value));
return new_value;
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
} // namespace detail
template<typename _integer_type>
inline _integer_type add_and_fetch(volatile _integer_type * operand_address, const _integer_type & addend)
{
// if your compiler can't find the function to call here then there is no implementation available for your machine
return detail::implementation_AAF<_integer_type>::add_and_fetch(operand_address, addend);
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
// add
template<typename _integer_type>
inline void add(volatile _integer_type * operand_address, const _integer_type & addend)
{
if (machine::implements_add<sizeof(_integer_type)>::value)
machine::add(operand_address, addend);
else if (machine::implements_fetch_and_add<sizeof(_integer_type)>::value)
machine::fetch_and_add(operand_address, addend);
else if (machine::implements_add_and_fetch<sizeof(_integer_type)>::value)
machine::add_and_fetch(operand_address, addend);
else
fetch_and_add(operand_address, addend); // this will simulate using CAS or LL/SC (or it will fail the compilation if neither is available)
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
// TODO: this is where we add implementations for:
// - functions not implemented by the machine
// - functions that take unsigned types (routed to call the signed versions with appropriate conversions)
// For now we add nothing, so developers will need to stick to what their machine can do, and use signed
// integers only.
using machine::subtract;
using machine::subtract_and_fetch;
using machine::fetch_and_subtract;
//----------------------------------------------------------------------------------------
//---------------------------------------------------------------------
template<class _base_type, unsigned int _bytes_per_cache_line=machine::k_bytes_per_cache_line>
struct pad_to_cache_line : public _base_type
{
private:
typedef pad_to_cache_line this_type;
typedef _base_type base_type;
public:
static const unsigned int s_bytes_per_cache_line = _bytes_per_cache_line;
private:
int m_padding[(s_bytes_per_cache_line - sizeof(base_type))/sizeof(int)];
public:
pad_to_cache_line() {}
template<typename _arg_type> pad_to_cache_line(_arg_type arg) : base_type(arg) {}
};
//---------------------------------------------------------------------
} // namespace atomic
} // namespace threading
} // namespace Akupara
#endif // _AKUPARA_THREADING_ATOMIC_OPS_HPP__INCLUDED_

View file

@ -0,0 +1,201 @@
/*
* Akupara/threading/atomic_ops_gcc_x86.hpp
*
*
* Created by Udi Barzilai on 06/06.
* Copyright 2006 __MyCompanyName__. All rights reserved.
*
*/
#if !defined(_AKUPARA_THREADING_ATOMIC_OPS_GCC_X86_HPP__INCLUDED_)
# define _AKUPARA_THREADING_ATOMIC_OPS_GCC_X86_HPP__INCLUDED_
# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
namespace Akupara
{
namespace threading
{
namespace atomic
{
namespace machine
{
const unsigned int k_bytes_per_cache_line = 64; // this is true for P4 & K8
// Flags for operations supported by this machine
//-------------------------------------
template<> struct implements_load <4> : public true_type {};
template<> struct implements_store <4> : public true_type {};
template<> struct implements_CAS <4> : public true_type {};
template<> struct implements_CAS <8> : public true_type {};
template<> struct implements_add <4> : public true_type {};
template<> struct implements_fetch_and_add<4> : public true_type {};
//-------------------------------------
// CAS
//--------------------------------------------------------------------------------
template<>
inline bool compare_and_store<int64_t>(volatile int64_t * p, const int64_t & x, const int64_t & y)
{
register int32_t evh=int32_t(x>>32), evl=int32_t(x);
register const int32_t nvh=int32_t(y>>32), nvl=int32_t(y);
register bool result;
__asm__ __volatile__ (
"# CAS64\n"
" lock \n"
" cmpxchg8b %[location] \n"
" sete %[result] \n"
: [location] "+m" (*p), [result] "=qm" (result), [expected_value_high] "+d" (evh), [expected_value_low] "+a" (evl)
: [new_value_high] "c" (nvh), [new_value_low] "b" (nvl)
: "cc"
);
return result;
}
//--------------------------------------------------------------------------------
template<>
inline bool compare_and_store<int32_t>(volatile int32_t *p, const int32_t & x, const int32_t & y)
{
register int32_t expected_value = x;
register bool result;
__asm__ __volatile__ (
"# CAS32\n"
" lock \n"
" cmpxchgl %[new_value],%[operand] \n"
" sete %[result] \n"
: [operand] "+m" (*p), [result] "=qm" (result), [expected_value] "+a" (expected_value)
: [new_value] "r" (y)
: "cc"
);
return result;
}
//--------------------------------------------------------------------------------
// Atomic add/sub
//--------------------------------------------------------------------------------
inline void increment(volatile int32_t * operand_address)
{
__asm__ __volatile__ (
"# atomic_increment_32\n"
" lock; \n"
" incl %[operand]; \n"
: [operand] "+m" (*operand_address)
:
: "cc"
);
}
//--------------------------------------------------------------------------------
inline void decrement(volatile int32_t * operand_address)
{
__asm__ __volatile__ (
"# atomic_decrement_32\n"
" lock; \n"
" decl %[operand]; \n"
: [operand] "+m" (*operand_address)
:
: "cc"
);
}
//--------------------------------------------------------------------------------
template<>
inline void add<int32_t>(volatile int32_t * operand_address, const int32_t & addend)
{
if (__builtin_constant_p(addend) && addend==1)
increment(operand_address);
else if (__builtin_constant_p(addend) && addend==-1)
decrement(operand_address);
else
__asm__ __volatile__ (
"# atomic_add_32 \n"
" lock \n"
" addl %[addend], %[operand] \n"
: [operand] "+m" (*operand_address)
: [addend] "ir" (addend)
: "cc"
);
}
//--------------------------------------------------------------------------------
template<>
inline void subtract<int32_t>(volatile int32_t * operand_address, const int32_t & subtrahend)
{
if (__builtin_constant_p(subtrahend) && subtrahend==1)
decrement(operand_address);
else if (__builtin_constant_p(subtrahend) && subtrahend==-1)
increment(operand_address);
else
__asm__ __volatile__ (
"# atomic_subtract_32 \n"
" lock \n"
" subl %[subtrahend], %[operand] \n"
: [operand] "+m" (*operand_address)
: [subtrahend] "ir" (subtrahend)
: "cc"
);
}
//--------------------------------------------------------------------------------
// Atomic fetch and add/sub
//--------------------------------------------------------------------------------
template<>
inline int32_t fetch_and_add<int32_t>(volatile int32_t * operand_address, const int32_t & addend)
{
register int32_t addend_and_fetched = addend;
__asm__ __volatile__ (
"# atomic_fetch_and_add_32 \n"
" lock; \n"
" xaddl %[addend], %[operand]; \n"
: [operand] "+m" (*operand_address), [addend] "+r" (addend_and_fetched)
:
: "cc"
);
return addend_and_fetched;
}
//--------------------------------------------------------------------------------
template<>
inline int32_t fetch_and_subtract<int32_t>(volatile int32_t * operand_address, const int32_t & subtrahend)
{
return fetch_and_add(operand_address, -subtrahend);
}
//--------------------------------------------------------------------------------
// Memory barriers
//--------------------------------------------------------------------------------
inline void memory_barrier_readwrite()
{
#if _AKUPARA_X86_SSE_NOT_AVAILABLE
__asm__ __volatile__ (" lock; addl $0,0(%%esp); # memory_barrier_readwrite" : : : "memory");
#else
__asm__ __volatile__ (" mfence; # memory_barrier_readwrite" : : : "memory");
#endif // _LOCKFREE_ATOMIC_OPS_X86_LFENCE_NOT_AVAILABLE
}
//--------------------------------------------------------------------------------
inline void memory_barrier_read()
{
#if _AKUPARA_X86_SSE_NOT_AVAILABLE
__asm__ __volatile__ (" lock; addl $0,0(%%esp); # memory_barrier_read" : : : "memory");
#else
__asm__ __volatile__ (" lfence; # memory_barrier_read" : : : "memory");
#endif // _LOCKFREE_ATOMIC_OPS_X86_LFENCE_NOT_AVAILABLE
}
//--------------------------------------------------------------------------------
inline void memory_barrier_write()
{
__asm__ __volatile__ (" sfence; # memory_barrier_write" : : : "memory");
}
//--------------------------------------------------------------------------------
} // namespace machine
} // namespace atomic
} // namespace threading
} // namespace Akupara
# endif // defined(__GNUC__) && defined(__i386__)
#endif // _AKUPARA_THREADING_ATOMIC_OPS_GCC_X86_HPP__INCLUDED_

View file

@ -0,0 +1,49 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __IncludeWindows_h__
#define __IncludeWindows_h__
#ifdef _WINDOWS
/* Copy to include
#include "IncludeWindows.h"
*/
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0601 // Windows 7
#endif
#ifndef WINVER
#define WINVER 0x0601 // Windows 7
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX // DO NOT REMOVE NOMINMAX - DOING SO CAUSES CONFLICTS WITH STD INCLUDES (<limits> ...)
#endif
#include <WinSock2.h>
#include <Windows.h>
#include <objbase.h>
#endif // #if _WINDOWS
#endif // #ifndef __IncludeWindows_h__

View file

@ -0,0 +1,743 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//----------------------------------------------------------------------------------
//
//
//! \file WCMRAudioDeviceManager.cpp
//!
//! WCMRAudioDeviceManager and related class declarations
//!
//---------------------------------------------------------------------------------*/
#include "WCMRAudioDeviceManager.h"
//**********************************************************************************************
// WCMRAudioDevice::WCMRAudioDevice
//
//! Constructor for the audio device. The derived classes will need to do more actual work, such
//! as determining supported sampling rates, buffer sizes, and channel counts. Connection
//! and streaming will also be provided by the derived implementations.
//!
//! \param *pManager : The audio device manager that's managing this device.
//!
//! \return Nothing.
//!
//**********************************************************************************************
WCMRAudioDevice::WCMRAudioDevice (WCMRAudioDeviceManager *pManager)
{
m_pMyManager = pManager;
m_DeviceName = "Unknown";
m_ConnectionStatus = DeviceDisconnected;
m_IsActive = false;
m_IsStreaming = false;
m_CurrentSamplingRate = -1;
m_CurrentBufferSize = 0;
m_LeftMonitorChannel = -1;
m_RightMonitorChannel = -1;
m_MonitorGain = 1.0f;
}
//**********************************************************************************************
// WCMRAudioDevice::~WCMRAudioDevice
//
//! Destructor for the audio device. It release all the connections that were created.
//!
//! \param none
//!
//! \return Nothing.
//!
//**********************************************************************************************
WCMRAudioDevice::~WCMRAudioDevice ()
{
AUTO_FUNC_DEBUG;
try
{
}
catch (...)
{
//destructors should absorb exceptions, no harm in logging though!!
DEBUG_MSG ("Exception during destructor");
}
}
//**********************************************************************************************
// WCMRAudioDevice::DeviceName
//
//! Retrieves Device's name.
//!
//! \param none
//!
//! \return The device name.
//!
//**********************************************************************************************
const std::string& WCMRAudioDevice::DeviceName () const
{
return (m_DeviceName);
}
//**********************************************************************************************
// WCMRAudioDevice::InputChannels
//
//! Retrieves Input Channel information. Note that the list may be changed at run-time.
//!
//! \param none
//!
//! \return A vector with Input Channel Names.
//!
//**********************************************************************************************
const std::vector<std::string>& WCMRAudioDevice::InputChannels ()
{
return (m_InputChannels);
}
//**********************************************************************************************
// WCMRAudioDevice::OutputChannels
//
//! Retrieves Output Channel Information. Note that the list may be changed at run-time.
//!
//! \param none
//!
//! \return A vector with Output Channel Names.
//!
//**********************************************************************************************
const std::vector<std::string>& WCMRAudioDevice::OutputChannels ()
{
return (m_OutputChannels);
}
//**********************************************************************************************
// WCMRAudioDevice::SamplingRates
//
//! Retrieves supported sampling rate information.
//!
//! \param none
//!
//! \return A vector with supported sampling rates.
//!
//**********************************************************************************************
const std::vector<int>& WCMRAudioDevice::SamplingRates ()
{
return (m_SamplingRates);
}
//**********************************************************************************************
// WCMRAudioDevice::CurrentSamplingRate
//
//! The device's current sampling rate. This may be overridden, if the device needs to
//! query the driver for the current rate.
//!
//! \param none
//!
//! \return The device's current sampling rate. -1 on error.
//!
//**********************************************************************************************
int WCMRAudioDevice::CurrentSamplingRate ()
{
return (m_CurrentSamplingRate);
}
//**********************************************************************************************
// WCMRAudioDevice::SetCurrentSamplingRate
//
//! Change the sampling rate to be used by the device. This will most likely be overridden,
//! the base class simply updates the member variable.
//!
//! \param newRate : The rate to use (samples per sec).
//!
//! \return eNoErr always. The derived classes may return error codes.
//!
//**********************************************************************************************
WTErr WCMRAudioDevice::SetCurrentSamplingRate (int newRate)
{
//changes the status.
m_CurrentSamplingRate = newRate;
return (eNoErr);
}
//**********************************************************************************************
// WCMRAudioDevice::BufferSizes
//
//! Retrieves supported buffer size information.
//!
//! \param none
//!
//! \return A vector with supported buffer sizes.
//!
//**********************************************************************************************
const std::vector<int>& WCMRAudioDevice::BufferSizes ()
{
return (m_BufferSizes);
}
//**********************************************************************************************
// WCMRAudioDevice::CurrentBufferSize
//
//! The device's current buffer size in use. This may be overridden, if the device needs to
//! query the driver for the current size.
//!
//! \param none
//!
//! \return The device's current buffer size. 0 on error.
//!
//**********************************************************************************************
int WCMRAudioDevice::CurrentBufferSize ()
{
return (m_CurrentBufferSize);
}
//**********************************************************************************************
// WCMRAudioDevice::CurrentBlockSize
//
//! Device's block size we use for holding the audio samples.
//! Usually this is equal to the buffer size, but in some cases the buffer size holds additional
//! data other then the audio buffers, like frames info in SG, so it can be overriden
//!
//! \param none
//!
//! \return The device's current block size. 0 on error.
//!
//**********************************************************************************************
int WCMRAudioDevice::CurrentBlockSize()
{
// By default - return the buffer size
return CurrentBufferSize();
}
//**********************************************************************************************
// WCMRAudioDevice::SetCurrentBufferSize
//
//! Change the buffer size to be used by the device. This will most likely be overridden,
//! the base class simply updates the member variable.
//!
//! \param newSize : The buffer size to use (in sample-frames)
//!
//! \return eNoErr always. The derived classes may return error codes.
//!
//**********************************************************************************************
WTErr WCMRAudioDevice::SetCurrentBufferSize (int newSize)
{
//This will most likely be overridden, the base class simply
//changes the member.
m_CurrentBufferSize = newSize;
return (eNoErr);
}
//**********************************************************************************************
// WCMRAudioDevice::ConnectionStatus
//
//! Retrieves the device's current connection status. This will most likely be overridden,
//! in case some driver communication is required to query the status.
//!
//! \param none
//!
//! \return A ConnectionStates value.
//!
//**********************************************************************************************
WCMRAudioDevice::ConnectionStates WCMRAudioDevice::ConnectionStatus ()
{
return (m_ConnectionStatus);
}
//**********************************************************************************************
// WCMRAudioDevice::Active
//
//! Retrieves Device activation status.
//!
//! \param none
//!
//! \return true if device is active, false otherwise.
//!
//**********************************************************************************************
bool WCMRAudioDevice::Active ()
{
return (m_IsActive);
}
//**********************************************************************************************
// WCMRAudioDevice::SetActive
//
//! Sets the device's activation status.
//!
//! \param newState : Should be true to activate, false to deactivate. This roughly corresponds
//! to opening and closing the device handle/stream/audio unit.
//!
//! \return eNoErr always, the derived classes may return appropriate error code.
//!
//**********************************************************************************************
WTErr WCMRAudioDevice::SetActive (bool newState)
{
//This will most likely be overridden, the base class simply
//changes the member.
m_IsActive = newState;
return (eNoErr);
}
//**********************************************************************************************
// WCMRAudioDevice::Streaming
//
//! Retrieves Device streaming status.
//!
//! \param none
//!
//! \return true if device is streaming, false otherwise.
//!
//**********************************************************************************************
bool WCMRAudioDevice::Streaming ()
{
return (m_IsStreaming);
}
//**********************************************************************************************
// WCMRAudioDevice::SetStreaming
//
//! Sets the device's streaming status.
//!
//! \param newState : Should be true to start streaming, false to stop streaming. This roughly
//! corresponds to calling Start/Stop on the lower level interface.
//!
//! \return eNoErr always, the derived classes may return appropriate error code.
//!
//**********************************************************************************************
WTErr WCMRAudioDevice::SetStreaming (bool newState)
{
//This will most likely be overridden, the base class simply
//changes the member.
m_IsStreaming = newState;
return (eNoErr);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// IsProcessActive - returns true if process code is running.
// A normal audio device should return the Streaming() value
///////////////////////////////////////////////////////////////////////////////////////////////////////
bool WCMRAudioDevice::IsProcessActive()
{
return Streaming();
}
//**********************************************************************************************
// WCMRAudioDevice::DoIdle
//
//! A place for doing idle time processing. The derived classes will probably do something
//! meaningful.
//!
//! \param none
//!
//! \return eNoErr always.
//!
//**********************************************************************************************
WTErr WCMRAudioDevice::DoIdle ()
{
//We don't need to do anything here...
//the derived classes may want to use this however.
return (eNoErr);
}
//**********************************************************************************************
// WCMRAudioDevice::InputLevels
//
//! Retrieve current input levels.
//!
//! \param none
//!
//! \return A vector (the same size as input channels list) that contains current input levels.
//!
//**********************************************************************************************
const std::vector<float>& WCMRAudioDevice::InputLevels ()
{
//The derived classes may override if they need to query
//the driver for the levels.
return (m_InputLevels);
}
//**********************************************************************************************
// WCMRAudioDevice::OutputLevels
//
//! Retrieve current output levels.
//!
//! \param none
//!
//! \return A vector (the same size as output channels list) that contains current output levels.
//!
//**********************************************************************************************
const std::vector<float>& WCMRAudioDevice::OutputLevels ()
{
//The derived classes may override if they need to query
//the driver for the levels.
return (m_OutputLevels);
}
//**********************************************************************************************
// WCMRAudioDevice::GetMonitorInfo
//
//! Retrieves current monitoring information.
//!
//! \param *pLeftChannel : Pointer to receive left monitor channel index.
//! \param *pRightChannel : Pointer to receive right monitor channel index.
//! \param *pGain : Pointer to receive the gain (linear) to be applied.
//!
//! \return Nothing.
//!
//**********************************************************************************************
void WCMRAudioDevice::GetMonitorInfo (int *pLeftChannel, int *pRightChannel, float *pGain)
{
if (pLeftChannel)
*pLeftChannel = m_LeftMonitorChannel;
if (pRightChannel)
*pRightChannel = m_RightMonitorChannel;
if (pGain)
*pGain = m_MonitorGain;
return;
}
//**********************************************************************************************
// WCMRAudioDevice::SetMonitorChannels
//
//! Used to set the channels to be used for monitoring.
//!
//! \param leftChannel : Left monitor channel index.
//! \param rightChannel : Right monitor channel index.
//!
//! \return eNoErr always, the derived classes may return appropriate errors.
//!
//**********************************************************************************************
WTErr WCMRAudioDevice::SetMonitorChannels (int leftChannel, int rightChannel)
{
//This will most likely be overridden, the base class simply
//changes the member.
m_LeftMonitorChannel = leftChannel;
m_RightMonitorChannel = rightChannel;
return (eNoErr);
}
//**********************************************************************************************
// WCMRAudioDevice::SetMonitorGain
//
//! Used to set monitor gain (or atten).
//!
//! \param newGain : The new gain or atten. value to use. Specified as a linear multiplier (not dB)
//!
//! \return eNoErr always, the derived classes may return appropriate errors.
//!
//**********************************************************************************************
WTErr WCMRAudioDevice::SetMonitorGain (float newGain)
{
//This will most likely be overridden, the base class simply
//changes the member.
m_MonitorGain = newGain;
return (eNoErr);
}
//**********************************************************************************************
// WCMRAudioDevice::ShowConfigPanel
//
//! Used to show device specific config/control panel. Some interfaces may not support it.
//! Some interfaces may require the device to be active before it can display a panel.
//!
//! \param pParam : A device/interface specific parameter - optional.
//!
//! \return eNoErr always, the derived classes may return errors.
//!
//**********************************************************************************************
WTErr WCMRAudioDevice::ShowConfigPanel (void *WCUNUSEDPARAM(pParam))
{
//This will most likely be overridden...
return (eNoErr);
}
//**********************************************************************************************
// WCMRAudioDevice::SendCustomCommand
//
//! Used to Send a custom command to the audiodevice. Some interfaces may require the device
//! to be active before it can do anything in this.
//!
//! \param customCommand : A device/interface specific command.
//! \param pCommandParam : A device/interface/command specific parameter - optional.
//!
//! \return eNoErr always, the derived classes may return errors.
//!
//**********************************************************************************************
WTErr WCMRAudioDevice::SendCustomCommand (int WCUNUSEDPARAM(customCommand), void *WCUNUSEDPARAM(pCommandParam))
{
//This will most likely be overridden...
return (eNoErr);
}
//**********************************************************************************************
// WCMRAudioDevice::GetLatency
//
//! Get Latency for device.
//!
//! Use 'kAudioDevicePropertyLatency' and 'kAudioDevicePropertySafetyOffset' + GetStreamLatencies
//!
//! \param isInput : Return latency for the input if isInput is true, otherwise the output latency
//! wiil be returned.
//! \return Latency in samples.
//!
//**********************************************************************************************
uint32_t WCMRAudioDevice::GetLatency (bool isInput)
{
//This will most likely be overridden...
return 0;
}
//**********************************************************************************************
// WCMRAudioDeviceManager::WCMRAudioDeviceManager
//
//! The constructuor, most of the work will be done in the derived class' constructor.
//!
//! \param *pTheClient :
//!
//! \return Nothing.
//!
//**********************************************************************************************
WCMRAudioDeviceManager::WCMRAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter)
: m_pTheClient (pTheClient)
, m_eAudioDeviceFilter(eCurAudioDeviceFilter)
{
//The derived classes will do lot more init!
return;
}
//**********************************************************************************************
// WCMRAudioDeviceManager::~WCMRAudioDeviceManager
//
//! It clears the device list, releasing each of the device.
//!
//! \param none
//!
//! \return Nothing.
//!
//**********************************************************************************************
WCMRAudioDeviceManager::~WCMRAudioDeviceManager()
{
AUTO_FUNC_DEBUG;
try
{
//Need to call release on our devices, and erase them from list
std::vector<WCMRAudioDevice*>::iterator deviceIter;
while (m_Devices.size())
{
WCMRAudioDevice *pDeviceToRelease = m_Devices.back();
m_Devices.pop_back();
if (pDeviceToRelease)
SAFE_RELEASE (pDeviceToRelease);
}
//The derived classes may want to do additional de-int!
}
catch (...)
{
//destructors should absorb exceptions, no harm in logging though!!
DEBUG_MSG ("Exception during destructor");
}
}
//**********************************************************************************************
// WCMRAudioDeviceManager::DoIdle_Private
//
//! Used for idle time processing. This calls each device's DoIdle so that it can perform it's own idle processing.
//!
//! \param none
//!
//! \return noErr if no devices have returned an error. An error code if any of the devices returned error.
//!
//**********************************************************************************************
WTErr WCMRAudioDeviceManager::DoIdle_Private()
{
WTErr retVal = eNoErr;
//Need to call DoIdle of all our devices...
std::vector<WCMRAudioDevice*>::iterator deviceIter;
for (deviceIter = m_Devices.begin(); deviceIter != m_Devices.end(); deviceIter++)
{
WTErr thisDeviceErr = (*deviceIter)->DoIdle();
if (thisDeviceErr != eNoErr)
retVal = thisDeviceErr;
}
return (retVal);
}
//**********************************************************************************************
// WCMRAudioDeviceManager::Devices_Private
//
//! Retrieve list of devices managed by this manager.
//!
//! \param none
//!
//! \return A vector containing the list of devices.
//!
//**********************************************************************************************
const WCMRAudioDeviceList& WCMRAudioDeviceManager::Devices_Private() const
{
return (m_Devices);
}
//**********************************************************************************************
// *WCMRAudioDeviceManager::GetDeviceByName_Private
//
//! Locates a device based on device name.
//!
//! \param nameToMatch : Device to look for.
//!
//! \return Pointer to the device object if found, NULL otherwise.
//!
//**********************************************************************************************
WCMRAudioDevice *WCMRAudioDeviceManager::GetDeviceByName_Private(const std::string& nameToMatch) const
{
//Need to check all our devices...
WCMRAudioDevice *pRetVal = NULL;
WCMRAudioDeviceListConstIter deviceIter;
for (deviceIter = m_Devices.begin(); deviceIter != m_Devices.end(); deviceIter++)
{
if ((*deviceIter)->DeviceName() == nameToMatch)
{
pRetVal = *deviceIter;
break;
}
}
return (pRetVal);
}
//**********************************************************************************************
// *WCMRAudioDeviceManager::GetDefaultDevice
//
//! Locates a device based on device name.
//!
//! \param nameToMatch : Device to look for.
//!
//! \return Pointer to the device object if found, NULL otherwise.
//!
//**********************************************************************************************
WCMRAudioDevice *WCMRAudioDeviceManager::GetDefaultDevice_Private()
{
//Need to check all our devices...
WCMRAudioDevice *pRetVal = NULL;
WCMRAudioDeviceListIter deviceIter = m_Devices.begin();
if(deviceIter != m_Devices.end())
{
pRetVal = *deviceIter;
}
return (pRetVal);
}
//**********************************************************************************************
// WCMRAudioDeviceManager::NotifyClient
//
//! A helper routine used to call the client for notification.
//!
//! \param forReason : The reason for notification.
//! \param *pParam : A parameter (if required) for notification.
//!
//! \return Nothing.
//!
//**********************************************************************************************
void WCMRAudioDeviceManager::NotifyClient (WCMRAudioDeviceManagerClient::NotificationReason forReason, void *pParam)
{
if (m_pTheClient)
m_pTheClient->AudioDeviceManagerNotification (forReason, pParam);
return;
}

View file

@ -0,0 +1,266 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//----------------------------------------------------------------------------------
//
//
//! \file WCMRAudioDeviceManager.h
//!
//! WCMRAudioDeviceManager and related class declarations
//!
//---------------------------------------------------------------------------------*/
#ifndef __WCMRAudioDeviceManager_h_
#define __WCMRAudioDeviceManager_h_
/* Copy to include
#include "WCMRAudioDeviceManager.h"
*/
#define AUTO_FUNC_DEBUG
#define DEBUG_MSG(a)
#define ASSERT_ERROR(a, b)
#define TRACE_MSG(a)
#include <string>
#include <vector>
#include <map>
#include "WCRefManager.h"
#include "BasicTypes/WUTypes.h"
#include "WUErrors.h"
#define WCUNUSEDPARAM(a)
//forward decl.
class WCMRAudioConnection;
class WCMRAudioDevice;
class WCMRAudioDeviceManager;
typedef std::vector<WCMRAudioDevice *> WCMRAudioDeviceList; ///< Vector for audio devices
typedef std::vector<WCMRAudioDevice *>::iterator WCMRAudioDeviceListIter; ///< Vector iterator for audio devices
typedef std::vector<WCMRAudioDevice *>::const_iterator WCMRAudioDeviceListConstIter; ///< Vector iterator for audio devices
typedef std::vector<WCMRAudioConnection *> WCMRAudioConnectionsList; ///< Vector for audio devices
/// for notification... A client must derive it's class from us.
class WCMRAudioDeviceManagerClient
{
public:
enum NotificationReason
{
DeviceListChanged,
Dropout,
RequestReset,
RequestResync,
SamplingRateChanged, //param has new SR, or -1 if not known
SamplingRateChangedSilent, //To indicate sampling rate changed but no need to notify user
BufferSizeChanged,
ClockSourceChanged,
DeviceStoppedStreaming,
DeviceDroppedSamples,
DeviceConnectionLost,
DeviceGenericError,
DeviceStatusChanged,
DeviceStatisticsUpdated,
DeviceDebugInfo, //param has c string
DeviceProgressInfo, //param has c string
MIDIData,
MIDINodeUp,
MIDINodeDown,
DeviceSampleRateMisMatch,
SystemSamplingRateChangedInfoOnly,
LostClockSource,
IODeviceDisconnected,
ChannelCountModified,
MasterUp,
MasterDown,
AudioDropFound,
ReflasherEvent,
AGDeviceSamplingRateChangedInfoOnly,
IODeviceNameChanged,
SetDisplayNameFromIOModule,
IOMStateChanged, ///< This is used when IOM state is changed.
AudioCallback // VKamyshniy: param is AudioCallbackDataData*
};
WCMRAudioDeviceManagerClient () {}
virtual ~WCMRAudioDeviceManagerClient () {}
// VKamyshniy: This is a structure to call the client's AudioDeviceManagerNotification
// every AudioCallback time
struct AudioCallbackData
{
const float *acdInputBuffer;
float *acdOutputBuffer;
size_t acdFrames;
uint32_t acdSampleTime;
uint64_t acdCycleStartTimeNanos;
};
virtual void AudioDeviceManagerNotification (NotificationReason WCUNUSEDPARAM(reason), void *WCUNUSEDPARAM(pParam)) {}
};
class WCMRAudioDevice : public WCRefManager
{
public:
enum ConnectionStates
{
DeviceAvailable,
DeviceDisconnected,
DeviceError
};
WCMRAudioDevice (WCMRAudioDeviceManager *pManager);///<Constructor
virtual ~WCMRAudioDevice ();///<Destructor
virtual const std::string& DeviceName() const;///<Name?
virtual const std::vector<std::string>& InputChannels();///<Current Input Channel List? - note that this may change with change in sampling rate.
virtual const std::vector<std::string>& OutputChannels();///<Current Output Channel List? - note that this may change with change in sampling rate.
virtual const std::vector<int>& SamplingRates();///<Supported Sampling Rate List?
virtual int CurrentSamplingRate(); ///<Current Sampling rate.?
virtual WTErr SetCurrentSamplingRate(int newRate);///<Change Current Sampling Rate : This is a requset, might not be successful at run time!
virtual const std::vector<int>& BufferSizes();///<Supported Buffer Size List? - note that this may change with change in sampling rate.
virtual int CurrentBufferSize();///<Current Buffer Size.? - note that this may change with change in sampling rate.
virtual WTErr SetCurrentBufferSize (int newSize);///<Change Current Buffer Size : This is a requset, might not be successful at run time!
virtual int CurrentBlockSize();
virtual ConnectionStates ConnectionStatus();///< Connection Status - device available, gone, disconnected
virtual bool Active();///<Active status - mainly significant for ASIO, as certain ops can only be performed on active devices!
virtual WTErr SetActive (bool newState);///<Prepare/Activate device.
virtual bool Streaming();///<Streaming Status?
virtual WTErr SetStreaming (bool newState);///<Start/Stop Streaming - should reconnect connections when streaming starts!
virtual bool IsProcessActive();
virtual WTErr DoIdle();///<Do Idle Processing
virtual const std::vector<float>& InputLevels();///<Retrieve Input Levels (for VU display)?
virtual const std::vector<float>& OutputLevels();///<Retrieve Output Levels (for VU display)?
void GetMonitorInfo (int *pLeftChannel = NULL, int *pRightChannel = NULL, float *pGain = NULL);///<Retrieve current monitor channel pair and gain - optional, will not be available with AG
virtual WTErr SetMonitorChannels (int leftChannel, int rightChannel);///<Set monitor channels. - optional, will not be available with AG
virtual WTErr SetMonitorGain (float newGain);///<Set monitor gain. - optional, will not be available with AG
virtual WTErr ShowConfigPanel (void *pParam);///< Show Control Panel - in case of ASIO this will work only with Active device!
virtual WTErr SendCustomCommand (int customCommand, void *pCommandParam); ///< Send a custom command to the audiodevice...
virtual uint32_t GetLatency (bool isInput); ///Get latency.
protected:
WCMRAudioDeviceManager *m_pMyManager; ///< The manager who's managing this device, can be used for sending notifications!
std::string m_DeviceName; ///< Name of the device.
std::vector<std::string> m_InputChannels; ///< List of input channel names.
std::vector<std::string> m_OutputChannels; ///< List of output channel names.
std::vector<int> m_SamplingRates; ///< List of available sampling rates.
std::vector<int> m_BufferSizes; ///< List of available buffer sizes.
int m_CurrentSamplingRate; ///< Currently selected sampling rate.
int m_CurrentBufferSize; ///< Currently selected buffer size.
ConnectionStates m_ConnectionStatus; ///< Status of device connection
bool m_IsActive; ///< Flag for teh active status.
bool m_IsStreaming; ///< Flag for streaming status.
std::vector<float> m_InputLevels; ///< List of input levels.
std::vector<float> m_OutputLevels; ///< List of output levels.
int m_LeftMonitorChannel; ///< The device channel to use for monitoring left channel data.
int m_RightMonitorChannel; ///< The device channel to use for monitoring right channel data.
float m_MonitorGain; ///< Amount of gain to apply for monitoring signal.
};
// This enum is for choosing filter for audio devices scan
typedef enum eAudioDeviceFilter
{
eAllDevices = 0, // Choose all audio devices
eInputOnlyDevices, // Choose only input audio devices
eOutputOnlyDevices, // Choose only output audio devices
eFullDuplexDevices, // Choose audio devices that have both input and output channels on the same device
eMatchedDuplexDevices, // Match(aggregate) audio devices that have both input and output channels but are considered different audio devices (For mac)
eAudioDeviceFilterNum // Number of enums
} eAudioDeviceFilter;
//! WCMRAudioDeviceManager
/*! The Audio Device Manager class */
class WCMRAudioDeviceManager : public WCRefManager
{
private://< Private version of class functions which will be called by class's public function after mutex lock acquistion.
WCMRAudioDevice* GetDefaultDevice_Private();
WTErr DoIdle_Private();
const WCMRAudioDeviceList& Devices_Private() const;
WCMRAudioDevice* GetDeviceByName_Private(const std::string & nameToMatch) const;
public://< Public functions for the class.
WCMRAudioDevice* GetDefaultDevice()
{
//wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
return GetDefaultDevice_Private();
}
virtual WTErr DoIdle()
{
//wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
return DoIdle_Private();
}
const WCMRAudioDeviceList& Devices() const
{
//wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
return Devices_Private();
}
WCMRAudioDevice* GetDeviceByName(const std::string & nameToMatch) const
{
//wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
return GetDeviceByName_Private(nameToMatch);
}
public:
WCMRAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter
); ///< constructor
virtual ~WCMRAudioDeviceManager(void); ///< Destructor
virtual WTErr UpdateDeviceList () = 0; //has to be overridden!
//This is primarily for use by WCMRAudioDevice and it's descendants... We could have made it
//protected and made WCMRAudioDevice a friend, and then in some way found a way to extend
//the friendship to WCMRAudioDevice's descendants, but that would require a lot of extra
//effort!
void NotifyClient (WCMRAudioDeviceManagerClient::NotificationReason forReason, void *pParam = NULL);
virtual void EnableVerboseLogging(bool /*bEnable*/, const std::string& /*logFilePath*/) { };
protected:
//< NOTE : Mutex protection is commented, but wrapper classes are still there, in case they are required in future.
//wvNS::wvThread::ThreadMutex m_AudioDeviceManagerMutex; ///< Mutex for Audio device manager class function access.
WCMRAudioDeviceManagerClient *m_pTheClient; ///< The device manager's client, used to send notifications.
WCMRAudioDeviceList m_Devices; ///< List of all relevant devices devices
eAudioDeviceFilter m_eAudioDeviceFilter; // filter of 'm_Devices'
};
#endif //#ifndef __WCMRAudioDeviceManager_h_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,220 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//----------------------------------------------------------------------------------
//
//
//! \file WCMRCoreAudioDeviceManager.h
//!
//! WCMRCoreAudioDeviceManager and related class declarations
//!
//---------------------------------------------------------------------------------*/
#ifndef __WCMRCoreAudioDeviceManager_h_
#define __WCMRCoreAudioDeviceManager_h_
#include "WCMRAudioDeviceManager.h"
#include "WCMRNativeAudio.h"
#include "Threads/WCThreadSafe.h"
#include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/AudioToolbox.h>
#include <mach/mach.h>
#include <CoreAudio/CoreAudio.h>
//forward decl.
class WCMRCoreAudioDeviceManager;
#define WV_USE_TONE_GEN 0 ///! Set this to 1 to use a tone generator for input. See description at SetupToneGenerator for details.
// This enum is for choosing filter for audio devices scan
typedef enum eCABS_Method
{
eCABS_Simple = 0,
eCABS_DestructiveCache,
eCABS_CacheOnDeviceSet,
eCABS_MethodNum // Must be last
} eCABS_Method;
//! Manages a port audio device, providing information
//! about the device, and managing audio callbacks.
class WCMRCoreAudioDevice : public WCMRNativeAudioDevice
{
public:
WCMRCoreAudioDevice (WCMRCoreAudioDeviceManager *pManager, AudioDeviceID deviceID, bool useMultithreading = true, bool bNocopy = false);///<Constructor
virtual ~WCMRCoreAudioDevice ();///<Destructor
virtual const std::string& DeviceName() const;///<Name?
virtual const std::vector<std::string>& InputChannels();///<Current Input Channel List? - note that this may change with change in sampling rate.
virtual const std::vector<std::string>& OutputChannels();///<Current Output Channel List? - note that this may change with change in sampling rate.
virtual const std::vector<int>& SamplingRates();///<Supported Sampling Rate List?
virtual int CurrentSamplingRate(); ///<Current Sampling rate.?
virtual WTErr SetCurrentSamplingRate(int newRate);///<Change Current Sampling Rate : This is a requset, might not be successful at run time!
virtual const std::vector<int>& BufferSizes();///<Supported Buffer Size List? - note that this may change with change in sampling rate.
virtual int CurrentBufferSize();///<Current Buffer Size.? - note that this may change with change in sampling rate.
virtual WTErr SetCurrentBufferSize (int newSize);///<Change Current Buffer Size : This is a requset, might not be successful at run time!
virtual ConnectionStates ConnectionStatus();///< Connection Status - device available, gone, disconnected
virtual WTErr SetActive (bool newState);///<Prepare/Activate device.
virtual WTErr SetStreaming (bool newState);///<Start/Stop Streaming - should reconnect connections when streaming starts!
virtual WTErr DoIdle();///<Do Idle Processing
virtual WTErr SetMonitorChannels (int leftChannel, int rightChannel);///<Set monitor channels. - optional, will not be available with AG
virtual WTErr SetMonitorGain (float newGain);///<Set monitor gain. - optional, will not be available with AG
virtual WTErr ShowConfigPanel (void *pParam);///< Show Control Panel - in case of ASIO this will work only with Active device!
virtual int AudioCallback (float *pOutputBuffer, unsigned long framesPerBuffer, uint32_t inSampleTime, uint64_t inCycleStartTime);
AudioDeviceID DeviceID () {return m_DeviceID;}
virtual uint32_t GetLatency (bool isInput); ///< Get latency.
virtual OSStatus GetStreamLatency(AudioDeviceID deviceID, bool isInput, std::vector<int>& latencies);
protected:
AudioDeviceID m_DeviceID; ///< The CoreAudio device id
bool m_StopRequested; ///< should be set to true when want to stop, set to false otherwise.
float *m_pInputData; ///< This is what came in with the most recent callback.
int m_SampleCounter; ///< The current running sample counter, updated by the audio callback.
int m_SampleCountAtLastIdle; ///< What was the sample count last time we checked...
int m_StalledSampleCounter; ///< The number of idle calls with same sample count detected
int m_ChangeCheckCounter; ///< The number of idle calls passed since we checked the buffer size change.
wvNS::wvThread::timestamp m_LastCPULog; ///< The time when the last CPU details log was sent as a notification.
// unsigned int m_IOCyclesTimesTaken[MAX_IOCYCLE_TIMES]; ///< This stores the times taken by each IOCycle, in host-time units.
// int m_CurrentIOCycle; ///< The location in m_IOCyclesTymesTaken array, where the next cycle's value will go.
// int m_CyclesToAccumulate; ///< The number of cycles to accumulate the values for - maximum for last one second.
// unsigned int m_CyclePeriod; ///< The number of host time units for a cycle period - determined by buffer size and sampling rate
AudioBufferList m_InputAudioBufferList; ///< The buffer list used to get AHHAL to render input to.
AudioUnit m_AUHALAudioUnit;///< The AUHAL AudioUnit
int m_BufferSizeChangeRequested;
int m_BufferSizeChangeReported;
int m_ResetRequested;
int m_ResetReported;
int m_ResyncRequested;
int m_ResyncReported;
int m_SRChangeRequested;
int m_SRChangeReported;
int m_DropsDetected; ///< Number of times audio drops have been detected so far.
int m_DropsReported; ///< Number of times audio drops have been reported so far to the client.
bool m_IgnoreThisDrop; ///< Allows disregarding the first drop
thread_t m_IOProcThreadPort; ///< Thread handle to calculate CPU consumption.
int m_CPUCount; ///< Number of processors/core to normalize cpu consumption calculation.
#if WV_USE_TONE_GEN
//The Tone Generator...
float_t *m_pToneData;
uint32_t m_ToneDataSamples;
uint32_t m_NextSampleToUse;
#endif //WV_USE_TONE_GEN
WTErr UpdateDeviceInfo (bool updateSRSupported, bool updateBufferSizes);
WTErr UpdateDeviceName();
WTErr UpdateDeviceInputs();
WTErr UpdateDeviceOutputs();
WTErr UpdateDeviceSampleRates();
WTErr UpdateDeviceBufferSizes();
WTErr SetWorkingBufferSize(int newSize);
OSStatus SetBufferSizesByIO(int newSize);
WTErr SetAndCheckCurrentSamplingRate (int newRate);
WTErr EnableAudioUnitIO();
WTErr virtual EnableListeners();
WTErr virtual DisableListeners();
WTErr SetupAUHAL();
WTErr TearDownAUHAL();
#if WV_USE_TONE_GEN
void SetupToneGenerator ();
#endif //WV_USE_TONE_GEN
static OSStatus StaticAudioIOProc(void *inRefCon, AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList *ioData);
OSStatus AudioIOProc(AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList *ioData);
static OSStatus StaticPropertyChangeProc (AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput,
AudioDevicePropertyID inPropertyID, void *inClientData);
void PropertyChangeProc (AudioDevicePropertyID inPropertyID);
private:
};
//! WCMRCoreAudioDeviceManager
/*! The CoreAudio Device Manager class */
class WCMRCoreAudioDeviceManager : public WCMRAudioDeviceManager
{
public:
WCMRCoreAudioDeviceManager(WCMRAudioDeviceManagerClient *pTheClient, eAudioDeviceFilter eCurAudioDeviceFilter,
bool useMultithreading = true, eCABS_Method eCABS_method = eCABS_Simple, bool bNocopy = false); ///< constructor
virtual ~WCMRCoreAudioDeviceManager(void); ///< Destructor
virtual WTErr UpdateDeviceList() //has to be overridden!
{
//wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
return UpdateDeviceList_Private();
}
virtual eCABS_Method GetBufferSizeMethod()
{
//wvNS::wvThread::ThreadMutex::lock theLock(m_AudioDeviceManagerMutex);
return GetBufferSizeMethod_Private();
}
virtual WTErr DoIdle();
private:
WTErr UpdateDeviceList_Private();
eCABS_Method GetBufferSizeMethod_Private() { return m_eCABS_Method; }
protected:
int m_UpdateDeviceListRequested; ///< Number of times device list change has been detected.
int m_UpdateDeviceListProcessed; ///< Number of times device list change has been processed.
bool m_UseMultithreading; ///< Flag indicates whether to use multi-threading for audio processing.
bool m_bNoCopyAudioBuffer;
eCABS_Method m_eCABS_Method; // Type of core audio buffer size list method
static OSStatus StaticPropertyChangeProc (AudioHardwarePropertyID inPropertyID, void* inClientData);
OSStatus PropertyChangeProc (AudioHardwarePropertyID inPropertyID);
void remove_pattern(const std::string& original_str, const std::string& pattern_str, std::string& return_str);
};
#endif //#ifndef __WCMRCoreAudioDeviceManager_h_

View file

@ -0,0 +1,270 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//----------------------------------------------------------------------------------
//
//
//! \file WCMRNativeAudio.cpp
//!
//! WCMRNativeAudioConnection and related class defienitions
//!
//---------------------------------------------------------------------------------*/
#if defined(__MACOS__)
#include <CoreAudio/CoreAudio.h>
#endif
#include "WCMRNativeAudio.h"
#include "MiscUtils/safe_delete.h"
#include <sstream>
#include <boost/assign/list_of.hpp>
#define NONE_DEVICE_NAME "None"
#define NONE_DEVICE_INPUT_NAMES "Input "
#define NONE_DEVICE_OUTPUT_NAMES "Output "
//**********************************************************************************************
// WCMRNativeAudioNoneDevice::WCMRNativeAudioNoneDevice
//
//! Constructor for the dummy "None" device. This constructor simply adds supported SRs,
//! buffer sizes, and channels, so that it may look like a real native device to
//! the applications.
//!
//! \param pManager : The managing device manager - simply passed on to the base class.
//!
//!
//**********************************************************************************************
WCMRNativeAudioNoneDevice::WCMRNativeAudioNoneDevice (WCMRAudioDeviceManager *pManager)
: WCMRNativeAudioDevice (pManager, false /*useMultiThreading*/)
, m_SilenceThread(0)
#if defined (_WINDOWS)
, _waitableTimerForUsleep (CreateWaitableTimer(NULL, TRUE, NULL))
#endif
{
m_DeviceName = NONE_DEVICE_NAME;
m_SamplingRates = boost::assign::list_of (m_CurrentSamplingRate=44100)(48000)(88200)(96000);
m_BufferSizes = boost::assign::list_of (32)(64)(128)(m_CurrentBufferSize=256)(512)(1024);
for (int channel = 0; channel < __m_NumInputChannels; channel++)
{
std::stringstream name;
name << NONE_DEVICE_INPUT_NAMES;
name << (channel + 1);
m_InputChannels.push_back(name.str());
}
for (int channel = 0; channel < __m_NumOutputChannels; channel++)
{
std::stringstream name;
name << NONE_DEVICE_INPUT_NAMES;
name << (channel + 1);
m_OutputChannels.push_back(name.str());
}
_m_inputBuffer = new float[__m_NumInputChannels * m_BufferSizes.back()];
_m_outputBuffer = new float[__m_NumOutputChannels * m_BufferSizes.back()];
}
WCMRNativeAudioNoneDevice::~WCMRNativeAudioNoneDevice ()
{
#if defined (_WINDOWS)
if(_waitableTimerForUsleep) {
CloseHandle(_waitableTimerForUsleep);
}
#endif
}
WTErr WCMRNativeAudioNoneDevice::SetActive (bool newState)
{
//This will most likely be overridden, the base class simply
//changes the member.
if (Active() == newState)
{
return (eNoErr);
}
if (Active() && Streaming())
{
SetStreaming(false);
}
return WCMRAudioDevice::SetActive(newState);
}
WTErr WCMRNativeAudioNoneDevice::SetCurrentBufferSize (int newSize)
{
//changes the status.
int oldSize = CurrentBufferSize();
bool oldActive = Active();
//same size, nothing to do.
if (oldSize == newSize)
return eNoErr;
//see if this is one of our supported rates...
std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize);
if (intIter == m_BufferSizes.end())
{
//Can't change, perhaps use an "invalid param" type of error
return eCommandLineParameter;
}
if (Streaming())
{
//Can't change, perhaps use an "in use" type of error
return eGenericErr;
}
return WCMRAudioDevice::SetCurrentBufferSize(newSize);
}
WTErr WCMRNativeAudioNoneDevice::SetStreaming (bool newState)
{
if (Streaming() == newState)
{
return (eNoErr);
}
WCMRAudioDevice::SetStreaming(newState);
if(Streaming())
{
if (m_SilenceThread)
std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the inactive NONE-DEVICE was streaming!" << std::endl;
pthread_attr_t attributes;
size_t stack_size = 100000;
#ifdef __MACOS__
stack_size = (((stack_size - 1) / PTHREAD_STACK_MIN) + 1) * PTHREAD_STACK_MIN;
#endif
if (pthread_attr_init (&attributes)) {
std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_attr_init () failed!" << std::endl;
return eGenericErr;
}
if (pthread_attr_setstacksize (&attributes, stack_size)) {
std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_attr_setstacksize () failed!" << std::endl;
return eGenericErr;
}
if (pthread_create (&m_SilenceThread, &attributes, __SilenceThread, this)) {
m_SilenceThread = 0;
std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_create () failed!" << std::endl;
return eGenericErr;
}
}
else
{
if (!m_SilenceThread)
{
std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the active NONE-DEVICE was NOT streaming!" << std::endl;
}
while (m_SilenceThread)
{
_usleep(1); //now wait for ended thread;
}
}
return eNoErr;
}
void WCMRNativeAudioNoneDevice::_SilenceThread()
{
#if defined(_WINDOWS)
float* theInpBuffers[__m_NumInputChannels];
for(int i = 0; i < __m_NumInputChannels; ++i)
{
theInpBuffers[i] = _m_inputBuffer + m_BufferSizes.back() * i;
}
#else
float* theInpBuffers = _m_inputBuffer;
#endif
uint32_t currentSampleTime = 0;
const size_t buffer_size = CurrentBufferSize();
const uint64_t cyclePeriodNanos = (1000000000.0 * buffer_size) / CurrentSamplingRate();
struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData =
{
(const float*)theInpBuffers,
_m_outputBuffer,
buffer_size,
0,
0
};
audioCallbackData.acdCycleStartTimeNanos =__get_time_nanos();
// VERY ROUGH IMPLEMENTATION:
while(Streaming()) {
uint64_t cycleEndTimeNanos = audioCallbackData.acdCycleStartTimeNanos + cyclePeriodNanos;
m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData);
currentSampleTime += buffer_size;
int64_t timeToSleepUsecs = ((int64_t)cycleEndTimeNanos - (int64_t)__get_time_nanos())/1000;
if (timeToSleepUsecs > 0) {
_usleep (timeToSleepUsecs);
}
audioCallbackData.acdCycleStartTimeNanos = cycleEndTimeNanos+1;
}
m_SilenceThread = 0;
}
void* WCMRNativeAudioNoneDevice::__SilenceThread(void *This)
{
((WCMRNativeAudioNoneDevice*)This)->_SilenceThread();
return 0;
}
#if defined(_WINDOWS)
void WCMRNativeAudioNoneDevice::_usleep(uint64_t duration_usec)
{
LARGE_INTEGER ft;
ft.QuadPart = -(10*duration_usec); // Convert to 100 nanosecond interval, negative value indicates relative time
SetWaitableTimer(_waitableTimerForUsleep, &ft, 0, NULL, NULL, 0);
WaitForSingleObject(_waitableTimerForUsleep, INFINITE);
}
#endif
uint64_t
WCMRNativeAudioNoneDevice::__get_time_nanos ()
{
#ifdef __MACOS__
// here we exploit the time counting API which is used by the WCMRCoreAudioDeviceManager. However,
// the API should be a part of WCMRCoreAudioDeviceManager to give a chance of being tied to the
// audio device transport timeß.
return AudioConvertHostTimeToNanos (AudioGetCurrentHostTime ());
#elif _WINDOWS
LARGE_INTEGER Frequency, Count ;
QueryPerformanceFrequency (&Frequency) ;
QueryPerformanceCounter (&Count);
return uint64_t ((Count.QuadPart * 1000000000.0 / Frequency.QuadPart));
#endif
}

View file

@ -0,0 +1,90 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//----------------------------------------------------------------------------------
//
//
//! \file WCMRNativeAudio.h
//!
//! WCMRNativeAudio and related class declarations
//!
//---------------------------------------------------------------------------------*/
#ifndef __WCMRNativeAudio_h_
#define __WCMRNativeAudio_h_
#if defined(_WINDOWS)
#include "windows.h"
#endif
#include "pthread.h"
#include "WCRefManager.h"
#include "WCMRAudioDeviceManager.h"
class WCMRNativeAudioDevice; //forward
class WCMRNativeAudioDevice : public WCMRAudioDevice
{
public:
WCMRNativeAudioDevice (WCMRAudioDeviceManager *pManager, bool useMultithreading = true, bool bNoCopy = false) : WCMRAudioDevice (pManager),
m_UseMultithreading (useMultithreading),
m_bNoCopyAudioBuffer(bNoCopy)
{}
virtual ~WCMRNativeAudioDevice () {}
protected:
bool m_UseMultithreading;
bool m_bNoCopyAudioBuffer; ///< This flag determines whether the audio callback performs a copy of audio, or the source/sink perform the copy. It should be true to let source/sink do the copies.
};
//! A dummy device to allow apps to choose "None" in case no real device connection is required.
class WCMRNativeAudioNoneDevice : public WCMRNativeAudioDevice
{
public:
WCMRNativeAudioNoneDevice (WCMRAudioDeviceManager *pManager);
virtual ~WCMRNativeAudioNoneDevice ();
virtual WTErr SetActive (bool newState);///<Prepare/Activate device.
virtual WTErr SetStreaming (bool newState);///<Start/Stop Streaming - should reconnect connections when streaming starts!
virtual WTErr SetCurrentBufferSize (int newSize);///<Change Current Buffer Size : This is a requset, might not be successful at run time!
private:
static void* __SilenceThread(void *This);
void _SilenceThread();
#if defined(_WINDOWS)
void _usleep(uint64_t usec);
#else
inline void _usleep(uint64_t usec) { ::usleep(usec); }
#endif
static const size_t __m_NumInputChannels = 32;
static const size_t __m_NumOutputChannels = 32;
pthread_t m_SilenceThread;
float *_m_inputBuffer;
float *_m_outputBuffer;
static uint64_t __get_time_nanos ();
#if defined (_WINDOWS)
HANDLE _waitableTimerForUsleep;
#endif
};
#endif //#ifndef __WCMRNativeAudio_h_

View file

@ -0,0 +1,122 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __MinMaxUtilities_h__
#define __MinMaxUtilities_h__
/* copy to include
#include "MiscUtils/MinMaxUtilities.h"
*/
#include "BasicTypes/WUDefines.h"
#include "BasicTypes/WUMathConsts.h"
#include "WavesPublicAPI/wstdint.h"
// New accelerated templates
#if defined ( __cplusplus ) && !defined (__WUMinMax)
#define __WUMinMax // Also defined in Nativepr.h
template<class T> inline T WUMin(const T &a, const T &b) {return (a < b) ? a : b;} // requires only < to be defined for T
template<class T> inline T WUMax(const T &a,const T &b) {return (a < b) ? b : a;} // requires only < to be defined for T
template<class T> inline T WUMinMax(const T &Smallest, const T &Biggest, const T &Val) // requires only < to be defined for T
{
return ((Val < Smallest) ? Smallest : ((Biggest < Val) ? Biggest : Val));
}
/*
// Min and Max
template<class T> inline T WUMin(T a,T b) {return (a < b) ? a : b;} // requires only < to be defined for T
template<class T> inline T WUMax(T a,T b) {return (a < b) ? b : a;} // requires only < to be defined for T
template<class T> inline T WUMinMax(T SMALLEST, T BIGGEST, T X) // requires only < to be defined for T
{
return ((X < SMALLEST) ? SMALLEST : ((BIGGEST < X) ? BIGGEST : X));
}
*/
// Absolute value
#ifdef _WINDOWS
#include <math.h>
#define __abs(x) abs(x)
#define __labs(x) labs(x)
#define __fabs(x) fabs(x)
#endif
#ifdef __GNUC__
#include <iostream> // why don't know makes it work need to check
#include <cstdlib>
#include <cmath>
#define __abs(x) std::abs(x)
#define __labs(x) std::labs(x)
#define __fabs(x) std::fabs(x)
#endif
#ifdef __MACOS__
#ifdef __GNUC__
#include <iostream> // why don't know makes it work need to check
#include <cmath>
#define __abs(x) std::abs(x)
#define __labs(x) std::labs(x)
#define __fabs(x) std::fabs(x)
#endif
#endif
// log2: on Windows there's no proper definition for log2, whereas on other platform there is.
#ifndef WUlog2
#if defined(_WINDOWS)
#define WUlog2(x) (kdOneOverLog2 * log10((x)))
#else
#define WUlog2(x) log2(x)
#endif
#endif
template <class T> inline T WUAbs(const T &xA)
{
return (xA > T(0))? xA: -xA;
}
template <> inline int WUAbs(const int &xA)
{
return __abs(xA);
}
//template <> inline int32_t WUAbs(const int32_t &xA)// 64BitConversion
//{
// return __labs(xA);
//}
template <> inline float WUAbs(const float &xA)
{
return (float) __fabs(xA);
}
template <> inline double WUAbs(const double &xA)
{
return __fabs(xA);
}
#endif
int32_t DllExport WURand(intptr_t in_Seed);
int32_t DllExport WURand();
int32_t DllExport rand_gen_formula(int32_t rndSeed);
template <class T> inline bool WUIsEqualWithTolerance(const T &xA, const T &xB, const T &xTolerance)
{
return (WUAbs(xA - xB) < xTolerance) ? true : false;
}
#endif

View file

@ -0,0 +1,87 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef _WINDOWS
#include "IncludeWindows.h"
#endif
#if defined(__linux__) || defined(__MACOS__)
#include <sys/time.h>
#endif
#include "UMicroseconds.h"
namespace wvNS {
UMicroseconds& UMicroseconds::ReadTime()
{
#ifdef _WINDOWS
LARGE_INTEGER Frequency, Count ;
QueryPerformanceFrequency(&Frequency) ;
QueryPerformanceCounter(&Count);
theTime = uint64_t((Count.QuadPart * 1000000.0 / Frequency.QuadPart));
#endif
#if defined(__linux__) || defined(__MACOS__)
// Mac code replaced by posix calls, to reduce Carbon dependency.
timeval buf;
gettimeofday(&buf,NULL);
// micro sec
theTime = uint64_t(buf.tv_sec) * 1000*1000 + buf.tv_usec;
#endif
return *this;
}
/*
Removed in favor of the posix implementation.
#ifdef __MACOS__
uint32_t UMicroseconds::hi() {return reinterpret_cast<UnsignedWide*>(&theTime)->hi;}
uint32_t UMicroseconds::lo() {return reinterpret_cast<UnsignedWide*>(&theTime)->lo;}
#endif
*/
void UMicrosecondsAccumulator::Start()
{
m_start_time.ReadTime();
}
void UMicrosecondsAccumulator::Stop()
{
UMicroseconds stop_time;
m_accumulator += stop_time.GetNativeTime() - m_start_time.GetNativeTime();
}
void UMicrosecondsAccumulator::Clear()
{
m_start_time = 0;
m_accumulator = 0;
}
UMicroseconds UMicrosecondsAccumulator::GetAccumulatedTime() const
{
return m_accumulator;
}
UMicrosecondsAccumulator& UMicrosecondsAccumulator::operator+=(const UMicrosecondsAccumulator& inaccum_to_add)
{
m_accumulator += inaccum_to_add.GetAccumulatedTime();
return *this;
}
} // namespace wvNS {

View file

@ -0,0 +1,123 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __UMicroseconds_h__
#define __UMicroseconds_h__
/* Copy to include
#include "UMicroseconds.h"
*/
#include "BasicTypes/WUDefines.h"
#include "BasicTypes/WUTypes.h"
namespace wvNS {
// a wraper for Microseconds function from Timer.h
class DllExport UMicroseconds
{
public:
#ifdef _WINDOWS
typedef int64_t TimeKeeper;
#endif
#ifdef __MACOS__
typedef uint64_t TimeKeeper;
#endif
#ifdef __linux__
typedef uint64_t TimeKeeper;
#endif
private:
TimeKeeper theTime;
public:
UMicroseconds()
{
ReadTime();
}
UMicroseconds(const TimeKeeper in_initVal) : theTime(in_initVal) {}
UMicroseconds(const UMicroseconds& inUM) : theTime(inUM.theTime) {}
UMicroseconds& operator=(const UMicroseconds& inUM) {theTime = inUM.theTime; return *this;}
UMicroseconds& operator+=(const TimeKeeper in_timeToAdd) {theTime += in_timeToAdd; return *this;}
UMicroseconds& ReadTime();
TimeKeeper GetNativeTime() const {return theTime;}
operator uint64_t () {return static_cast<uint64_t>(theTime);}
operator double () const {return static_cast<const double>(theTime);}
double Seconds() const {return static_cast<double>(theTime) / double(1000000);}
double MilliSeconds() const {return static_cast<double>(theTime) / double(1000);}
double MicroSeconds() const {return static_cast<double>(theTime);}
#ifdef __MACOS__
uint32_t hi();
uint32_t lo();
#endif
};
inline UMicroseconds operator-(const UMicroseconds& in_one, const UMicroseconds& in_two)
{
UMicroseconds retVal(in_one.GetNativeTime() - in_two.GetNativeTime());
return retVal;
}
class UMicrosecondsAccumulator
{
public:
UMicrosecondsAccumulator() : m_start_time(0), m_accumulator(0) {}
void Start();
void Stop();
void Clear();
UMicroseconds GetAccumulatedTime() const;
UMicrosecondsAccumulator& operator+=(const UMicrosecondsAccumulator&);
protected:
UMicroseconds m_start_time;
UMicroseconds m_accumulator;
};
inline UMicroseconds operator-(const UMicrosecondsAccumulator& in_one, const UMicrosecondsAccumulator& in_two)
{
UMicroseconds retVal(in_one.GetAccumulatedTime() - in_two.GetAccumulatedTime());
return retVal;
}
//=========================================================================================//
inline void MicrosecondDelay(double amt)
//=========================================================================================//
{
UMicroseconds than;
UMicroseconds now;
do
{
now.ReadTime();
} while ((now.MicroSeconds() - than.MicroSeconds()) < amt);
}
} // namespace wvNS {
#endif //#ifndef __UMicroseconds_h__

View file

@ -0,0 +1,903 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __WCFixedString_h__
#define __WCFixedString_h__
/* Copy to include.
#include "WCFixedString.h"
*/
// do not #include anything else here but standard C++ library files, this file should be free from any and all depandencies
// do not put any DEBUG_s or TRACE_s in this file, since it is used in BgkConsole functions
#include <algorithm>
#include <cctype>
#include <cstring>
#include <cstdio>
#ifdef __MACOS__
#include <strings.h>
#endif
#include "BasicTypes/WUDefines.h"
#include "BasicTypes/WTByteOrder.h"
#include "WavesPublicAPI/wstdint.h"
#include "MiscUtils/MinMaxUtilities.h"
// use this macro instead of std :: string to mark the that use of std :: string could not be replaced
// by WFixedString.
#define std_string_approved std::string
#ifdef __POSIX__
const char* const kStrNewLine = "\n";
#endif
#ifdef _WINDOWS
const char* const kStrNewLine = "\r\n";
#endif
class DllExport WCFixedStringBase
{
public:
typedef size_t pos_t;
typedef intptr_t spos_t; // signed position, defined to intptr_t because Windows does not have ssize_t
static const pos_t npos = UINTPTR_MAX; // Same as size_max
WCFixedStringBase(char* const in_begin, const size_t in_MaxFixedStringLength) :
m_begin(in_begin),
m_MaxFixedStringLength(in_MaxFixedStringLength),
m_end(in_begin)
{
*m_end = '\0';
}
inline WCFixedStringBase& operator=(const WCFixedStringBase& in_fixedStrToAssign)
{
if (this != &in_fixedStrToAssign)
{
clear();
operator<<(in_fixedStrToAssign);
}
return *this;
}
inline WCFixedStringBase& operator=(const char* in_CStrToAssign)
{
clear();
operator<<(in_CStrToAssign);
return *this;
}
inline WCFixedStringBase& operator=(const char in_charToAssign)
{
clear();
operator<<(in_charToAssign);
return *this;
}
char operator[](const pos_t in_index) const
{
if (in_index < m_MaxFixedStringLength)
return m_begin[in_index];
else
return m_begin[m_MaxFixedStringLength]; // in_index was too big
}
char& operator[](const pos_t in_index)
{
if (in_index < m_MaxFixedStringLength)
return m_begin[in_index];
else
return m_begin[m_MaxFixedStringLength]; // in_index was too big
}
inline size_t resize(const size_t in_newSize)
{
m_end = m_begin + WUMin<size_t>(in_newSize, m_MaxFixedStringLength);
*m_end = '\0';
return size();
}
size_t max_size()
{
return m_MaxFixedStringLength;
}
size_t capacity()
{
return m_MaxFixedStringLength;
}
inline char * peek()
{
return m_begin;
}
inline const char * c_str() const
{
*m_end = '\0';
return m_begin;
}
inline void clear()
{
m_end = m_begin;
*m_end = '\0';
}
inline size_t size() const
{
return m_end - m_begin;
}
inline char* begin() const
{
return m_begin;
}
inline char* end() const
{
return m_end;
}
inline size_t length() const
{
return size();
}
inline bool empty() const
{
return m_begin == m_end;
}
inline void reverse(char* in_left, char* in_right)
{
char* left = in_left;
char* right = in_right;
while (left < right)
{
char temp = *--right;
*right = *left;
*left++ = temp;
}
}
inline void reverse()
{
reverse(m_begin, m_end);
}
inline void to_lower()
{
char* pToDo = m_begin;
while (pToDo < m_end)
{
*pToDo = static_cast<char>(std::tolower(*pToDo));
++pToDo;
}
}
inline void to_upper()
{
char* pToDo = m_begin;
while (pToDo < m_end)
{
*pToDo = static_cast<char>(std::toupper(*pToDo));
++pToDo;
}
}
// append a single char in_count times
inline void append(const char in_charToAppend, const size_t in_count)
{
size_t counter = 0;
while ((m_end < m_begin+m_MaxFixedStringLength) && counter++ < in_count)
*m_end++ = in_charToAppend;
#if kEnableDebug == 1
if (counter < in_count) // if there wasn't enough room for some appended chars
{
m_begin[0] = '@'; // mark the string as overflowed
}
#endif
*m_end = '\0';
}
inline void append(const char* in_chars)
{
operator<<(in_chars);
}
// append "iterator style"
inline void append(const char* in_chars_begin, const char* in_chars_end)
{
const char* curr_char = in_chars_begin;
while ((m_end < m_begin+m_MaxFixedStringLength) && curr_char < in_chars_end && *curr_char != '\0')
*m_end++ = *curr_char++;
#if kEnableDebug == 1
if (curr_char < in_chars_end) // if there wasn't enough room for some appended chars
{
m_begin[0] = '@'; // mark the string as overflowed
}
#endif
*m_end = '\0';
}
// append from a char* in_count chars, (no \0 is required to terminate the input string)
inline void append(const char* in_chars_begin, const size_t in_count)
{
append(in_chars_begin, in_chars_begin + in_count);
}
// assign from a char* in_count chars, (no \0 is required to terminate the input string)
inline void assign(const char* in_chars_begin, const size_t in_count)
{
clear();
append(in_chars_begin, in_chars_begin + in_count);
}
// assign from a char* , (a \0 is required to terminate the input string)
inline void assign(const char* in_chars_ptr)
{
clear();
operator<<(in_chars_ptr);
}
// assign from a char* to a char*
inline void assign(const char* in_begin, const char* in_end)
{
assign(in_begin, size_t(in_end - in_begin));
}
inline void append_double_with_precision(const double in_double, const int in_precision)
{
const unsigned int tempBufSize = 32;
char buf[tempBufSize];
#ifdef _WINDOWS
_snprintf_s(buf, tempBufSize, tempBufSize - 1, "%.*f", in_precision, in_double);
#endif
#ifdef __MACOS__
std::snprintf(buf, tempBufSize, "%.*f", in_precision, in_double);
#endif
#ifdef __linux__
snprintf(buf, tempBufSize, "%.*f", in_precision, in_double);
#endif
operator<<(buf);
}
inline void append_uint(const uint64_t in_uint, const int_fast16_t in_base = 10)
{
uint_fast64_t num = in_uint;
char* lasr_char_before = m_end;
do {
char remainder(static_cast<char>(num % in_base));
if ( remainder < 10 )
operator<<(char(remainder + '0'));
else
operator<<(char(remainder - 10 + 'A'));
num /= in_base;
} while (num != 0);
reverse(lasr_char_before, m_end);
}
inline void append_hex_binary(const uint8_t* in_binary, const size_t in_size)
{
static const char hexdigits[] = "0123456789ABCDEF";
#if _BYTEORDER_BIG_ENDIAN==1
for (size_t ibyte = 0; ibyte < in_size; ++ibyte)
#elif _BYTEORDER_BIG_ENDIAN==0
for (size_t ibyte = in_size; ibyte > 0; --ibyte)
#endif
{
operator<<(hexdigits[in_binary[ibyte - 1] >> 4]);
operator<<(hexdigits[in_binary[ibyte - 1] & 0x0F]);
}
}
inline WCFixedStringBase& operator<<(const char in_charToAppend)
{
if (m_end < m_begin+m_MaxFixedStringLength)
*m_end++ = in_charToAppend;
#if kEnableDebug == 1
else // if there wasn't enough room for the appended char
{
m_begin[0] = '@'; // mark the string as overflowed
}
#endif
*m_end = '\0';
return *this;
}
inline WCFixedStringBase& operator<<(const char* const in_strToAppend)
{
if (0 != in_strToAppend)
{
const char* pSource = in_strToAppend;
while (*pSource != '\0' && m_end < m_begin+m_MaxFixedStringLength)
*m_end++ = *pSource++;
#if kEnableDebug == 1
if (*pSource != '\0') // if there wasn't enough room for some appended chars
{
m_begin[0] = '@'; // mark the string as overflowed
}
#endif
*m_end = '\0';
}
return *this;
}
WCFixedStringBase& operator<<(const uint64_t in_uint)
{
append_uint(in_uint, 10);
return *this;
}
// Warning prevention: the operator<< function overload for unsigneds used to create lots
// of warnings once size_t usage was becoming widespread. So for each OS we define only
// those overloads that are actually needed. On Windows 32 bit we still get
// 'warning C4267: 'argument' : conversion from 'size_t' to 'const unsigned int', possible loss of data'
// warning which we do not know how to solve yet. The function DummyFunctionsForWarningTest
// in file WCFixedStringStream.cpp calls all combinations of operator<<(unsigned something)
// And should produce no warnings - (except the C4267 on windows).
#if defined(__MACOS__) // both 32 & 64 bit
WCFixedStringBase& operator<<(const size_t in_uint) {
return operator<<(static_cast<unsigned long long>(in_uint));
}
#endif
// WCFixedStringBase& operator<<(const unsigned char in_uint) {
// return operator<<(static_cast<const unsigned long long>(in_uint));
// }
//
// WCFixedStringBase& operator<<(const size_t in_uint) {
// return operator<<(static_cast<const uint64_t>(in_uint));
// }
//
#if defined(__MACOS__) || defined(_WINDOWS) || defined(__linux__) // both 32 & 64 bit
WCFixedStringBase& operator<<(const unsigned int in_uint) {
return operator<<(static_cast<uint64_t>(in_uint));
}
#endif
//
#if defined(_WINDOWS) || defined(__linux__) // both 32 & 64 bit
WCFixedStringBase& operator<<(const unsigned long in_uint) {
return operator<<(static_cast<uint64_t>(in_uint));
}
#endif
WCFixedStringBase& operator<<(const long long in_int)
{
if (in_int < 0)
operator<<('-');
#ifdef _WINDOWS
// uintmax_t unsigned_in_num = _abs64(in_int);
uintmax_t unsigned_in_num = in_int < 0 ? static_cast<uintmax_t>(-in_int) : static_cast<uintmax_t>(in_int);
#else
uintmax_t unsigned_in_num = std::abs(in_int);
#endif
append_uint(unsigned_in_num, 10);
return *this;
}
WCFixedStringBase& operator<<(const short in_int) {
return operator<<(static_cast<int64_t>(in_int));
}
WCFixedStringBase& operator<<(const int in_int) {
return operator<<(static_cast<int64_t>(in_int));
}
WCFixedStringBase& operator<<(const long in_int) {
return operator<<(static_cast<int64_t>(in_int));
}
WCFixedStringBase& operator<<(const double in_doubleToWrite)
{
append_double_with_precision(in_doubleToWrite, 10);
return *this;
}
WCFixedStringBase& operator<<(const float in_floatToWrite)
{
append_double_with_precision(double(in_floatToWrite), 5);
return *this;
}
inline WCFixedStringBase& operator<<(const WCFixedStringBase& in_fixedStrToAppend)
{
operator<<(in_fixedStrToAppend.c_str());
return *this;
}
WCFixedStringBase& operator<< (bool abool)
{
return abool ? operator<<("true") : operator<<("false");
}
template<typename T> WCFixedStringBase& operator+=(T in_type)
{
return operator<<(in_type);
}
ptrdiff_t compare(const char* in_to_compare) const
{
ptrdiff_t retVal = 1;
if (0 != in_to_compare)
{
retVal = strcmp(c_str(), in_to_compare);
}
return retVal;
}
ptrdiff_t compare(const WCFixedStringBase& in_to_compare) const
{
ptrdiff_t retVal = compare(in_to_compare.c_str());
return retVal;
}
ptrdiff_t case_insensitive_compare(const char* in_to_compare) const
{
ptrdiff_t retVal = 1;
if (0 != in_to_compare)
{
#ifdef _WINDOWS
retVal = _stricmp(c_str(), in_to_compare);
#endif
#if defined(__linux__) || defined(__MACOS__)
retVal = strcasecmp(c_str(), in_to_compare);
#endif
}
return retVal;
}
ptrdiff_t case_insensitive_compare(const WCFixedStringBase& in_to_compare) const
{
ptrdiff_t retVal = case_insensitive_compare(in_to_compare.c_str());
return retVal;
}
pos_t find(const char in_char_to_find) const
{
const char* pCurrChar = m_begin;
while (pCurrChar < m_end && *pCurrChar != in_char_to_find)
++pCurrChar;
return (pCurrChar < m_end) ? (pCurrChar - m_begin) : npos;
}
pos_t rfind(const char in_char_to_find) const
{
pos_t retVal = npos;
const char* pCurrChar = m_end;
while (pCurrChar != m_begin)
{
--pCurrChar;
if (*pCurrChar == in_char_to_find)
{
retVal = pCurrChar - m_begin;
break;
}
}
return retVal;
}
pos_t find(const char* in_chars_to_find, const pos_t in_start_from = 0) const
{
pos_t retVal = npos;
size_t to_find_size = ::strlen(in_chars_to_find);
if (to_find_size > 0 && to_find_size <= size() && in_start_from < size())
{
const char* pCurrChar = m_begin + in_start_from;
while ((m_end - pCurrChar) >= (ptrdiff_t)to_find_size)
{
int found = ::memcmp(pCurrChar, in_chars_to_find, to_find_size);
if (0 == found)
{
retVal = (pCurrChar - m_begin);
break;
}
++pCurrChar;
}
}
return retVal;
}
pos_t rfind(const char* in_chars_to_find) const
{
pos_t retVal = npos;
size_t to_find_size = ::strlen(in_chars_to_find);
if (to_find_size > 0 && to_find_size <= size())
{
const char* pCurrChar = m_end - to_find_size;
while (m_begin <= pCurrChar)
{
int found = ::memcmp(pCurrChar, in_chars_to_find, to_find_size);
if (0 == found)
{
retVal = (pCurrChar - m_begin);
break;
}
--pCurrChar;
}
}
return retVal;
}
pos_t find_case_insensitive(const char* in_chars_to_find, const pos_t in_start_from = 0) const
{
pos_t retVal = npos;
size_t to_find_size = ::strlen(in_chars_to_find);
if (to_find_size > 0 && to_find_size <= size() && in_start_from < size())
{
const char* pCurrChar = m_begin + in_start_from;
while ((m_end - pCurrChar) >= (ptrdiff_t)to_find_size)
{
size_t i;
for (i = 0; i < to_find_size; ++i)
{
if (tolower(*(pCurrChar+i)) != tolower(in_chars_to_find[i]))
break;
}
if (i == to_find_size)
{
retVal = (pCurrChar - m_begin);
break;
}
++pCurrChar;
}
}
return retVal;
}
pos_t find_first_of(const char* in_possibe_chars_to_find, const pos_t in_start_from = 0) const
{
pos_t retVal = npos;
if (in_start_from < size())
{
const char* pFoundChar = strpbrk(m_begin + in_start_from, in_possibe_chars_to_find);
if (0 != pFoundChar)
{
retVal = (pFoundChar - m_begin);
}
}
return retVal;
}
pos_t find_last_of(const char* in_possibe_chars_to_find, const pos_t in_start_from = 0) const
{
pos_t retVal = npos;
pos_t curr_location = in_start_from;
while (size() > curr_location)
{
pos_t found = find_first_of(in_possibe_chars_to_find, curr_location);
if (npos != found)
{
retVal = found;
curr_location = found + 1;
}
else
break;
}
return retVal;
}
pos_t find_first_not_of(const char* in_acceptable_chars, const pos_t in_start_from = 0) const
{
pos_t retVal = npos;
if (in_start_from < size())
{
retVal = (strspn(m_begin + in_start_from, in_acceptable_chars));
if (size() <= retVal + in_start_from)
{
retVal = npos;
}
else
{
retVal += in_start_from;
}
}
return retVal;
}
pos_t find_last_not_of(const char* in_acceptable_chars, const pos_t in_start_from = 0) const
{
pos_t retVal = npos;
pos_t curr_location = in_start_from;
while (size() > curr_location)
{
pos_t found = find_first_not_of(in_acceptable_chars, curr_location);
if (npos != found)
{
retVal = found;
curr_location = found + 1;
}
else
break;
}
return retVal;
}
// return true if in_begin_text is found at position 0 OR if in_begin_text is empty
bool begins_with(const char* in_begin_text) const
{
pos_t where = find(in_begin_text, 0);
bool retVal = (0 == where) || (0 == ::strlen(in_begin_text));
return retVal;
}
// return true if in_end_text is found at th end OR if in_end_text is empty
bool ends_with(const char* in_end_text) const
{
pos_t where = rfind(in_end_text);
bool retVal = ((size() - strlen(in_end_text)) == where) || (0 == ::strlen(in_end_text));
return retVal;
}
size_t replace(const char in_look_for, const char in_replace_with)
{
size_t retVal = 0;
char* pCurrChar = m_begin;
while (pCurrChar < m_end)
{
if (*pCurrChar == in_look_for)
{
*pCurrChar = in_replace_with;
++retVal;
}
++pCurrChar;
}
return retVal;
}
// erase in_size chars starting from in_location
void erase(const pos_t in_location, const size_t in_num_chars = 1)
{
if (size() > in_location && in_num_chars > 0)
{
size_t actual_num_chars = WUMin(in_num_chars, size_t(size() - in_location));
char* pTo = m_begin + in_location;
char* pFrom = pTo + actual_num_chars;
while (pFrom < m_end)
*pTo++ = *pFrom++;
resize(size() - actual_num_chars);
}
}
// erase any char that appear in in_forbidden_chars
void erase_all_of(const char* in_forbidden_chars)
{
pos_t curr_location = 0;
while (npos != curr_location)
{
curr_location = find_first_of(in_forbidden_chars, curr_location);
if (npos != curr_location)
erase(curr_location);
}
}
// erase any char that do not appear in in_allowed_chars
void erase_all_not_of(const char* in_allowed_chars)
{
pos_t curr_location = 0;
while (npos != curr_location)
{
curr_location = find_first_not_of(in_allowed_chars, curr_location);
if (npos != curr_location)
erase(curr_location);
}
}
//! Copy the content of fixed string to a buffer appending a '\0' at the end.
//! If in_buffer_size is more than the allocated buffer size memory over write will happen!
void copy_to_buffer(const size_t in_buffer_size, char* out_buffer)
{
if (in_buffer_size > 0 && 0 != out_buffer)
{
char* cur_buffer = out_buffer;
const char* cur_fixed = m_begin;
const char* end_buffer = out_buffer + (WUMin<size_t>(in_buffer_size - 1, m_end - m_begin));
while (cur_buffer < end_buffer)
*cur_buffer++ = *cur_fixed++;
*cur_buffer = '\0';
}
}
protected:
~WCFixedStringBase() {}
char* const m_begin;
const size_t m_MaxFixedStringLength;
char* m_end;
private:
WCFixedStringBase();
WCFixedStringBase(const WCFixedStringBase& in_fixedStrToCopy);
#if 0
:
m_begin(in_fixedStrToCopy.m_begin),
m_MaxFixedStringLength(in_fixedStrToCopy.m_MaxFixedStringLength),
m_end(in_fixedStrToCopy.m_end)
{
}
#endif
};
template<size_t kMaxFixedStringLength> class DllExport WCFixedString : public WCFixedStringBase
{
public:
inline WCFixedString() :
WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
{
}
inline WCFixedString(const char* const in_strToAssign) :
WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
{
operator<<(in_strToAssign);
}
inline WCFixedString(const WCFixedStringBase& in_fixedStrToAssign) :
WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
{
operator<<(in_fixedStrToAssign);
}
inline WCFixedString(const WCFixedString& in_fixedStrToAssign) :
WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
{
operator<<(in_fixedStrToAssign);
}
inline WCFixedString(const char in_char, const size_t in_count = 1) :
WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
{
append(in_char, in_count);
}
inline WCFixedString(const char* in_chars, const size_t in_count) :
WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
{
append(in_chars, in_count);
}
// substr now supports negative in_length, which means "from the end" so
// "abcdefg".substr(1, -1) == "bcdef"
inline const WCFixedString substr(const pos_t in_pos = 0, const spos_t in_length = kMaxFixedStringLength) const
{
pos_t adjusted_pos = WUMin<size_t>(in_pos, size());
size_t adjusted_length = 0;
if (in_length < 0)
{
adjusted_length = size_t(WUMax<spos_t>(0, spos_t(size() - adjusted_pos) + in_length));
}
else
adjusted_length = WUMin<size_t>(in_length, size() - adjusted_pos);
WCFixedString retVal;
retVal.append(m_begin + adjusted_pos, adjusted_length);
return retVal;
}
protected:
char m_fixedString[kMaxFixedStringLength + 1]; // the "+ 1" is so that *m_end is always valid, and we can put the '\0' there};
};
inline bool operator==(const WCFixedStringBase& in_left, const WCFixedStringBase& in_right)
{
return 0 == in_left.compare(in_right.c_str());
}
inline bool operator==(const WCFixedStringBase& in_left, const char* const in_right)
{
return 0 == in_left.compare(in_right);
}
inline bool operator!=(const WCFixedStringBase& in_left, const WCFixedStringBase& in_right)
{
return 0 != in_left.compare(in_right.c_str());
}
inline bool operator!=(const WCFixedStringBase& in_left, const char* const in_right)
{
return 0 != in_left.compare(in_right);
}
// class WCFixedStringBase
typedef WCFixedString<4> WCFixedString4;
typedef WCFixedString<15> WCFixedString15;
typedef WCFixedString<31> WCFixedString31;
typedef WCFixedString<63> WCFixedString63;
typedef WCFixedString<127> WCFixedString127;
typedef WCFixedString<255> WCFixedString255;
typedef WCFixedString<511> WCFixedString511;
typedef WCFixedString<1023> WCFixedString1023;
typedef WCFixedString<2047> WCFixedString2047;
template<size_t kSizeOfFirst, size_t kSizeOfSecond>
class WCFixedStringPair : public std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >
{
public:
WCFixedStringPair(const char* const in_firstStr = 0, const char* const in_secondStr = 0) :
std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
WCFixedStringPair(const WCFixedStringBase& in_firstStr, const char* const in_secondStr = 0) :
std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
WCFixedStringPair(const WCFixedStringBase& in_firstStr, const WCFixedStringBase& in_secondStr) :
std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
};
#endif // #ifndef __WCFixedString_h__

View file

@ -0,0 +1,334 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __WUErrors_h__
#define __WUErrors_h__
/* Copy to include:
#include "WUErrors.h"
*/
#include "BasicTypes/WUTypes.h"
// General errors
//const WTErr eNoErr = 0; // moved to #include "WavesPublicAPI/WTErr.h"
const WTErr eGenericErr = -1;
const WTErr eUserCanceled = -2;
const WTErr eUnknownErr = -3;
const WTErr eExceptionErr = -4;
const WTErr eEndianError = -5;
const WTErr eThreadSafeError = -6;
const WTErr eSomeThingNotInitailzed = -7;
const WTErr eWrongObjectState = -8; //!< object was not in an acceptable state
const WTErr eUninitalized = -9;
const WTErr eDeprecated = -10;
const WTErr eCommandLineParameter = -11;
const WTErr eNotANumber = -12; //!< expected a number but none was found
const WTErr eNotJustANumber = -13; //!< expected a number and found one but also other stuff (e.g. "123XYZ")
const WTErr eNegativeNumber = -14; //!< expected a positive number and found a negative
const WTErr eTimeOut = -15; //!< something timed out
const WTErr eCoreAudioFailed = -16; //!< Error in a core audio call
const WTErr eSomeThingInitailzedTwice = -17;
const WTErr eGenerateHelpInfo = -18;
const WTErr eOutOfRangeNumber = -19;
const WTErr eMacOnlyCode = -20;
const WTErr eWinOnlyCode = -21;
const WTErr eAppLaunchFailed = -22; //!< failed to launch an application
const WTErr eAppTerminateFailed = -23; //!< failed to terminate an application
const WTErr eAppReturnedError = -24; //!< Non zero exit code from application
const WTErr eNotImplemented = -25; //!< Function is not implmemented
const WTErr eNotEmpty = -26; //!< Something was expected to be empty but is not
// File Manager errors
const WTErr eFMNoSuchVolume = -1001;
const WTErr eFMFileNotFound = -1002;
const WTErr eFMFileAllreadyExists = -1003;
const WTErr eFMAllreadyOpenWithWritePerm = -1004;
const WTErr eFMEndOfFile = -1005;
const WTErr eFMPermissionErr = -1006;
const WTErr eFMBusyErr = -1007;
const WTErr eFMOpenFailed = -1008;
const WTErr eFMTranslateFileNameFailed = -1009;
const WTErr eFMWTPathRefCreationFailed = -1010;
const WTErr eFMReadFailed = -1011;
const WTErr eFMIllegalPathRef = -1012;
const WTErr eFMFileNotOpened = -1013;
const WTErr eFMFileSizeTooBig = -1014;
const WTErr eFMNoSuchDomain = -1015;
const WTErr eFMNoSuchSystemFolder = -1016;
const WTErr eFMWrongParameters = -1017;
const WTErr eFMIsNotAFolder = -1018;
const WTErr eFMIsAFolder = -1019;
const WTErr eFMIsNotAFile = -1020;
const WTErr eFMIsAFile = -1021;
const WTErr eFMDeleteFailed = -1022;
const WTErr eFMCreateFailed = -1023;
const WTErr eFMPathTooLong = -1024;
const WTErr eFMIOError = -1025;
const WTErr eFMIllegalOpenFileRef = -1026;
const WTErr eFMDiskFull = -1027;
const WTErr eFMFileNotEmpty = -1028;
const WTErr eFMEndOfFolder = -1029;
const WTErr eFMSamePath = -1030;
const WTErr eFMPathTooShort = -1031;
const WTErr eFMIncompletePath = -1032;
const WTErr eFMIsNoAFileSystemLink = -1033;
const WTErr eFMSymlinkBroken = -1034;
const WTErr eFMMoveFailed = -1035;
const WTErr eFMWriteFailed = -1036;
const WTErr eFMTooManyOpenFiles = -1037;
const WTErr eFMTooManySymlinks = -1038;
// System errors
const WTErr eGenericSystemError = -2000;
const WTErr eSysNoEnvironmentVariable = -2001;
const WTErr eDLLLoadingFailed = -2002;
const WTErr eFuncPoinerNotFound = -2003;
const WTErr eDLLNotFound = -2004;
const WTErr eBundleNotLoaded = -2005;
const WTErr eBundleCreateFailed = -2006;
const WTErr eBundleExecutableNotFound = -2007;
const WTErr eNotABundle = -2008;
const WTErr eInvalideDate = -2009;
const WTErr eNoNetDevice = -2010;
const WTErr eCacheCreatedFromResource = -2011;
const WTErr eNotAValidApplication = -2012;
// Resource Manager errors
const WTErr eRMResNotFound = -3000;
const WTErr eRMResExists = -3001; //!< a resource exist even though it's not expected to
const WTErr eRMContainerNotFound = -3002; //!< The container was not found in the list of containers
const WTErr eRMResRefNotFound = -3003; //!< The resRef was not found in container's resource list
const WTErr eRMInvalidResRef = -3004;
const WTErr eRMInvalidResContainer = -3005;
const WTErr eRMInvalidNativeResContainer = -3006;
const WTErr eRMAttachResContainerFailed = -3007;
const WTErr eRMInvalidResID = -3008;
const WTErr eRMResUpdateFailed = -3009;
// Graphic Manager & GUI errors
const WTErr eGMIsNotInitailzed = -3500;
const WTErr eGMInvalidImage = -3501;
const WTErr eGMGenericErr = -3502;
const WTErr eGMNoCurrentContext = -3503;
const WTErr eGUISkinNotFound = -3504;
const WTErr eGMNoVertices = -3505;
const WTErr eGMNoColors = -3506;
const WTErr eGMNoTexture = -3507;
const WTErr eGMIncompatibleOGLVersion = -3508;
const WTErr eGMNoDeviceContext = -3509;
const WTErr eGMNoPixelFormat = -3510;
const WTErr eGMNoOGLContext = -3511;
const WTErr eGMNoOGLContextSharing = -3512;
const WTErr eGMUnsupportedImageFormat = -3513;
const WTErr eGMUninitializedContext = -3514;
const WTErr eControlOutOfRange = -3515;
const WTErr eGMUninitializedFont = -3516;
const WTErr eGMInvalidFontDrawMethod = -3517;
const WTErr eGMUnreleasedTextures = -3518;
const WTErr eGMWrongThread = -3519;
const WTErr eGMDontCommitDraw = -3520;
// Errors in the -5000 -> -5999 are defined in Waves-incs.h
// Memory errors
const WTErr eMemNewFailed = -4001; //!< Something = new CSomething, returned null
const WTErr eMemNewTPtrFailed = -4002; //!< NewTPtr or NewTPtrClear failed
const WTErr eMemNullPointer = -4003; //!< a null pointer was encountered where it should not
const WTErr eMemObjNotInitialized = -4004;
const WTErr eMemBuffTooShort = -4005; //!< the buffer in question did not have enough space for the operation
const WTErr eInstanciationFailed = -4006;
const WTErr eMemAddressSpaceError = -4007; //!< memory falls outside the legal address space
const WTErr eMemBadPointer = -4008;
const WTErr eMemOutOfMemory = -4009;
// XML Errors
const WTErr eXMLParserFailed = -6001;
const WTErr eXMLTreeNotValid = -6002;
const WTErr eXMLTreeEmpty = -6003;
const WTErr eXMLElementMissing = -6004;
const WTErr eXMLElementUninitalized = -6005; //!< element was default constructed it has not element name, etc..
const WTErr eXMLElementIncomplete = -6006; //!< XML parser did not complete building the element
const WTErr eXMLAttribMissing = -6007;
// Preset errors
const WTErr ePresetFileProblem = -7860;
const WTErr eInvalidFileFormatProblem = -7861;
const WTErr ePresetLockedProblem = -7862;
const WTErr ePresetInfoNotFound = -7863;
const WTErr eDuplicatePluginSpecificTag = -7959;
const WTErr ePluginSpecifcNotExisting = -7960;
const WTErr eBuffSizeToSmall = -7961;
const WTErr eCreatingPopupWhereAnItemExists = -7962;
const WTErr eDeletePluginSpecifcFailed = -7963;
const WTErr eFactoryPresetNumOutOfRange = -7964;
const WTErr eNoFactoryPresets = -7965;
const WTErr eLoadPresetToPlugin_vec_empty = -7966;
const WTErr eFactoryPresetNotFound = -7967;
const WTErr eCantCreateUserPrefFile = -7968;
const WTErr eDataFormatNotSupported = -7969;
const WTErr eCantLoadProcessFunction = -7970;
const WTErr eIllegalChunkIndex = -7971;
const WTErr eIllegalChunkID = -7972;
const WTErr eIllegalChunkVersion = -7973;
// Shell errors
const WTErr eNotAPluginFile = -8001;
const WTErr eFaildToLoadPluginDLL = -8002;
const WTErr eNoPluginManager = -8003;
const WTErr eGetAvailablePluginsFailed = -8004;
const WTErr eNoPluginsAvailable = -8005;
const WTErr ePluginSubComponentNotFound = -8006;
const WTErr ePluginOpenFailed = -8007;
const WTErr eSubComponentRejected = -8009; //!< user did not want this sub-component - probably through preferences
const WTErr eIncompatibleNumOfIOs = -8010; //!< e.g. surround sub-component in stereo only shell
const WTErr eStemProblem = -8011; //!< Some problem with stems
const WTErr eComponentTypeNotSupported = -8012;
const WTErr ePluginNotLoaded = -8013;
const WTErr ePluginInstanceNotCreate = -8014;
const WTErr ePluginAlgNotCreate = -8015;
const WTErr ePluginGUINotCreate = -8016;
const WTErr eMissmatchChannelCount = -8017;
const WTErr eIncompatibleVersion = -8018;
const WTErr eIncompatibleAffiliation = -8019;
const WTErr eNoSubComponentsFound = -8020;
// Net-shell errors
const WTErr eNetShellInitFailed = -9001;
// Protection errors
const WTErr eWLSLicenseFileNotFound = -10001;
const WTErr eWLSPluginNotAuthorized = -10002;
const WTErr eWLSNoLicenseForPlugin = -10003;
const WTErr eWLSInvalidLicenseFileName = -10004;
const WTErr eWLSInvalidLicenseFileContents = -10005;
const WTErr eWLSInvalidDeviceID = -10006;
const WTErr eWLSInvalidClientID = -10007;
const WTErr eWLSLicenseFileDownloadFailed = -10008;
const WTErr eWLSNoLicensesForClientOrDevice = -10009;
const WTErr eWLSNoLicensesForSomePlugins = -10010;
// Communication errors
const WTErr eCommEndOfRecievedMessage = -11001;
const WTErr eCommSocketDisconnected = -11002;
// Window Manager Errors
const WTErr eWMEventNotHandled = -12001;
const WTErr eWMDisposeViewFailed = -12002;
// Plugin View Manager Errors
const WTErr ePVMPlatformNotSupported = -13001;
const WTErr ePVMAlreadyInitialized = -13002;
const WTErr ePVMIllegalParent = -13003;
const WTErr ePVMCannotCreateView = -13004;
const WTErr ePVMNothingSelected = -13005;
const WTErr ePVMDisabledItemChosen = -13006;
const WTErr ePVMMenuItemNotFound = -13007;
const WTErr ePVMMenuItemNotASubMenu = -13008;
const WTErr ePVMUnknownMenu = -13009;
const WTErr ePVMEmptyNativeViewRef = -13010;
const WTErr ePVMGenericError = -13011;
const WTErr ePVMFunctionNotImplemented = -13012;
// Plugin View Manager - Menu Errors
const WTErr ePVMCannotCreateMenu = -13501;
const WTErr ePVMCannotSetMenuFont = -13502;
const WTErr ePVMCannotSetMenu = -13503;
const WTErr ePVMItemParentNotExists = -13504;
// Plugin View Manager - TextField Errors
const WTErr ePVMCannotCreateTextField = -13553;
const WTErr ePVMCannotEmbedTextField = -13554;
const WTErr ePVMNoTextToValidate = -13555;
const WTErr ePVMTextTooLong = -13556;
const WTErr ePVMIllegalCharacter = -13557;
// Meter Manager Errors
const WTErr eMM_MeterGetMeterValueForParameterNotConnected = -14000 ;
//Surface Driver Manager Errors
const WTErr eSDM_SurfaceDriverAPIFailed = -14101;
// IPC Errors
const WTErr eIPC_CreateNamedPipeFailed = -14200;
const WTErr eIPC_OpenPipeTimeout = -14201;
const WTErr eIPC_DeleteNamedPipeFailed = -14202;
const WTErr eIPC_SelectOnNamedPipeFailed = -14203;
const WTErr eIPC_ReadFromNamedPipeFailed = -14204;
const WTErr eIPC_ReadEndOfFileFromNamedPipe = -14205;
const WTErr eIPC_CloseNamedPipeFailed = -14206;
const WTErr eIPC_ParseArgsFailed = -14207;
const WTErr eIPC_OpenPipeFailed = -14208;
const WTErr eIPC_SendMsgFailed = -14209;
const WTErr eIPC_SendCommandInvalid = -14210;
const WTErr eIPC_QtTestMode = -14211;
const WTErr eIPC_ChangePermissionOnPipe = -14212;
const WTErr eIPC_ConnectionLost = -14213;
const WTErr eIPC_InvalidRole = -14213;
const WTErr eIPC_CreateNamedPipeM2SFailed = -14214;
const WTErr eIPC_CreateNamedPipeS2MFailed = -14215;
const WTErr eIPC_ChangePermissionOnPipeM2S = -14216;
const WTErr eIPC_ChangePermissionOnPipeS2M = -14217;
const WTErr eIPC_OpenReadPipeFailed = -14218;
const WTErr eIPC_OpenReadPipeDIsableSigPipe = -14219;
const WTErr eIPC_OpenWritePipeFailed = -14220;
const WTErr eIPC_WritePipeFailed = -14221;
const WTErr eIPC_WritePipeNotOpen = -14222;
const WTErr eIPC_WriteBufferResizeFailed = -14223;
const WTErr eIPC_NotConnectedSendMsgFailed = -14224;
const WTErr eIPC_OpenWritePipeWorkerStoping = -14225;
const WTErr eIPC_SoketSendFailed = -14226;
const WTErr eIPC_PtonFailed = -14227;
const WTErr eIPC_SocketFailed = -14228;
const WTErr eIPC_BindFailed = -14229;
const WTErr eIPC_ListenFailed = -14230;
const WTErr eIPC_ConnectFailed = -14231;
const WTErr eIPC_WsaStartupFailed = -14232;
const WTErr eIPC_UdpSocketCreateFailed = -14233;
const WTErr eIPC_UdpSocketConnectFailed = -14234;
const WTErr eIPC_UdpSocketBinFailed = -14235;
const WTErr eIPC_SetBufferPreambleFailed = -14226;
// Database errors
const WTErr eDB_BatchRollback = -15501;
// inventory related errors
const WTErr eUnknown_Device = -16001;
const WTErr eInvNoDevice = -16002;
// SG protocol service errors
const WTErr eSGProtocolService_Not_Running = -17001;
const WTErr eSGProtocolService_Version_MisMatch = -17002;
// Error code related to Param
const WTErr eInvalidParam = -18001;
#define WUIsError(theErrorCode) (eNoErr != (theErrorCode))
#define WUNoError(theErrorCode) (eNoErr == (theErrorCode))
#define WUThrowError(theErrorCode) {if(WUIsError(theErrorCode))throw (theErrorCode);}
#define WUThrowErrorIfNil(thePtr , theErrorCode) {if (0 == thePtr )throw (theErrorCode);}
#define WUThrowErrorIfFalse(theBool , theErrorCode) {if (!(theBool))throw (theErrorCode);}
#define WUThrowErrorCodeIfError(err,theErrorCode) {if(WUIsError(err))throw (theErrorCode);}
// Get the error string that match the error code.
DllExport const char* WTErrName(WTErr wtErr);
#endif //__WUErrors_h__:

View file

@ -0,0 +1,36 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __safe_delete_h__
#define __safe_delete_h__
/* Copy to include:
#include "safe_delete.h"
*/
#define safe_delete(__pObject__) {if((__pObject__) != 0) {delete (__pObject__); (__pObject__) = 0;}}
#define safe_delete_array(__pArray__) {if((__pArray__) != 0) {delete [] (__pArray__); (__pArray__) = 0;}}
template <class T> void safe_delete_from_iterator(T* pToDelete)
{
safe_delete(pToDelete);
}
#endif // __safe_delete_h__

View file

@ -0,0 +1,44 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "WCRefManager.h"
/// Construcotr.
WCRefManager::WCRefManager()
{
m_RefCount = 1;
}
/// Destructor.
WCRefManager::~WCRefManager()
{
}
/// Adds a reference to class.
void WCRefManager::AddRef()
{
m_RefCount++;
}
/// Decrements reference count and deletes the object if reference count becomes zero.
void WCRefManager::Release()
{
m_RefCount--;
if( m_RefCount <= 0 )
delete this;
}

View file

@ -0,0 +1,80 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef WCREFMANAGER_H
#define WCREFMANAGER_H
#define SAFE_RELEASE(p) if (p) {p->Release(); p = NULL;}
//In order to use this interface, derive the Interface class
//from WCRefManager_Interface and derive the implementation class
//from WCRefManager_Impl. Further, in the implementation class
//declaration, place the macro WCREFMANAGER_IMPL.
class WCRefManager_Interface
{
public:
/// Constructor.
WCRefManager_Interface() {};
/// Destructor.
virtual ~WCRefManager_Interface() {};
/// Adds a reference to class.
virtual void AddRef() = 0;
/// Decrements reference count and deletes the object if reference count becomes zero.
virtual void Release() = 0;
};
///! See details at WCRefManager_Interface for how to use this.
class WCRefManager_Impl
{
public:
WCRefManager_Impl () : m_RefCount(1) {}
virtual ~WCRefManager_Impl() {}
protected:
/// Variable to store reference count.
unsigned int m_RefCount;
/// Helper to put implementation in an interface derived class, don't forget to
/// derive the impl from WCRefManager_Impl
#define WCREFMAN_IMPL \
public: \
virtual void AddRef() {m_RefCount++;} \
virtual void Release() {m_RefCount--; if (m_RefCount<=0) delete this;}
};
class WCRefManager
{
public:
/// Construcotr.
WCRefManager();
/// Destructor.
virtual ~WCRefManager();
/// Adds a reference to class.
void AddRef();
/// Decrements reference count and deletes the object if reference count becomes zero.
void Release();
private:
/// Variable to store reference count.
unsigned int m_RefCount;
};
#endif // WCREFMANAGER_H

View file

@ -0,0 +1,844 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Threads/WCThreadSafe.h"
#if XPLATFORMTHREADS_WINDOWS
#define _WIN32_WINNT 0x0500 // need at least Windows2000 (for TryEnterCriticalSection() and SignalObjectAndWait()
#include "IncludeWindows.h"
#include <process.h>
#endif // XPLATFORMTHREADS_WINDOWS
#if defined(__MACOS__)
#include <CoreServices/CoreServices.h>
#include <stdio.h>
#endif // __MACOS__
#if XPLATFORMTHREADS_POSIX
#include </usr/include/unistd.h> // avoid the framework version and use the /usr/include version
#include <pthread.h>
#include <sched.h>
#include <sys/time.h>
#include <errno.h>
#include <signal.h>
// We do this externs because <stdio.h> comes from MSL
extern "C" FILE *popen(const char *command, const char *type);
extern "C" int pclose(FILE *stream);
static int (*BSDfread)( void *, size_t, size_t, FILE * ) = 0;
#include <string.h>
#endif //XPLATFORMTHREADS_POSIX
#include "Akupara/threading/atomic_ops.hpp"
namespace wvNS {
static const unsigned int knMicrosecondsPerSecond = 1000*1000;
static const unsigned int knNanosecondsPerMicrosecond = 1000;
static const unsigned int knNanosecondsPerSecond = knMicrosecondsPerSecond*knNanosecondsPerMicrosecond;
namespace wvThread
{
//--------------------------------------------------------------------------------
static inline bool EnsureThreadingInitialized()
{
bool bRetval = true;
return bRetval;
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
static uint32_t CalculateTicksPerMicrosecond();
static uint32_t CalculateTicksPerMicrosecond()
{
uint32_t nTicksPerMicrosecond=0;
#if defined(_WIN32)
LARGE_INTEGER TSC;
::QueryPerformanceFrequency(&TSC);
nTicksPerMicrosecond = uint32_t (TSC.QuadPart / knMicrosecondsPerSecond);
#elif defined(__linux__) && defined(__i386__)
static const timediff sktd_TSC_MeasurementPeriod = 40*1000; // delay for CalculateTicksPerMicrosecond() to measure the TSC frequency
uint64_t Tstart, Tend;
timeval tvtmp, tvstart, tvend;
//--------------------- begin measurement code
// poll to align to a tick of gettimeofday
::gettimeofday(&tvtmp,0);
do {
::gettimeofday(&tvstart,0);
__asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (Tstart)); // RDTSC
} while (tvtmp.tv_usec!=tvstart.tv_usec);
// delay some
::usleep(sktd_TSC_MeasurementPeriod);
//
::gettimeofday(&tvtmp,0);
do {
::gettimeofday(&tvend,0);
__asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (Tend)); // RDTSC
} while (tvtmp.tv_usec!=tvend.tv_usec);
//--------------------- end measurement code
suseconds_t elapsed_usec = (tvend.tv_sec-tvstart.tv_sec)*knMicrosecondsPerSecond + (tvend.tv_usec-tvstart.tv_usec);
uint64_t elapsed_ticks = Tend-Tstart;
nTicksPerMicrosecond = uint32_t (elapsed_ticks/elapsed_usec);
#endif
return nTicksPerMicrosecond;
}
#if defined(__MACOS__) //&& !defined(__MACH__)
bool FindNetInterfaceByIPAddress(const char *sIP, char *sInterface) // sIP and sInterface are both char[16]
{
FILE *fProcess , *pSubcall;
char sLine[256]="", *pToken, sCommand[150];
bool res = false;
int iret;
fProcess = popen("ifconfig -l inet", "r");
if (fProcess)
{
memset(sInterface, '\0', 16);
iret = BSDfread(sLine, sizeof(char), sizeof(sLine), fProcess);
pToken = strtok(sLine, " ");
while (pToken)
{
sprintf(sCommand, "ifconfig %s | grep \"inet %s \"", pToken, sIP);
pSubcall = popen(sCommand, "r");
if (pSubcall)
{
char sSubline[100]="";
if (BSDfread(sSubline, sizeof(char), sizeof(sSubline), pSubcall))
{
// found
strcpy(sInterface, pToken);
res = true;
pclose(pSubcall);
break;
}
}
pclose(pSubcall);
pToken = strtok(NULL, " ");
}
}
pclose(fProcess);
return res;
}
#endif // MACOS
timestamp now(void)
{
EnsureThreadingInitialized();
static const uint32_t nTicksPerMicrosecond = CalculateTicksPerMicrosecond();
#if defined(_WIN32)
if (nTicksPerMicrosecond)
{
LARGE_INTEGER TSC;
::QueryPerformanceCounter(&TSC);
return timestamp(uint32_t(TSC.QuadPart/nTicksPerMicrosecond));
}
else return timestamp(0);
#elif defined(__MACOS__)
if (nTicksPerMicrosecond) {} // prevent 'unused' warnings
UnsignedWide usecs;
::Microseconds(&usecs);
return timestamp(usecs.lo);
#elif defined(__linux__) && defined(__i386__) && defined(__gnu_linux__)
uint64_t TSC;
__asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (TSC)); // RDTSC
return timestamp(TSC/nTicksPerMicrosecond);
#elif defined(__linux__) && defined(__PPC__) && defined(__gnu_linux__)
#warning need to implement maybe
#else
#error Dont know how to get microseconds timer !
#endif // defined(_WIN32)
}
void sleep_milliseconds(unsigned int nMillisecs)
{
EnsureThreadingInitialized();
#if XPLATFORMTHREADS_WINDOWS
::Sleep(nMillisecs);
#elif XPLATFORMTHREADS_POSIX
::usleep(nMillisecs*1000);
#else
#error Not implemented for your OS
#endif
}
#if XPLATFORMTHREADS_WINDOWS
inline DWORD win32_milliseconds(timediff td) { return (td+499)/1000; }
#endif
void sleep(timediff _td)
{
if (_td>0)
{
EnsureThreadingInitialized();
#if XPLATFORMTHREADS_WINDOWS
::Sleep(win32_milliseconds(_td)); // This is the best we can do in windows
#elif XPLATFORMTHREADS_POSIX
::usleep(_td);
#else
#error Not implemented for your OS
#endif
}
}
#if XPLATFORMTHREADS_WINDOWS
void yield() { ::Sleep(0); }
#elif XPLATFORMTHREADS_POSIX
void yield() { ::sched_yield(); }
#endif
class ThreadMutexInited::OSDependentMutex : public noncopyableobject
{
#if defined (XPLATFORMTHREADS_WINDOWS)
protected:
CRITICAL_SECTION m_critsec;
public:
inline OSDependentMutex() { EnsureThreadingInitialized(); ::InitializeCriticalSection(&m_critsec); }
inline ~OSDependentMutex() { EnsureThreadingInitialized(); ::DeleteCriticalSection (&m_critsec); }
inline void obtain() { EnsureThreadingInitialized(); ::EnterCriticalSection (&m_critsec); }
inline void release() { EnsureThreadingInitialized(); ::LeaveCriticalSection (&m_critsec); }
inline bool tryobtain() { EnsureThreadingInitialized(); return TryEnterCriticalSection(&m_critsec)!=FALSE; }
#elif defined (XPLATFORMTHREADS_POSIX)
protected:
pthread_mutex_t m_ptmutex;
public:
inline OSDependentMutex()
{
EnsureThreadingInitialized();
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
::pthread_mutex_init (&m_ptmutex, &attr);
}
inline ~OSDependentMutex() { EnsureThreadingInitialized(); ::pthread_mutex_destroy(&m_ptmutex); }
inline void obtain() { EnsureThreadingInitialized(); ::pthread_mutex_lock (&m_ptmutex); }
inline void release() { EnsureThreadingInitialized(); ::pthread_mutex_unlock (&m_ptmutex); }
inline bool tryobtain() { EnsureThreadingInitialized(); return ::pthread_mutex_trylock(&m_ptmutex)!=EBUSY; }
#endif
};
ThreadMutexInited::ThreadMutexInited() :
m_osdmutex(0) {}
void ThreadMutexInited::init()
{
if (! is_init())
{
m_osdmutex = new OSDependentMutex;
}
}
void ThreadMutexInited::uninit()
{
if (is_init())
{
delete m_osdmutex;
m_osdmutex = 0;
}
}
ThreadMutexInited::~ThreadMutexInited()
{
uninit();
}
void ThreadMutexInited::obtain()
{
if (is_init())
{
m_osdmutex->obtain();
}
}
void ThreadMutexInited::release()
{
if (is_init())
{
m_osdmutex->release();
}
}
bool ThreadMutexInited::tryobtain()
{
bool retVal = true;
if (is_init())
{
retVal = m_osdmutex->tryobtain();
}
return retVal;
}
class ThreadConditionSignal::OSDependentObject : public noncopyableobject
{
#if defined (XPLATFORMTHREADS_POSIX)
protected:
pthread_cond_t m_ptcond;
pthread_mutex_t m_ptmutex;
public:
inline OSDependentObject()
{
EnsureThreadingInitialized();
::pthread_mutex_init(&m_ptmutex,0);
::pthread_cond_init(&m_ptcond, 0);
}
inline ~OSDependentObject() { ::pthread_cond_destroy(&m_ptcond), ::pthread_mutex_destroy(&m_ptmutex); }
inline void signal_unicast() { ::pthread_cond_signal(&m_ptcond); }
inline void signal_broadcast() { ::pthread_cond_broadcast(&m_ptcond); }
inline void await_signal() { ::pthread_cond_wait(&m_ptcond, &m_ptmutex); }
inline bool await_signal(timediff td)
{
timespec tspecDeadline;
timeval tvNow;
::gettimeofday(&tvNow,0);
tspecDeadline.tv_nsec = (tvNow.tv_usec + td%knMicrosecondsPerSecond)*knNanosecondsPerMicrosecond;
tspecDeadline.tv_sec = tvNow.tv_sec + td/knMicrosecondsPerSecond;
if (!(tspecDeadline.tv_nsec < suseconds_t(knNanosecondsPerSecond)))
++tspecDeadline.tv_sec, tspecDeadline.tv_nsec-=knNanosecondsPerSecond;
return ::pthread_cond_timedwait(&m_ptcond, &m_ptmutex, &tspecDeadline) != ETIMEDOUT;
}
void obtain_mutex() { ::pthread_mutex_lock(&m_ptmutex); }
bool tryobtain_mutex() { return ::pthread_mutex_trylock(&m_ptmutex)!=EBUSY; }
void release_mutex() { ::pthread_mutex_unlock(&m_ptmutex); }
#elif XPLATFORMTHREADS_WINDOWS
protected:
unsigned int m_nWaiterCount;
CRITICAL_SECTION m_csectWaiterCount;
HANDLE m_hndSemaphoreSignaller; // We keep this semaphore always at 0 count (non-signalled). We use it to release a controlled number of threads.
HANDLE m_hndEventAllWaitersReleased; // auto-reset
HANDLE m_hndMutex; // the mutex associated with the condition
bool m_bBroadcastSignalled; // means that the last waiter must signal m_hndEventAllWaitersReleased when done waiting
protected:
// - - - - - - - - - - - - - - - - - - - - - - - -
bool await_signal_win32(DWORD dwTimeout)
{
::EnterCriticalSection(&m_csectWaiterCount);
++m_nWaiterCount;
::LeaveCriticalSection(&m_csectWaiterCount);
// This is the actual wait for the signal
bool bWaitSucceeded = ::SignalObjectAndWait(m_hndMutex, m_hndSemaphoreSignaller, dwTimeout, FALSE) == WAIT_OBJECT_0;
//
::EnterCriticalSection(&m_csectWaiterCount);
bool bLastWaiter = --m_nWaiterCount==0 && m_bBroadcastSignalled;
::LeaveCriticalSection(&m_csectWaiterCount);
// re-acquire the mutex
if (bLastWaiter)
::SignalObjectAndWait(m_hndEventAllWaitersReleased, m_hndMutex, INFINITE, FALSE);
else
::WaitForSingleObject(m_hndMutex, INFINITE);
return bWaitSucceeded;
}
public:
inline bool await_signal(timediff td) { return await_signal_win32((win32_milliseconds(td))); }
inline void await_signal() { await_signal_win32(INFINITE); }
OSDependentObject() : m_nWaiterCount(0), m_bBroadcastSignalled(false)
{
EnsureThreadingInitialized();
::InitializeCriticalSection(&m_csectWaiterCount);
m_hndEventAllWaitersReleased = ::CreateEvent(
0, // security
FALSE, // auto-reset
FALSE, // initial state non-sognalled
0); // name
m_hndSemaphoreSignaller = ::CreateSemaphore(
0, // security
0, // initial count (and will stay this way)
0x100000, // maximum count (should be as large as the maximum number of waiting threads)
0); // name
m_hndMutex = ::CreateMutex(
0, // security
FALSE, // not owned initially
0); // name
//if (m_hndEventAllWaitersReleased==INVALID_HANDLE_VALUE || m_hndSemaphoreSignaller==INVALID_HANDLE_VALUE)
// throw something();
}
~OSDependentObject()
{
::CloseHandle(m_hndMutex);
::CloseHandle(m_hndSemaphoreSignaller);
::CloseHandle(m_hndEventAllWaitersReleased);
::DeleteCriticalSection(&m_csectWaiterCount);
}
inline void signal_unicast()
{
::EnterCriticalSection(&m_csectWaiterCount);
unsigned int nWaiters = m_nWaiterCount;
::LeaveCriticalSection(&m_csectWaiterCount);
if (nWaiters)
::ReleaseSemaphore(m_hndSemaphoreSignaller, 1, 0); // release 1 semaphore credit to release one waiting thread
}
void signal_broadcast()
{
::EnterCriticalSection(&m_csectWaiterCount);
unsigned int nWaiters = m_nWaiterCount;
if (nWaiters)
{
m_bBroadcastSignalled = true;
::ReleaseSemaphore(m_hndSemaphoreSignaller, nWaiters, 0); // release as many credits as there are waiting threads
::LeaveCriticalSection(&m_csectWaiterCount);
::WaitForSingleObject(m_hndEventAllWaitersReleased, INFINITE);
// at this point all threads are waiting on m_hndMutex, which would be released outside this function call
m_bBroadcastSignalled = false;
}
else
// no one is waiting
::LeaveCriticalSection(&m_csectWaiterCount);
}
//------------------------------------------------
inline void obtain_mutex() { ::WaitForSingleObject(m_hndMutex, INFINITE); }
inline bool tryobtain_mutex() { return ::WaitForSingleObject(m_hndMutex,0) == WAIT_OBJECT_0; }
inline void release_mutex() { ::ReleaseMutex(m_hndMutex); }
//------------------------------------------------
#endif // OS switch
};
void ThreadConditionSignal::obtain_mutex()
{
m_osdepobj.obtain_mutex();
}
bool ThreadConditionSignal::tryobtain_mutex() { return m_osdepobj.tryobtain_mutex(); }
void ThreadConditionSignal::release_mutex()
{
m_osdepobj.release_mutex();
}
void ThreadConditionSignal::await_condition() { m_osdepobj.await_signal(); }
bool ThreadConditionSignal::await_condition(timediff tdTimeout) { return m_osdepobj.await_signal(tdTimeout); }
void ThreadConditionSignal::signal_condition_single() { m_osdepobj.signal_unicast(); }
void ThreadConditionSignal::signal_condition_broadcast() { m_osdepobj.signal_broadcast(); }
ThreadConditionSignal::ThreadConditionSignal() : m_osdepobj(*new OSDependentObject) {}
ThreadConditionSignal::~ThreadConditionSignal() { delete &m_osdepobj; }
#if XPLATFORMTHREADS_POSIX
namespace // anon
{
inline int max_FIFO_schedparam()
{
static const int max_priority = ::sched_get_priority_max(SCHED_FIFO);
return max_priority;
}
inline int schedparam_by_percentage(unsigned short percentage)
{
return (max_FIFO_schedparam()*10*percentage+500)/1000;
}
class POSIXThreadPriority
{
public:
int m_SchedPolicy;
int m_SchedPriority;
POSIXThreadPriority(ThreadPriority pri)
{
switch (pri)
{
case ThreadPriority::TimeCritical: m_SchedPolicy=SCHED_FIFO, m_SchedPriority=schedparam_by_percentage(80); break;
case ThreadPriority::AboveNormal: m_SchedPolicy=SCHED_FIFO, m_SchedPriority=schedparam_by_percentage(20); break;
case ThreadPriority::BelowNormal: // fall through to normal; nothing is below normal in POSIX
case ThreadPriority::Normal: // fall through to default
default: m_SchedPolicy=SCHED_OTHER, m_SchedPriority=0; break;
}
}
};
} // namespace anonymous
#endif // XPLATFORMTHREADS_POSIX
#if XPLATFORMTHREADS_WINDOWS
namespace // anon
{
inline int WinThreadPriority(ThreadPriority pri)
{
switch (pri)
{
case ThreadPriority::BelowNormal: return THREAD_PRIORITY_BELOW_NORMAL;
case ThreadPriority::AboveNormal: return THREAD_PRIORITY_ABOVE_NORMAL;
case ThreadPriority::TimeCritical: return THREAD_PRIORITY_TIME_CRITICAL;
case ThreadPriority::Normal: // fall through to default
default: return THREAD_PRIORITY_NORMAL;
}
}
} // namespace anon
#endif // XPLATFORMTHREADS_WINDOWS
void SetMyThreadPriority(ThreadPriority pri)
{
#if XPLATFORMTHREADS_WINDOWS
::SetThreadPriority(::GetCurrentThread(), WinThreadPriority(pri));
#endif // XPLATFORMTHREADS_WINDOWS
#if XPLATFORMTHREADS_POSIX
const POSIXThreadPriority posixpri(pri);
sched_param sparam;
::memset(&sparam, 0, sizeof(sparam));
sparam.sched_priority = posixpri.m_SchedPriority;
#if defined(__linux__)
::sched_setscheduler(0, posixpri.m_SchedPolicy, &sparam); // linux uses this function instead of pthread_
#else
pthread_setschedparam(pthread_self(), posixpri.m_SchedPolicy, &sparam);
#endif
#endif // XPLATFORMTHREADS_POSIX
}
struct ThreadWrapperData
{
ThreadFunction *func;
ThreadFunctionArgument arg;
};
#if XPLATFORMTHREADS_WINDOWS
static unsigned int __stdcall ThreadWrapper(void * arg)
{
register ThreadWrapperData *twd = reinterpret_cast<ThreadWrapperData*>(arg);
ThreadFunction *func=twd->func;
ThreadFunctionArgument farg=twd->arg;
delete twd;
return DWORD(func(farg));
}
#elif XPLATFORMTHREADS_POSIX
static void * ThreadWrapper(void *arg)
{
register ThreadWrapperData *twd = reinterpret_cast<ThreadWrapperData*>(arg);
ThreadFunction *func=twd->func;
ThreadFunctionArgument farg=twd->arg;
delete twd;
return reinterpret_cast<void*>(func(farg));
}
typedef void*(ThreadWrapperFunction)(void*);
static ThreadWrapperFunction *ThunkedThreadWrapper = ThreadWrapper;
#endif // OS switch
class ThreadHandle::OSDependent
{
public:
static void StartThread(ThreadWrapperData *, ThreadHandle &, ThreadPriority);
static bool KillThread(ThreadHandle);
static bool JoinThread(ThreadHandle, ThreadFunctionReturnType*);
static void Close(ThreadHandle);
#if XPLATFORMTHREADS_WINDOWS
static inline uintptr_t from_oshandle(HANDLE h) { return reinterpret_cast<uintptr_t>(h); }
static inline HANDLE to_oshandle(uintptr_t h) { return reinterpret_cast<HANDLE>(h); }
#elif XPLATFORMTHREADS_POSIX
static inline uintptr_t from_oshandle(pthread_t pt) { return uintptr_t(pt); }
static inline pthread_t to_oshandle(uintptr_t h) { return pthread_t(h); }
#endif // OS switch
};
#if XPLATFORMTHREADS_WINDOWS
const ThreadHandle ThreadHandle::Invalid(OSDependent::from_oshandle(INVALID_HANDLE_VALUE));
#elif XPLATFORMTHREADS_POSIX
const ThreadHandle ThreadHandle::Invalid(OSDependent::from_oshandle(0));
#endif // OS switch
inline void ThreadHandle::OSDependent::StartThread(ThreadWrapperData *ptwdata, ThreadHandle &th, ThreadPriority pri)
{
#if XPLATFORMTHREADS_WINDOWS
uintptr_t h = ::_beginthreadex(
0, // no security attributes, not inheritable
0, // default stack size
ThreadWrapper, // function to call
(void*)(ptwdata), // argument for function
0, // creation flags
0 // where to store thread ID
);
if (h)
{
th.m_oshandle = h;
if (pri!=ThreadPriority::Normal)
::SetThreadPriority(to_oshandle(h), WinThreadPriority(pri));
}
else
th=Invalid;
#elif XPLATFORMTHREADS_POSIX
pthread_attr_t my_thread_attr, *pmy_thread_attr = 0;
sched_param my_schedparam;
if (pri!=ThreadPriority::Normal)
{
pmy_thread_attr = &my_thread_attr;
const POSIXThreadPriority posixpriority(pri);
int result;
result = pthread_attr_init (pmy_thread_attr);
result = pthread_attr_setschedpolicy(pmy_thread_attr, posixpriority.m_SchedPolicy);
memset(&my_schedparam, 0, sizeof(my_schedparam));
my_schedparam.sched_priority = posixpriority.m_SchedPriority;
result = pthread_attr_setschedparam(pmy_thread_attr, &my_schedparam);
}
pthread_t pt;
int anyerr = pthread_create(
&pt, // variable for thread handle
pmy_thread_attr, // default attributes
ThunkedThreadWrapper,
ptwdata
);
if (anyerr)
th=Invalid;
else
th.m_oshandle = OSDependent::from_oshandle(pt);
#endif
}
inline bool ThreadHandle::OSDependent::KillThread(ThreadHandle h)
{
#if XPLATFORMTHREADS_WINDOWS
return ::TerminateThread(to_oshandle(h.m_oshandle), (DWORD)-1) != 0;
#elif XPLATFORMTHREADS_POSIX
return pthread_cancel(to_oshandle(h.m_oshandle)) == 0;
#endif
}
bool ThreadHandle::OSDependent::JoinThread(ThreadHandle h, ThreadFunctionReturnType *pretval)
{
#if XPLATFORMTHREADS_WINDOWS
const bool kbReturnedOk = (WAIT_OBJECT_0 == ::WaitForSingleObject(OSDependent::to_oshandle(h.m_oshandle), INFINITE));
if (kbReturnedOk && pretval)
{
DWORD dwExitCode;
::GetExitCodeThread(to_oshandle(h.m_oshandle), &dwExitCode);
*pretval = (ThreadFunctionReturnType)(dwExitCode);
}
return kbReturnedOk;
#endif
#if XPLATFORMTHREADS_POSIX
ThreadFunctionReturnType ptrExitCode = 0;
int join_return_code = pthread_join(to_oshandle(h.m_oshandle), (void**)ptrExitCode);
const bool kbReturnedOk = (0 == join_return_code);
if (0 != pretval)
{
*pretval = ptrExitCode;
}
return kbReturnedOk;
#endif
}
#if XPLATFORMTHREADS_WINDOWS
inline void ThreadHandle::OSDependent::Close(ThreadHandle h)
{
::CloseHandle(OSDependent::to_oshandle(h.m_oshandle));
}
#endif // XPLATFORMTHREADS_WINDOWS
#if XPLATFORMTHREADS_POSIX
inline void ThreadHandle::OSDependent::Close(ThreadHandle) {}
#endif // XPLATFORMTHREADS_POSIX
//**********************************************************************************************
class WCThreadRef::OSDependent
{
public:
static void GetCurrentThreadRef(WCThreadRef& tid);
#if XPLATFORMTHREADS_WINDOWS
static inline uintptr_t from_os(DWORD thread_id) { return (uintptr_t)(thread_id); }
static inline DWORD to_os(uintptr_t thread_id) { return (DWORD)(thread_id); }
#elif XPLATFORMTHREADS_POSIX
static inline uintptr_t from_os(pthread_t thread_id) { return (uintptr_t)(thread_id); }
static inline pthread_t to_os(uintptr_t thread_id) { return pthread_t(thread_id); }
#endif // OS switch
};
//**********************************************************************************************
inline void WCThreadRef::OSDependent::GetCurrentThreadRef(WCThreadRef& tid)
{
#if XPLATFORMTHREADS_WINDOWS
DWORD thread_id = ::GetCurrentThreadId();
tid.m_osThreadRef = OSDependent::from_os(thread_id);
#elif XPLATFORMTHREADS_POSIX
pthread_t thread_id = ::pthread_self();
tid.m_osThreadRef = OSDependent::from_os(thread_id);
#endif // OS switch
}
//**********************************************************************************************
ThreadHandle StartThread(ThreadFunction func, ThreadFunctionArgument arg, ThreadPriority thpri)
{
EnsureThreadingInitialized();
ThreadWrapperData *ptwdata = new ThreadWrapperData;
ptwdata->func = func;
ptwdata->arg = arg;
ThreadHandle thToReturn;
ThreadHandle::OSDependent::StartThread(ptwdata, thToReturn, thpri);
return thToReturn;
}
bool KillThread(ThreadHandle h)
{
EnsureThreadingInitialized();
return ThreadHandle::OSDependent::KillThread(h);
}
bool JoinThread(ThreadHandle h, ThreadFunctionReturnType *pretval)
{
EnsureThreadingInitialized();
return ThreadHandle::OSDependent::JoinThread(h, pretval);
}
void Close(ThreadHandle h)
{
EnsureThreadingInitialized();
return ThreadHandle::OSDependent::Close(h);
}
//*******************************************************************************************
WCThreadRef GetCurrentThreadRef()
{
EnsureThreadingInitialized(); // Is it necessary?
WCThreadRef tRefToReturn;
WCThreadRef::OSDependent::GetCurrentThreadRef(tRefToReturn);
return tRefToReturn;
}
//*******************************************************************************************
bool IsThreadExists(const WCThreadRef& threadRef)
{
#if XPLATFORMTHREADS_WINDOWS
DWORD dwThreadId = WCThreadRef::OSDependent::to_os((uintptr_t)threadRef);
HANDLE handle = ::OpenThread(SYNCHRONIZE, // dwDesiredAccess - use of the thread handle in any of the wait functions
FALSE, // bInheritHandle - processes do not inherit this handle
dwThreadId);
// Now we have the handle, check if the associated thread exists:
DWORD retVal = WaitForSingleObject(handle, 0);
if (retVal == WAIT_FAILED)
return false; // the thread does not exists
else
return true; // the thread exists
#elif XPLATFORMTHREADS_POSIX
pthread_t pthreadRef = WCThreadRef::OSDependent::to_os((uintptr_t)threadRef);
int retVal = pthread_kill(pthreadRef, 0); // send a signal to the thread, but do nothing
if (retVal == ESRCH)
return false; // the thread does not exists
else
return true; // the thread exists
#endif // OS switch
}
//*******************************************************************************************
bool operator==(const WCThreadRef& first, const WCThreadRef& second)
{
return (first.m_osThreadRef == second.m_osThreadRef);
}
bool operator!=(const WCThreadRef& first, const WCThreadRef& second)
{
return (first.m_osThreadRef != second.m_osThreadRef);
}
bool operator<(const WCThreadRef& first, const WCThreadRef& second)
{
return (first.m_osThreadRef < second.m_osThreadRef);
}
bool operator>(const WCThreadRef& first, const WCThreadRef& second)
{
return (first.m_osThreadRef > second.m_osThreadRef);
}
bool WCAtomicLock::obtain(const uint32_t in_num_trys)
{
bool retVal = false;
uint32_t timeOut = in_num_trys;
while (true)
{
retVal = Akupara::threading::atomic::compare_and_store<int32_t>(&m_the_lock, int32_t(0), int32_t(1));
if (retVal)
{
break;
}
else
{
if (--timeOut == 0)
{
break;
}
sleep_milliseconds(1000);
}
}
return retVal;
}
void WCAtomicLock::release()
{
m_the_lock = 0;
}
} // namespace wvThread
} // namespace wvNS {

View file

@ -0,0 +1,410 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __WCThreadSafe_h_
#define __WCThreadSafe_h_
/* Copy to include
#include "Threads/WCThreadSafe.h"
*/
//
// * WCThreadSafe.h (used to be called XPlatformOSServices.hpp)
// *
// * Consistent C++ interfaces to common Operating System services.
// *
// *
// *
// *
// * Created 2004-December-13 by Udi Barzilai as XPlatformOSServices.hpp
// * Moved to WCThreadSafe.h by Shai 26/10/2005
// * 26/10/2005: ThreadMutex now inhetites from ThreadMutexInited
// * namespace changed to wvThread
#include "WavesPublicAPI/wstdint.h"
#include <string>
#include "BasicTypes/WUDefines.h"
#if defined(__linux__) || defined(__MACOS__)
#define XPLATFORMOSSERVICES_UNIX 1
#endif
#if defined(_WIN32)
#define XPLATFORMOSSERVICES_WIN32 1
#endif
#if XPLATFORMOSSERVICES_WIN32
#define XPLATFORMTHREADS_WINDOWS 1
#elif XPLATFORMOSSERVICES_UNIX
#define XPLATFORMTHREADS_POSIX 1
#endif
namespace wvNS {
typedef uint32_t WTThreadSafetyType;
const WTThreadSafetyType kNoThreadSafetyNeeded = 0;
const WTThreadSafetyType kpthreadsmutexThreadSafety = 1;
namespace wvThread
{
//#include "BasicTypes/WavesAPISetAligment.h"
//Packing affects the layout of classes, and commonly, if packing changes across header files, there can be problems.
#ifdef _WINDOWS
#pragma pack(push)
#pragma pack(8)
#endif
#ifdef __MACOS__
#ifdef __GNUC__
#pragma pack(push, 8)
#endif
#endif
//--------------------------------------------------------
typedef int32_t timediff; // in microseconds
static const timediff ktdOneSecond = 1000*1000;
//--------------------------------------------------------
class timestamp
{
protected:
typedef uint32_t tickcount;
tickcount m_nMicroseconds; // may wrap around
static const tickcount ms_knWraparoundThreshold = ~tickcount(0) ^ (~tickcount(0)>>1); // half the range
public:
timestamp() : m_nMicroseconds(0) { /* uninitialized */ }
timestamp(const timestamp &_ts) : m_nMicroseconds(_ts.m_nMicroseconds) {}
timestamp &operator=(const timestamp &_rhs) { m_nMicroseconds = _rhs.m_nMicroseconds; return *this; }
explicit timestamp(tickcount _i) : m_nMicroseconds(_i) {}
uint32_t ticks() const { return m_nMicroseconds; }
timediff operator-(timestamp _rhs) const { return timediff(m_nMicroseconds-_rhs.m_nMicroseconds); }
timestamp & operator+=(timediff _t) { m_nMicroseconds+=_t; return *this; }
timestamp & operator-=(timediff _t) { m_nMicroseconds-=_t; return *this; }
timestamp operator+(timediff _t) const { return timestamp(m_nMicroseconds+_t); }
timestamp operator-(timediff _t) const { return timestamp(m_nMicroseconds-_t); }
bool operator==(timestamp _rhs) const { return m_nMicroseconds==_rhs.m_nMicroseconds; }
bool operator!=(timestamp _rhs) const { return m_nMicroseconds!=_rhs.m_nMicroseconds; }
bool operator< (timestamp _rhs) const { return m_nMicroseconds-_rhs.m_nMicroseconds >= ms_knWraparoundThreshold; }
static timestamp null() { return timestamp(0); }
bool is_null() const { return m_nMicroseconds==0; }
};
//--------------------------------------------------------
#ifdef __MACOS__
bool FindNetInterfaceByIPAddress(const char *sIP, char *sInterface);
#endif // MACOS
//--------------------------------------------------------
timestamp now();
//--------------------------------------------------------
DllExport void sleep(timediff);
DllExport void sleep_milliseconds(unsigned int nMillisecs);
//--------------------------------------------------------
void yield();
//--------------------------------------------------------
typedef uintptr_t os_dependent_handle_type;
//--------------------------------------------------------
typedef int ThreadFunctionReturnType;
typedef void * ThreadFunctionArgument;
//--------------------------------------------------------
typedef ThreadFunctionReturnType (ThreadFunction)(ThreadFunctionArgument);
//--------------------------------------------------------
class ThreadHandle
{
public:
class OSDependent;
protected:
uintptr_t m_oshandle; // hopefully this is good enough for all systems
public:
static const ThreadHandle Invalid;
protected:
ThreadHandle(uintptr_t n) : m_oshandle(n) {}
public:
ThreadHandle() : m_oshandle(Invalid.m_oshandle) {}
bool is_invalid() const { return !m_oshandle || m_oshandle==Invalid.m_oshandle; }
};
//--------------------------------------------------------
class ThreadPriority
{
public: enum value { BelowNormal=1, Normal=2, AboveNormal=3, TimeCritical=4 };
protected: value m_value;
public: ThreadPriority(value v) : m_value(v) {}
public: operator value() const { return m_value; }
};
//--------------------------------------------------------
void SetMyThreadPriority(ThreadPriority);
//--------------------------------------------------------
ThreadHandle StartThread(ThreadFunction, ThreadFunctionArgument, ThreadPriority=ThreadPriority::Normal);
bool JoinThread(ThreadHandle, ThreadFunctionReturnType * = 0);
bool KillThread(ThreadHandle); // use only for abnormal termination
void Close(ThreadHandle); // should be called once for every handle obtained from StartThread.
//--------------------------------------------------------
//--------------------------------------------------------
class DllExport noncopyableobject
{
protected:
noncopyableobject() {}
private:
noncopyableobject(const noncopyableobject &);
noncopyableobject & operator=(const noncopyableobject &);
};
//--------------------------------------------------------
//--------------------------------------------------------
// Thread Mutex class that needs to be explicitly initialized
class DllExport ThreadMutexInited : public noncopyableobject
{
protected:
class OSDependentMutex;
OSDependentMutex* m_osdmutex;
public:
ThreadMutexInited();
~ThreadMutexInited();
void init();
void uninit();
inline bool is_init() { return 0 != m_osdmutex; }
void obtain();
bool tryobtain();
void release();
private:
ThreadMutexInited(const ThreadMutexInited&); // cannot be copied
ThreadMutexInited& operator=(const ThreadMutexInited&); // cannot be copied
public:
class lock : public noncopyableobject
{
protected:
ThreadMutexInited &m_mutex;
public:
inline lock(ThreadMutexInited &mtx) : m_mutex(mtx) { m_mutex.obtain(); }
inline ~lock() { m_mutex.release(); }
};
class trylock : public noncopyableobject
{
protected:
ThreadMutexInited &m_mutex;
bool m_bObtained;
public:
inline trylock(ThreadMutexInited &mtx) : m_mutex(mtx), m_bObtained(false) { m_bObtained = m_mutex.tryobtain(); }
inline ~trylock() { if (m_bObtained) m_mutex.release(); }
inline operator bool() const { return m_bObtained; }
};
};
//--------------------------------------------------------
// Thread Mutex class that is automatically initialized
class ThreadMutex : public ThreadMutexInited
{
public:
ThreadMutex() {init();}
};
//--------------------------------------------------------
class DllExport ThreadConditionSignal : public noncopyableobject
{
protected:
class OSDependentObject;
OSDependentObject &m_osdepobj;
protected:
void obtain_mutex();
bool tryobtain_mutex();
void release_mutex();
public:
class lock : public noncopyableobject
{
protected:
ThreadConditionSignal &m_tcs;
public:
lock(ThreadConditionSignal &tcs) : m_tcs(tcs) { m_tcs.obtain_mutex(); }
~lock() { m_tcs.release_mutex(); }
};
class trylock : public noncopyableobject
{
protected:
ThreadConditionSignal &m_tcs;
bool m_bObtained;
public:
trylock(ThreadConditionSignal &tcs) : m_tcs(tcs), m_bObtained(false) { m_bObtained = m_tcs.tryobtain_mutex(); }
~trylock() { if (m_bObtained) m_tcs.release_mutex(); }
operator bool() const { return m_bObtained; }
};
public:
ThreadConditionSignal();
~ThreadConditionSignal();
// IMPORTANT: All of the functions below MUST be called ONLY while holding a lock for this object !!!
void await_condition();
bool await_condition(timediff tdTimeout);
void signal_condition_single();
void signal_condition_broadcast();
};
//--------------------------------------------------------
//--------------------------------------------------------
// A doorbell is a simple communication mechanism that allows
// one thread two wake another when there is some work to be done.
// The signal is 'clear on read'. This class is not intended for
// multi-way communication (i.e. more than two threads).
//#define XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR (!XPLATFORMTHREADS_WINDOWS && !XPLATFORMOSSERVICES_MACOS)
#ifdef XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
#undef XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
#endif
#define XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR 1
#if XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
class doorbell_type
{
protected:
ThreadConditionSignal m_signal;
bool m_rang;
protected:
template<bool wait_forever> bool wait_for_ring_internal(timediff timeout)
{// mutex
ThreadConditionSignal::lock guard(m_signal);
if (!m_rang)
{
if (wait_forever)
{
m_signal.await_condition();
}
else
{
m_signal.await_condition(timeout);
}
}
const bool rang = m_rang;
m_rang = false;
return rang;
}// mutex
public:
doorbell_type() : m_rang(false) {}
inline ~doorbell_type() {}
inline void ring()
{// mutex
ThreadConditionSignal::lock guard(m_signal);
m_rang = true;
m_signal.signal_condition_single();
}// mutex
inline bool wait_for_ring() { return wait_for_ring_internal<true>(0); }
inline bool wait_for_ring(timediff timeout) { return wait_for_ring_internal<false>(timeout); }
};
#else
class doorbell_type : public noncopyableobject
{
protected:
os_dependent_handle_type m_os_dependent_handle;
protected:
template<bool wait_forever> bool wait_for_ring_internal(timediff);
public:
doorbell_type();
~doorbell_type();
void ring();
bool wait_for_ring();
bool wait_for_ring(timediff timeout);
};
#endif // XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
//--------------------------------------------------------
//---------------------------------------------------------------
class DllExport WCThreadRef // Class which holds the threadRef, DWORD in Windows and pthread_t in POSIX (Mac, Unix)
{
public:
class OSDependent; // the class which contains the OS Dependent implementation
WCThreadRef() : m_osThreadRef(0) {}
bool is_invalid() const { return m_osThreadRef == 0;}
operator uintptr_t() const {return m_osThreadRef;}
protected:
uintptr_t m_osThreadRef;
WCThreadRef(uintptr_t n) : m_osThreadRef(n) {}
friend DllExport bool operator==(const WCThreadRef& first, const WCThreadRef& second);
friend DllExport bool operator!=(const WCThreadRef& first, const WCThreadRef& second);
friend DllExport bool operator<(const WCThreadRef& first, const WCThreadRef& second);
friend DllExport bool operator>(const WCThreadRef& first, const WCThreadRef& second);
};
DllExport WCThreadRef GetCurrentThreadRef(); // getting the current thread reference - cross-platform implemented
bool IsThreadExists(const WCThreadRef& threadRef); // correct to the very snapshot of time of execution
//---------------------------------------------------------------
class DllExport WCAtomicLock
{
public:
WCAtomicLock() : m_the_lock(0) {}
bool obtain(const uint32_t in_num_trys = 1);
void release();
private:
int32_t m_the_lock;
};
//#include "BasicTypes/WavesAPIResetAligment.h"
#ifdef _WINDOWS
#pragma pack(pop)
#endif
#ifdef __MACOS__
#ifdef __GNUC__
#pragma pack(pop)
#endif
#endif
class WCStThreadMutexLocker
{
public:
WCStThreadMutexLocker(wvNS::wvThread::ThreadMutexInited& in_mutex) :
m_mutex(in_mutex)
{
m_mutex.obtain();
}
~WCStThreadMutexLocker()
{
m_mutex.release();
}
protected:
wvNS::wvThread::ThreadMutexInited& m_mutex;
WCStThreadMutexLocker(const WCStThreadMutexLocker&);
WCStThreadMutexLocker& operator=(const WCStThreadMutexLocker&);
};
} // namespace wvThread
} //namespace wvNS {
#endif // #ifndef __WCThreadSafe_h_

View file

@ -0,0 +1,59 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __WavesPublicAPI_Defines_h__
#define __WavesPublicAPI_Defines_h__
/*Copy to include
#include "WavesPublicAPI_Defines.h"
*/
#ifdef __MACOS__
#ifdef __GNUC__
#define WPAPI_DllExport __attribute__ ((visibility("default")))
#define __WPAPI_CDECL
#define __WPAPI_STDCALL
#else
#define WPAPI_DllExport __declspec(export)
#define __WPAPI_CDECL
#define __WPAPI_STDCALL
#endif
#endif
#ifdef _WINDOWS
#define WPAPI_DllExport __declspec(dllexport)
#define __WPAPI_CDECL __cdecl
#define __WPAPI_STDCALL __stdcall
#endif
#ifdef __linux__
#define WPAPI_DllExport __attribute__ ((visibility("default")))
#define __WPAPI_CDECL
#define __WPAPI_STDCALL
#endif
#endif //__WavesPublicAPI_Defines_h__

View file

@ -0,0 +1,45 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////
// \file WTErr.h, defines basic error type and "No Error" code
// All users may use their own error codes with this type, as long as eNoErr remains defined here
///////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef __WTErr_h__
#define __WTErr_h__
/* Copy to include:
#include "WavesPublicAPI/WTErr.h"
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "WavesPublicAPI/wstdint.h"
typedef int32_t WTErr; // Waves Type Error
const WTErr eNoErr = 0;
#ifdef __cplusplus
} //extern "C" {
#endif
#endif // __WTErr_h__

View file

@ -0,0 +1,358 @@
/*
Copyright (C) 2013 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __stdint_h__
#define __stdint_h__
/* Copy to include
#include "wstdint.h"
*/
#ifdef __MACOS__
#include <stddef.h>
#include </usr/include/stdint.h> // Mac has this file in /usr/includez
#endif
#ifdef __linux__
#if ! defined(__STDC_LIMIT_MACROS)
#define __STDC_LIMIT_MACROS
#endif
#include <stddef.h>
#include </usr/include/stdint.h>
#endif
#if (defined (_WINDOWS) || defined(WIN32) || defined(WIN64))
#if (_MSC_VER > 1600) || defined(__MINGW64__)
// Taken from MSDN official page:
// In Visual Studio 2010 _MSC_VER is defined as 1600, In Visual Studio 2012 _MSC_VER is defined as 1700.
#include <stdint.h>
#else
#ifndef _STDINT_H
#define _STDINT_H // this will prevent Altura's CGBase.h from defining int32_t
#endif
/*
* ISO C 99 <stdint.h> for platforms that lack it.
* <http://www.opengroup.org/onlinepubs/007904975/basedefs/stdint.h.html>
*/
/* Get wchar_t, WCHAR_MIN, WCHAR_MAX. */
#include <stddef.h>
/* Get CHAR_BIT, LONG_MIN, LONG_MAX, ULONG_MAX. */
#include <limits.h>
/* Get those types that are already defined in other system include files. */
#if defined(__FreeBSD__)
# include <sys/inttypes.h>
#endif
#if defined(__sun) && HAVE_SYS_INTTYPES_H
# include <sys/inttypes.h>
/* Solaris 7 <sys/inttypes.h> has the types except the *_fast*_t types, and
the macros except for *_FAST*_*, INTPTR_MIN, PTRDIFF_MIN, PTRDIFF_MAX.
But note that <sys/int_types.h> contains only the type definitions! */
# define HAVE_SYSTEM_INTTYPES
#endif
#if (defined(__hpux) || defined(_AIX)) && HAVE_INTTYPES_H
# include <inttypes.h>
/* HP-UX 10 <inttypes.h> has nearly everything, except UINT_LEAST8_MAX,
UINT_FAST8_MAX, PTRDIFF_MIN, PTRDIFF_MAX. */
/* AIX 4 <inttypes.h> has nearly everything, except INTPTR_MIN, INTPTR_MAX,
UINTPTR_MAX, PTRDIFF_MIN, PTRDIFF_MAX. */
# define HAVE_SYSTEM_INTTYPES
#endif
#if !(defined(UNIX_CYGWIN32) && defined(__BIT_TYPES_DEFINED__))
# define NEED_SIGNED_INT_TYPES
#endif
#if !defined(HAVE_SYSTEM_INTTYPES)
/* 7.18.1.1. Exact-width integer types */
#if !defined(__FreeBSD__)
#if defined(_MSC_VER)
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else // _MSC_VER
#ifdef NEED_SIGNED_INT_TYPES
typedef signed char int8_t;
#endif
typedef unsigned char uint8_t;
#ifdef NEED_SIGNED_INT_TYPES
typedef short int16_t;
#endif
typedef unsigned short uint16_t;
#ifdef NEED_SIGNED_INT_TYPES
typedef int int32_t;
#endif
typedef unsigned int uint32_t;
#if 0
#ifdef NEED_SIGNED_INT_TYPES
typedef long int64_t;
#endif
typedef unsigned long uint64_t;
#elif 0
#ifdef NEED_SIGNED_INT_TYPES
typedef long long int64_t;
#endif
typedef unsigned long long uint64_t;
#endif
#endif // _MSC_VER
#endif /* !FreeBSD */
/* 7.18.1.2. Minimum-width integer types */
typedef int8_t int_least8_t;
typedef uint8_t uint_least8_t;
typedef int16_t int_least16_t;
typedef uint16_t uint_least16_t;
#if !defined(kAlturaAlreadyDefinesInt32)
typedef int32_t int_least32_t;
#endif
typedef uint32_t uint_least32_t;
typedef int64_t int_least64_t;
typedef uint64_t uint_least64_t;
/* 7.18.1.3. Fastest minimum-width integer types */
typedef int32_t int_fast8_t;
typedef uint32_t uint_fast8_t;
typedef int32_t int_fast16_t;
typedef uint32_t uint_fast16_t;
typedef int32_t int_fast32_t;
typedef uint32_t uint_fast32_t;
typedef int64_t int_fast64_t;
typedef uint64_t uint_fast64_t;
/* 7.18.1.4. Integer types capable of holding object pointers */
#if !defined(__FreeBSD__)
/* On some platforms (like IRIX6 MIPS with -n32) sizeof(void*) < sizeof(long),
but this doesn't matter here. */
#if !defined(_INTPTR_T_DEFINED)
typedef long intptr_t;
#define _INTPTR_T_DEFINED
#endif
#if !defined(_UINTPTR_T_DEFINED)
typedef unsigned long uintptr_t;
#define _UINTPTR_T_DEFINED
#endif
#endif /* !FreeBSD */
/* 7.18.1.5. Greatest-width integer types */
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
#if 0 || 0
typedef int32_t intmax_t;
typedef uint32_t uintmax_t;
#endif
/* 7.18.2. Limits of specified-width integer types */
//#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
/* 7.18.2.1. Limits of exact-width integer types */
#define INT8_MIN -128
#define INT8_MAX 127
#define UINT8_MAX 255U
#define INT16_MIN -32768
#define INT16_MAX 32767
#define UINT16_MAX 65535U
#define INT32_MIN (~INT32_MAX)
#define INT32_MAX 2147483647
#define UINT32_MAX 4294967295U
#if 0
#define INT64_MIN (~INT64_MIN)
#define INT64_MAX 9223372036854775807L
#define UINT64_MAX 18446744073709551615UL
#elif 0
#define INT64_MIN (~INT64_MIN)
#define INT64_MAX 9223372036854775807LL
#define UINT64_MAX 18446744073709551615ULL
#endif
/* 7.18.2.2. Limits of minimum-width integer types */
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST8_MAX INT8_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST16_MAX INT16_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST32_MAX INT32_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#if 0 || 0
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST64_MAX UINT64_MAX
#endif
/* 7.18.2.3. Limits of fastest minimum-width integer types */
#define INT_FAST8_MIN INT32_MIN
#define INT_FAST8_MAX INT32_MAX
#define UINT_FAST8_MAX UINT32_MAX
#define INT_FAST16_MIN INT32_MIN
#define INT_FAST16_MAX INT32_MAX
#define UINT_FAST16_MAX UINT32_MAX
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST32_MAX INT32_MAX
#define UINT_FAST32_MAX UINT32_MAX
#if 0 || 0
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST64_MAX UINT64_MAX
#endif
/* 7.18.2.4. Limits of integer types capable of holding object pointers */
#define INTPTR_MIN LONG_MIN
#define INTPTR_MAX LONG_MAX
#define UINTPTR_MAX ULONG_MAX
/* 7.18.2.5. Limits of greatest-width integer types */
#if 0 || 0
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
#else
#define INTMAX_MIN INT32_MIN
#define INTMAX_MAX INT32_MAX
#define UINTMAX_MAX UINT32_MAX
#endif
/* 7.18.3. Limits of other integer types */
#define PTRDIFF_MIN (~(ptrdiff_t)0 << (sizeof(ptrdiff_t)*CHAR_BIT-1))
#define PTRDIFF_MAX (~PTRDIFF_MIN)
/* This may be wrong... */
#define SIG_ATOMIC_MIN 0
#define SIG_ATOMIC_MAX 127
//#define SIZE_MAX (~(size_t)0)
/* wchar_t limits already defined in <stddef.h>. */
/* wint_t limits already defined in <wchar.h>. */
//#endif
/* 7.18.4. Macros for integer constants */
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
/* 7.18.4.1. Macros for minimum-width integer constants */
#ifdef INT8_C
#undef INT8_C
#endif
#define INT8_C(x) x
#ifdef UINT8_C
#undef UINT8_C
#endif
#define UINT8_C(x) x##U
#ifdef INT16_C
#undef INT16_C
#endif
#define INT16_C(x) x
#ifdef UINT16_C
#undef UINT16_C
#endif
#define UINT16_C(x) x##U
#ifdef INT32_C
#undef INT32_C
#endif
#define INT32_C(x) x
#ifdef UINT32_C
#undef UINT32_C
#endif
#define UINT32_C(x) x##U
// INT64_C and UINT64_C definitions
#ifdef INT64_C
#undef INT64_C
#endif
#ifdef UINT64_C
#undef UINT64_C
#endif
#if 0
#define INT64_C(x) x##L
#define UINT64_C(x) x##UL
#elif 0
#define INT64_C(x) x##LL
#define UINT64_C(x) x##ULL
#endif // #if 0
/* 7.18.4.2. Macros for greatest-width integer constants */
// INTMAX_C and UINTMAX_C definitions
#ifdef INTMAX_C
#undef INTMAX_C
#endif
#ifdef UINTMAX_C
#undef UINTMAX_C
#endif
#if 0
#define INTMAX_C(x) x##L
#define UINTMAX_C(x) x##UL
#elif 0
#define INTMAX_C(x) x##LL
#define UINTMAX_C(x) x##ULL
#else
#define INTMAX_C(x) x
#define UINTMAX_C(x) x##U
#endif
#endif
#endif /* !HAVE_SYSTEM_INTTYPES */
#endif /* (_MSC_VER < 1400) */
#endif /* #ifdef _WINDOWS */
#endif /* __stdint_h__ */

View file

@ -0,0 +1,73 @@
#!/usr/bin/env python
from waflib.extras import autowaf as autowaf
import os
import sys
import re
# Library version (UNIX style major, minor, micro)
# major increment <=> incompatible changes
# minor increment <=> compatible changes (additions)
# micro increment <=> no interface changes
WAVESAUDIOBACKEND_VERSION = '0.0.1'
I18N_PACKAGE = 'wavesaudio-backend'
# Mandatory variables
top = '.'
out = 'build'
def options(opt):
autowaf.set_options(opt)
def configure(conf):
autowaf.configure(conf)
def build(bld):
obj = bld(features = 'cxx cxxshlib')
if bld.env['build_target'] == 'mountain_lion':
obj.framework = 'CoreMidi'
else:
obj.framework = 'CoreMIDI'
obj.source = [
'waves_audiobackend.cc',
'waves_audiobackend.latency.cc',
'waves_audiobackend.midi.cc',
'waves_audiobackend.port_engine.cc',
'waves_dataport.cc',
'waves_audioport.cc',
'waves_midiport.cc',
'waves_midi_device_manager.cc',
'waves_midi_device.cc',
'waves_midi_event.cc',
'waves_midi_buffer.cc',
'wavesapi/refmanager/WCRefManager.cpp',
'wavesapi/devicemanager/WCMRAudioDeviceManager.cpp',
'wavesapi/devicemanager/WCMRCoreAudioDeviceManager.cpp',
'wavesapi/devicemanager/WCMRNativeAudio.cpp',
'wavesapi/threads/WCThreadSafe.cpp',
'portmidi/src/pm_common/pmutil.c',
'portmidi/src/pm_common/portmidi.c',
'portmidi/src/pm_mac/pmmac.c',
'portmidi/src/pm_mac/pmmacosxcm.c',
'portmidi/src/pm_mac/finddefault.c',
'portmidi/src/pm_mac/readbinaryplist.c',
'portmidi/src/porttime/ptmacosx_mach.c'
]
obj.includes = ['.',
'wavesapi',
'wavesapi/refmanager',
'wavesapi/wavespublicapi',
'wavesapi/devicemanager',
'wavesapi/miscutils',
'portmidi',
'portmidi/src/pm_common'
]
obj.cxxflags = [ '-fPIC' ]
obj.name = 'waves_audiobackend'
obj.target = 'waves_audiobackend'
obj.use = [ 'libardour', 'libpbd' ]
obj.vnum = WAVESAUDIOBACKEND_VERSION
obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'backends')
obj.defines = ['PACKAGE="' + I18N_PACKAGE + '"',
'__MACOS__',
'ARDOURBACKEND_DLL_EXPORTS'
]