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,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;
}