mirror of
https://github.com/cookiengineer/audacity
synced 2025-11-08 22:23:59 +01:00
Locate and position the current Audacity source code, and clear a variety of old junk out of the way into junk-branches
This commit is contained in:
952
src/effects/audiounits/AudioUnitEffect.cpp
Normal file
952
src/effects/audiounits/AudioUnitEffect.cpp
Normal file
@@ -0,0 +1,952 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
AudioUnitEffect.cpp
|
||||
|
||||
Dominic Mazzoni
|
||||
|
||||
*******************************************************************//**
|
||||
|
||||
\class AudioUnitEffect
|
||||
\brief An Effect class that handles a wide range of effects. ??Mac only??
|
||||
|
||||
*//****************************************************************//**
|
||||
|
||||
\class AudioUnitGUIControl
|
||||
\brief Used with AudioUnitEffect
|
||||
|
||||
*//****************************************************************//**
|
||||
|
||||
\class AudioUnitDialog
|
||||
\brief A Dialog used with AudioUnitEffect
|
||||
|
||||
*//*******************************************************************/
|
||||
|
||||
#include "AudioUnitEffect.h"
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/control.h>
|
||||
#include <wx/frame.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/settings.h>
|
||||
#include <wx/tokenzr.h>
|
||||
|
||||
#if ((wxMAJOR_VERSION == 2) && (wxMINOR_VERSION < 6))
|
||||
#error Audio Units support requires wxMac 2.6
|
||||
#endif
|
||||
|
||||
#include <wx/mac/private.h>
|
||||
|
||||
//
|
||||
// Forward declarations of GUI classes
|
||||
//
|
||||
|
||||
class AudioUnitGUIControl : public wxControl
|
||||
{
|
||||
public:
|
||||
inline AudioUnitGUIControl(wxWindow *parent, wxWindowID id,
|
||||
wxPoint pos, wxSize size,
|
||||
ControlRef controlRef) {
|
||||
Create(parent, id, pos, size, controlRef);
|
||||
}
|
||||
|
||||
virtual ~AudioUnitGUIControl();
|
||||
bool Create(wxWindow *parent, wxWindowID id,
|
||||
wxPoint pos, wxSize size,
|
||||
ControlRef controlRef);
|
||||
void OnMouse(wxMouseEvent &event);
|
||||
|
||||
private:
|
||||
short GetModifiers(wxMouseEvent &event);
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
class AudioUnitDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
AudioUnitDialog(wxWindow *parent, wxWindowID id, wxString title,
|
||||
AudioUnit unit,
|
||||
AudioUnitCarbonView carbonView,
|
||||
Effect *effect);
|
||||
virtual ~AudioUnitDialog();
|
||||
|
||||
void RemoveHandler();
|
||||
|
||||
void OnOK(wxCommandEvent &event);
|
||||
void OnCancel(wxCommandEvent &event);
|
||||
void OnPreview(wxCommandEvent &event);
|
||||
|
||||
private:
|
||||
AudioUnit mUnit;
|
||||
AudioUnitGUIControl *mGUIControl;
|
||||
wxBoxSizer *mMainSizer;
|
||||
Effect *mEffect;
|
||||
|
||||
EventHandlerRef mHandlerRef;
|
||||
EventHandlerUPP mHandlerUPP;
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
//
|
||||
// AudioUnitEffect
|
||||
//
|
||||
|
||||
AudioUnitEffect::AudioUnitEffect(wxString name, Component component):
|
||||
mName(name),
|
||||
mComponent(component)
|
||||
{
|
||||
SetEffectFlags(PLUGIN_EFFECT | PROCESS_EFFECT);
|
||||
|
||||
mUnit = NULL;
|
||||
OpenAComponent(mComponent, &mUnit);
|
||||
}
|
||||
|
||||
AudioUnitEffect::~AudioUnitEffect()
|
||||
{
|
||||
if (mUnit) {
|
||||
CloseComponent(mUnit);
|
||||
}
|
||||
}
|
||||
|
||||
wxString AudioUnitEffect::GetEffectName()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
std::set<wxString> AudioUnitEffect::GetEffectCategories()
|
||||
{
|
||||
return std::set<wxString>();
|
||||
}
|
||||
|
||||
wxString AudioUnitEffect::GetEffectIdentifier()
|
||||
{
|
||||
wxStringTokenizer st(mName, wxT(" "));
|
||||
wxString id;
|
||||
|
||||
// CamelCase the name
|
||||
while (st.HasMoreTokens()) {
|
||||
wxString tok = st.GetNextToken();
|
||||
|
||||
id += tok.Left(1).MakeUpper() + tok.Mid(1);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
wxString AudioUnitEffect::GetEffectAction()
|
||||
{
|
||||
return wxString::Format(_("Performing Effect: %s"),
|
||||
mName.c_str());
|
||||
}
|
||||
|
||||
bool AudioUnitEffect::Init()
|
||||
{
|
||||
if (!mUnit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mSupportsMono = SetRateAndChannels(mUnit, 1, mProjectRate);
|
||||
mSupportsStereo = SetRateAndChannels(mUnit, 2, mProjectRate);
|
||||
|
||||
if (!mSupportsMono && !mSupportsStereo) {
|
||||
|
||||
mSupportsMono = SetRateAndChannels(mUnit, 1, 44100.0);
|
||||
mSupportsStereo = SetRateAndChannels(mUnit, 2, 44100.0);
|
||||
|
||||
if (!mSupportsMono && !mSupportsStereo) {
|
||||
printf("Audio Unit doesn't support mono or stereo.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioUnitEffect::PromptUser()
|
||||
{
|
||||
OSErr result;
|
||||
ComponentDescription desc;
|
||||
Component carbonViewComponent = NULL;
|
||||
AudioUnitCarbonView carbonView = NULL;
|
||||
|
||||
GetComponentInfo(mComponent, &desc, 0, 0, 0);
|
||||
carbonViewComponent = GetCarbonViewComponent(desc.componentSubType);
|
||||
result = OpenAComponent(carbonViewComponent, &carbonView);
|
||||
if (result != 0) {
|
||||
printf("Couldn't open carbon view component\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
AudioUnitDialog dlog(mParent, -1, mName,
|
||||
mUnit, carbonView, this);
|
||||
dlog.CentreOnParent();
|
||||
dlog.ShowModal();
|
||||
|
||||
CloseComponent(carbonView);
|
||||
|
||||
return (dlog.GetReturnCode() == wxID_OK);
|
||||
}
|
||||
|
||||
bool AudioUnitEffect::Process()
|
||||
{
|
||||
bool bGoodResult = true;
|
||||
|
||||
CopyInputTracks();
|
||||
|
||||
TrackListIterator iter(mOutputTracks);
|
||||
|
||||
int count = 0;
|
||||
Track *left = iter.First();
|
||||
Track *right;
|
||||
while(left) {
|
||||
sampleCount lstart, rstart;
|
||||
sampleCount len;
|
||||
GetSamples((WaveTrack *)left, &lstart, &len);
|
||||
|
||||
right = NULL;
|
||||
if (left->GetLinked() && mSupportsStereo) {
|
||||
right = iter.Next();
|
||||
GetSamples((WaveTrack *)right, &rstart, &len);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (!mSupportsStereo && right) {
|
||||
// If the effect is mono, apply to each channel separately
|
||||
|
||||
success = ProcessStereo(count, (WaveTrack *)left, NULL,
|
||||
lstart, 0, len);
|
||||
if (success)
|
||||
success = ProcessStereo(count, (WaveTrack *)right, NULL,
|
||||
rstart, 0, len);
|
||||
}
|
||||
else success = ProcessStereo(count,
|
||||
(WaveTrack *)left, (WaveTrack *)right,
|
||||
lstart, rstart, len);
|
||||
if (!success) {
|
||||
bGoodResult = false;
|
||||
break;
|
||||
}
|
||||
|
||||
left = iter.Next();
|
||||
count++;
|
||||
}
|
||||
|
||||
ReplaceProcessedTracks(bGoodResult);
|
||||
|
||||
return bGoodResult;
|
||||
}
|
||||
|
||||
void AudioUnitEffect::End()
|
||||
{
|
||||
}
|
||||
|
||||
bool AudioUnitEffect::SetRateAndChannels(AudioUnit unit,
|
||||
int numChannels,
|
||||
Float64 sampleRate)
|
||||
{
|
||||
AudioStreamBasicDescription streamFormat;
|
||||
ComponentResult auResult;
|
||||
|
||||
auResult = AudioUnitSetProperty(unit, kAudioUnitProperty_SampleRate,
|
||||
kAudioUnitScope_Global, 0,
|
||||
&sampleRate, sizeof(Float64));
|
||||
if (auResult != 0) {
|
||||
printf("Didn't accept sample rate\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
streamFormat.mSampleRate = sampleRate;
|
||||
streamFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
streamFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked |
|
||||
kAudioFormatFlagIsNonInterleaved;
|
||||
streamFormat.mBitsPerChannel = 32;
|
||||
streamFormat.mChannelsPerFrame = numChannels;
|
||||
streamFormat.mFramesPerPacket = 1;
|
||||
streamFormat.mBytesPerFrame = 4;
|
||||
streamFormat.mBytesPerPacket = 4;
|
||||
|
||||
auResult = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Input, 0,
|
||||
&streamFormat,
|
||||
sizeof(AudioStreamBasicDescription));
|
||||
|
||||
if (auResult != 0)
|
||||
return false;
|
||||
|
||||
auResult = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Output, 0,
|
||||
&streamFormat,
|
||||
sizeof(AudioStreamBasicDescription));
|
||||
|
||||
if (auResult != 0)
|
||||
return false;
|
||||
|
||||
auResult = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Global, 0,
|
||||
&streamFormat,
|
||||
sizeof(AudioStreamBasicDescription));
|
||||
|
||||
if (auResult != 0) {
|
||||
printf("Didn't accept global stream format\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioUnitEffect::CopyParameters(AudioUnit srcUnit, AudioUnit dstUnit)
|
||||
{
|
||||
ComponentResult auResult;
|
||||
int numParameters, i;
|
||||
AudioUnitParameterID *parameters;
|
||||
Float32 parameterValue;
|
||||
UInt32 size;
|
||||
|
||||
// Get number of parameters by passing NULL in the data field and
|
||||
// getting back the size of the parameter list
|
||||
|
||||
size = 0;
|
||||
auResult = AudioUnitGetProperty(srcUnit, kAudioUnitProperty_ParameterList,
|
||||
kAudioUnitScope_Global, 0,
|
||||
NULL, &size);
|
||||
if (auResult != 0) {
|
||||
printf("Couldn't get number of parameters\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now get the list of all parameter IDs
|
||||
|
||||
numParameters = size / sizeof(AudioUnitParameterID);
|
||||
parameters = new AudioUnitParameterID[numParameters];
|
||||
auResult = AudioUnitGetProperty(srcUnit, kAudioUnitProperty_ParameterList,
|
||||
kAudioUnitScope_Global, 0,
|
||||
parameters, &size);
|
||||
if (auResult != 0) {
|
||||
printf("Couldn't get parameter list\n");
|
||||
delete[] parameters;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy the parameters from the main unit to the unit specific to
|
||||
// this track
|
||||
|
||||
for(i=0; i<numParameters; i++) {
|
||||
auResult = AudioUnitGetParameter(srcUnit, parameters[i],
|
||||
kAudioUnitScope_Global, 0,
|
||||
¶meterValue);
|
||||
if (auResult != 0) {
|
||||
printf("Couldn't get parameter %d: ID=%d\n", i, (int)parameters[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
auResult = AudioUnitSetParameter(dstUnit, parameters[i],
|
||||
kAudioUnitScope_Global, 0,
|
||||
parameterValue, 0);
|
||||
if (auResult != 0)
|
||||
printf("Couldn't set parameter %d: ID=%d\n", i, (int)parameters[i]);
|
||||
}
|
||||
|
||||
delete[] parameters;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioUnitEffect::ProcessStereo(int count,
|
||||
WaveTrack *left, WaveTrack *right,
|
||||
sampleCount lstart,
|
||||
sampleCount rstart,
|
||||
sampleCount len)
|
||||
{
|
||||
int numChannels = (right != NULL ? 2 : 1);
|
||||
Float64 sampleRate = left->GetRate();
|
||||
AudioUnit trackUnit = mUnit;
|
||||
AURenderCallbackStruct callbackStruct;
|
||||
AudioTimeStamp timeStamp;
|
||||
AudioBufferList *bufferList = NULL;
|
||||
ComponentResult auResult;
|
||||
int waveTrackBlockSize;
|
||||
UInt32 size;
|
||||
UInt32 unitBlockSize;
|
||||
float *leftBuffer;
|
||||
float *rightBuffer;
|
||||
bool success = true;
|
||||
|
||||
if (!SetRateAndChannels(trackUnit, numChannels, sampleRate)) {
|
||||
printf("Unable to setup audio unit for channels=%d rate=%.1f\n",
|
||||
numChannels, sampleRate);
|
||||
return false;
|
||||
}
|
||||
|
||||
unitBlockSize = 0;
|
||||
size = sizeof(UInt32);
|
||||
auResult = AudioUnitGetProperty(trackUnit,
|
||||
kAudioUnitProperty_MaximumFramesPerSlice,
|
||||
kAudioUnitScope_Global,
|
||||
0,
|
||||
&unitBlockSize,
|
||||
&size);
|
||||
|
||||
if (unitBlockSize == 0 || auResult != 0) {
|
||||
printf("Warning: didn't get audio unit's MaximumFramesPerSlice\n");
|
||||
printf("Trying to set MaximumFramesPerSlice to 512\n");
|
||||
unitBlockSize = 512;
|
||||
auResult = AudioUnitSetProperty(trackUnit,
|
||||
kAudioUnitProperty_MaximumFramesPerSlice,
|
||||
kAudioUnitScope_Global,
|
||||
0,
|
||||
&unitBlockSize,
|
||||
sizeof(UInt32));
|
||||
if (auResult != 0)
|
||||
printf("Unable to set MaximumFramesPerSlice, rendering may fail...\n");
|
||||
}
|
||||
|
||||
auResult = AudioUnitInitialize(trackUnit);
|
||||
if (auResult != 0) {
|
||||
printf("Couldn't initialize audio unit\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
auResult = AudioUnitReset(trackUnit, kAudioUnitScope_Global, 0);
|
||||
if (auResult != 0) {
|
||||
printf("Reset failed.\n");
|
||||
AudioUnitUninitialize(trackUnit);
|
||||
return false;
|
||||
}
|
||||
|
||||
callbackStruct.inputProc = SimpleAudioRenderCallback;
|
||||
callbackStruct.inputProcRefCon = this;
|
||||
auResult = AudioUnitSetProperty(trackUnit,
|
||||
kAudioUnitProperty_SetRenderCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&callbackStruct,
|
||||
sizeof(AURenderCallbackStruct));
|
||||
if (auResult != 0) {
|
||||
printf("Setting input render callback failed.\n");
|
||||
AudioUnitUninitialize(trackUnit);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&timeStamp, 0, sizeof(AudioTimeStamp));
|
||||
timeStamp.mSampleTime = 0; // This is a double-precision number that should
|
||||
// accumulate the number of frames processed so far
|
||||
timeStamp.mFlags = kAudioTimeStampSampleTimeValid;
|
||||
|
||||
waveTrackBlockSize = left->GetMaxBlockSize() * 2;
|
||||
|
||||
leftBuffer = NULL;
|
||||
rightBuffer = NULL;
|
||||
mLeftBufferForCallback = NULL;
|
||||
mRightBufferForCallback = NULL;
|
||||
|
||||
if (left) {
|
||||
leftBuffer = new float[waveTrackBlockSize];
|
||||
}
|
||||
|
||||
if (right) {
|
||||
rightBuffer = new float[waveTrackBlockSize];
|
||||
}
|
||||
|
||||
bufferList = (AudioBufferList *)malloc(sizeof(UInt32) +
|
||||
numChannels * sizeof(AudioBuffer));
|
||||
bufferList->mNumberBuffers = numChannels;
|
||||
|
||||
sampleCount originalLen = len;
|
||||
sampleCount ls = lstart;
|
||||
sampleCount rs = rstart;
|
||||
while (len) {
|
||||
int block = waveTrackBlockSize;
|
||||
if (block > len) {
|
||||
block = len;
|
||||
}
|
||||
|
||||
if (left) {
|
||||
left->Get((samplePtr)leftBuffer, floatSample, ls, block);
|
||||
}
|
||||
|
||||
if (right) {
|
||||
right->Get((samplePtr)rightBuffer, floatSample, rs, block);
|
||||
}
|
||||
|
||||
success = DoRender(trackUnit, numChannels, leftBuffer, rightBuffer,
|
||||
block, unitBlockSize, &timeStamp, bufferList);
|
||||
if (!success) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (left) {
|
||||
left->Set((samplePtr)leftBuffer, floatSample, ls, block);
|
||||
}
|
||||
|
||||
if (right) {
|
||||
right->Set((samplePtr)rightBuffer, floatSample, rs, block);
|
||||
}
|
||||
|
||||
len -= block;
|
||||
ls += block;
|
||||
rs += block;
|
||||
|
||||
if (left && right) {
|
||||
if (TrackGroupProgress(count, (ls-lstart)/(double)originalLen)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (TrackProgress(count, (ls-lstart)/(double)originalLen)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bufferList) {
|
||||
free(bufferList);
|
||||
}
|
||||
|
||||
if (leftBuffer) {
|
||||
delete[] leftBuffer;
|
||||
}
|
||||
|
||||
if (rightBuffer) {
|
||||
delete[] rightBuffer;
|
||||
}
|
||||
|
||||
AudioUnitUninitialize(trackUnit);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool AudioUnitEffect::DoRender(AudioUnit unit,
|
||||
int numChannels,
|
||||
float *leftBuffer,
|
||||
float *rightBuffer,
|
||||
int len,
|
||||
int unitBlockSize,
|
||||
AudioTimeStamp *timeStamp,
|
||||
AudioBufferList *bufferList)
|
||||
{
|
||||
AudioUnitRenderActionFlags flags;
|
||||
ComponentResult auResult;
|
||||
int block;
|
||||
|
||||
for (int i = 0; i < len; i += block) {
|
||||
block = unitBlockSize;
|
||||
if (i + block > len) {
|
||||
block = len - i;
|
||||
}
|
||||
|
||||
for (int j = 0; j<numChannels; j++) {
|
||||
bufferList->mBuffers[j].mNumberChannels = 1;
|
||||
bufferList->mBuffers[j].mData = NULL;
|
||||
bufferList->mBuffers[j].mDataByteSize = sizeof(float) * block;
|
||||
}
|
||||
|
||||
if (leftBuffer) {
|
||||
mLeftBufferForCallback = &leftBuffer[i];
|
||||
bufferList->mBuffers[0].mData = mLeftBufferForCallback;
|
||||
}
|
||||
|
||||
if (rightBuffer) {
|
||||
mRightBufferForCallback = &rightBuffer[i];
|
||||
bufferList->mBuffers[1].mData = mRightBufferForCallback;
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
|
||||
auResult = AudioUnitRender(unit, &flags, timeStamp,
|
||||
0, block, bufferList);
|
||||
if (auResult != 0) {
|
||||
printf("Render failed: %d %4.4s\n", (int)auResult, (char *)&auResult);
|
||||
return false;
|
||||
}
|
||||
|
||||
timeStamp->mSampleTime += block;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
OSStatus AudioUnitEffect::SimpleAudioRenderCallback
|
||||
(void *inRefCon,
|
||||
AudioUnitRenderActionFlags *inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumFrames,
|
||||
AudioBufferList *ioData)
|
||||
{
|
||||
AudioUnitEffect *This = (AudioUnitEffect *)inRefCon;
|
||||
|
||||
if (This->mLeftBufferForCallback) {
|
||||
ioData->mBuffers[0].mData = This->mLeftBufferForCallback;
|
||||
}
|
||||
|
||||
if (This->mRightBufferForCallback) {
|
||||
ioData->mBuffers[1].mData = This->mRightBufferForCallback;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Component AudioUnitEffect::GetCarbonViewComponent(OSType subtype)
|
||||
{
|
||||
ComponentDescription desc;
|
||||
Component component;
|
||||
|
||||
desc.componentType = kAudioUnitCarbonViewComponentType; // 'auvw'
|
||||
desc.componentSubType = subtype;
|
||||
desc.componentManufacturer = 0;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
|
||||
// First see if we can find a carbon view designed specifically for this
|
||||
// plug-in:
|
||||
|
||||
component = FindNextComponent(NULL, &desc);
|
||||
if (component)
|
||||
return component;
|
||||
|
||||
// If not, grab the generic carbon view, which will create a GUI for
|
||||
// any Audio Unit.
|
||||
|
||||
desc.componentSubType = kAUCarbonViewSubType_Generic;
|
||||
component = FindNextComponent(NULL, &desc);
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
//
|
||||
// AudioUnitGUIControl methods
|
||||
//
|
||||
|
||||
BEGIN_EVENT_TABLE(AudioUnitGUIControl, wxControl)
|
||||
EVT_MOUSE_EVENTS(AudioUnitGUIControl::OnMouse)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
AudioUnitGUIControl::~AudioUnitGUIControl()
|
||||
{
|
||||
// Don't want to dispose of it...
|
||||
m_peer = NULL;
|
||||
}
|
||||
|
||||
bool AudioUnitGUIControl::Create(wxWindow *parent, wxWindowID id,
|
||||
wxPoint pos, wxSize size,
|
||||
ControlRef controlRef)
|
||||
{
|
||||
m_macIsUserPane = FALSE ;
|
||||
|
||||
if ( !wxControl::Create(parent, id, pos, size,
|
||||
0, wxDefaultValidator,
|
||||
wxString(wxT("AudioUnitControl"))) )
|
||||
return false;
|
||||
|
||||
m_peer = new wxMacControl(this, controlRef);
|
||||
|
||||
Rect outBounds;
|
||||
GetControlBounds(controlRef, &outBounds);
|
||||
|
||||
pos.x = outBounds.left;
|
||||
pos.y = outBounds.top;
|
||||
size.x = outBounds.right - outBounds.left;
|
||||
size.y = outBounds.bottom - outBounds.top;
|
||||
|
||||
MacPostControlCreate(pos, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
short AudioUnitGUIControl::GetModifiers(wxMouseEvent &event)
|
||||
{
|
||||
short modifiers = 0;
|
||||
|
||||
if ( !event.m_leftDown && !event.m_rightDown )
|
||||
modifiers |= btnState ;
|
||||
|
||||
if ( event.m_shiftDown )
|
||||
modifiers |= shiftKey ;
|
||||
|
||||
if ( event.m_controlDown )
|
||||
modifiers |= controlKey ;
|
||||
|
||||
if ( event.m_altDown )
|
||||
modifiers |= optionKey ;
|
||||
|
||||
if ( event.m_metaDown )
|
||||
modifiers |= cmdKey ;
|
||||
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
void AudioUnitGUIControl::OnMouse(wxMouseEvent &event)
|
||||
{
|
||||
int x = event.m_x ;
|
||||
int y = event.m_y ;
|
||||
|
||||
MacClientToRootWindow( &x , &y ) ;
|
||||
|
||||
Point localwhere ;
|
||||
ControlHandle control;
|
||||
|
||||
localwhere.h = x ;
|
||||
localwhere.v = y ;
|
||||
|
||||
short modifiers = GetModifiers(event);
|
||||
|
||||
if (event.GetEventType() == wxEVT_LEFT_DOWN ||
|
||||
event.GetEventType() == wxEVT_LEFT_DCLICK ) {
|
||||
#if ((wxMAJOR_VERSION == 2) && (wxMINOR_VERSION <= 4))
|
||||
WindowRef rootWindow = (WindowRef)GetParent()->MacGetRootWindow();
|
||||
#else
|
||||
WindowRef rootWindow = (WindowRef)GetParent()->MacGetTopLevelWindowRef();
|
||||
#endif
|
||||
|
||||
ControlPartCode code;
|
||||
|
||||
code = FindControl(localwhere,
|
||||
rootWindow,
|
||||
&control);
|
||||
|
||||
if (code) {
|
||||
Rect outBounds;
|
||||
GetControlBounds((ControlRef)control, &outBounds);
|
||||
|
||||
code = ::HandleControlClick(control,
|
||||
localwhere, modifiers,
|
||||
(ControlActionUPP)-1) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// AudioUnitDialog methods
|
||||
//
|
||||
|
||||
// Event handler to capture the window close event
|
||||
static const EventTypeSpec eventList[] =
|
||||
{
|
||||
{kEventClassWindow, kEventWindowClose},
|
||||
};
|
||||
|
||||
static pascal OSStatus EventHandler(EventHandlerCallRef handler, EventRef event, void *data)
|
||||
{
|
||||
OSStatus result = eventNotHandledErr;
|
||||
|
||||
AudioUnitDialog *dlg = (AudioUnitDialog *)data;
|
||||
|
||||
if (GetEventClass(event) == kEventClassWindow && GetEventKind(event) == kEventWindowClose) {
|
||||
dlg->RemoveHandler();
|
||||
dlg->Close();
|
||||
result = noErr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void EventListener(void *inUserData, AudioUnitCarbonView inView,
|
||||
const AudioUnitParameter *inParameter,
|
||||
AudioUnitCarbonViewEventID inEvent,
|
||||
const void *inEventParam)
|
||||
{
|
||||
// We're not actually using this yet...
|
||||
}
|
||||
|
||||
enum {
|
||||
PreviewID = 1
|
||||
};
|
||||
|
||||
BEGIN_EVENT_TABLE(AudioUnitDialog, wxDialog)
|
||||
EVT_BUTTON(wxID_OK, AudioUnitDialog::OnOK)
|
||||
EVT_BUTTON(wxID_CANCEL, AudioUnitDialog::OnCancel)
|
||||
EVT_BUTTON(PreviewID, AudioUnitDialog::OnPreview)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
AudioUnitDialog::AudioUnitDialog(wxWindow *parent, wxWindowID id,
|
||||
wxString title,
|
||||
AudioUnit unit,
|
||||
AudioUnitCarbonView carbonView,
|
||||
Effect *effect):
|
||||
mUnit(unit),
|
||||
mEffect(effect),
|
||||
mHandlerUPP(NULL),
|
||||
mHandlerRef(NULL)
|
||||
{
|
||||
long style = wxDEFAULT_DIALOG_STYLE;
|
||||
|
||||
#if ((wxMAJOR_VERSION == 2) && (wxMINOR_VERSION <= 4))
|
||||
|
||||
wxDialog::Create(parent, id, title,
|
||||
wxDefaultPosition, wxSize(500, 400),
|
||||
style, title);
|
||||
|
||||
#else
|
||||
|
||||
// wxMac 2.5 version, all of this is just to attempt to turn off
|
||||
// compositing...
|
||||
|
||||
// From wxDialog::Create
|
||||
SetExtraStyle(GetExtraStyle() | wxTOPLEVEL_EX_DIALOG);
|
||||
style |= wxTAB_TRAVERSAL;
|
||||
|
||||
// From wxTopLevelWindow::Create
|
||||
wxTopLevelWindow::Init();
|
||||
m_windowStyle = style;
|
||||
|
||||
// We added this line because many plug-ins are not happy with
|
||||
// compositing...Requires a patch to wx such that the line
|
||||
// "attr |= kWindowCompositingAttribute" only happens
|
||||
// if m_macUsesCompositing is true...
|
||||
//
|
||||
// LL: Unfortunately, wxWidgets 2.7+ doesn't have a direct
|
||||
// way to disable compositing, so bypass it until a way
|
||||
// is found.
|
||||
#if !wxCHECK_VERSION(2, 7, 0)
|
||||
m_macUsesCompositing = false;
|
||||
#endif
|
||||
|
||||
// Rest of wxTopLevelWindow::Create
|
||||
SetName(title);
|
||||
m_windowId = id == -1 ? NewControlId() : id;
|
||||
MacCreateRealWindow(title, wxDefaultPosition, wxSize(500, 400),
|
||||
MacRemoveBordersFromStyle(style) , title) ;
|
||||
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
|
||||
wxTopLevelWindows.Append(this);
|
||||
if ( parent )
|
||||
parent->AddChild(this);
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// On to our own code
|
||||
//
|
||||
|
||||
WindowRef windowRef = (WindowRef)MacGetWindowRef();
|
||||
ComponentResult auResult;
|
||||
ControlRef rootControl = NULL;
|
||||
GetRootControl(windowRef, &rootControl);
|
||||
|
||||
int width = 500;
|
||||
int height = 400;
|
||||
Float32Point location = {0, 0};
|
||||
Float32Point size = {width, height};
|
||||
ControlRef audioUnitControl = NULL;
|
||||
|
||||
auResult = AudioUnitCarbonViewCreate(carbonView,
|
||||
unit,
|
||||
windowRef,
|
||||
rootControl,
|
||||
&location,
|
||||
&size,
|
||||
&audioUnitControl);
|
||||
|
||||
AudioUnitCarbonViewSetEventListener(carbonView, EventListener, this);
|
||||
|
||||
mMainSizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
if (auResult == 0) {
|
||||
mGUIControl = new AudioUnitGUIControl(this, -1,
|
||||
wxPoint(0, 0),
|
||||
wxSize(width, height),
|
||||
audioUnitControl);
|
||||
|
||||
// Eventually, to handle resizing controls, call:
|
||||
// AudioUnitCarbonViewSetEventListener with the event:
|
||||
// kEventControlBoundsChanged
|
||||
|
||||
mMainSizer->Add(mGUIControl, 1, wxEXPAND);
|
||||
|
||||
mGUIControl->SetFocus();
|
||||
}
|
||||
else
|
||||
mGUIControl = NULL;
|
||||
|
||||
wxBoxSizer *hSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
wxButton *preview = new wxButton(this, PreviewID, _("Pre&view"));
|
||||
hSizer->Add(preview, 0, wxALL, 10);
|
||||
|
||||
hSizer->Add(10, 10);
|
||||
|
||||
wxButton *ok = new wxButton(this, wxID_OK, _("OK"));
|
||||
ok->SetDefault();
|
||||
ok->SetFocus();
|
||||
hSizer->Add(ok, 0, wxALL, 10);
|
||||
|
||||
wxButton *cancel = new wxButton(this, wxID_CANCEL, _("&Cancel"));
|
||||
hSizer->Add(cancel, 0, wxALL, 10);
|
||||
|
||||
mMainSizer->Add(hSizer, 0, wxALIGN_CENTER);
|
||||
|
||||
this->SetAutoLayout(true);
|
||||
this->SetSizer(mMainSizer);
|
||||
mMainSizer->Fit(this);
|
||||
mMainSizer->SetSizeHints(this);
|
||||
|
||||
// Some VST effects do not work unless the default handler is removed since
|
||||
// it captures many of the events that the plugins need. But, it must be
|
||||
// done last since proper window sizing will not occur otherwise.
|
||||
::RemoveEventHandler((EventHandlerRef)MacGetEventHandler());
|
||||
|
||||
// Install a bare minimum handler so we can capture the window close event. If
|
||||
// it's not captured, we will crash at Audacity termination since the window
|
||||
// is still on the wxWidgets toplevel window lists, but it's already gone.
|
||||
mHandlerUPP = NewEventHandlerUPP(EventHandler);
|
||||
InstallWindowEventHandler(windowRef,
|
||||
mHandlerUPP,
|
||||
GetEventTypeCount(eventList),
|
||||
eventList,
|
||||
this,
|
||||
&mHandlerRef);
|
||||
|
||||
}
|
||||
|
||||
AudioUnitDialog::~AudioUnitDialog()
|
||||
{
|
||||
RemoveHandler();
|
||||
}
|
||||
|
||||
void AudioUnitDialog::RemoveHandler()
|
||||
{
|
||||
if (mHandlerRef) {
|
||||
::RemoveEventHandler(mHandlerRef);
|
||||
mHandlerRef = NULL;
|
||||
MacInstallTopLevelWindowEventHandler();
|
||||
}
|
||||
|
||||
if (mHandlerUPP) {
|
||||
DisposeEventHandlerUPP(mHandlerUPP);
|
||||
mHandlerUPP = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioUnitDialog::OnOK(wxCommandEvent &event)
|
||||
{
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
void AudioUnitDialog::OnCancel(wxCommandEvent &event)
|
||||
{
|
||||
EndModal(wxID_CANCEL);
|
||||
}
|
||||
|
||||
void AudioUnitDialog::OnPreview(wxCommandEvent &event)
|
||||
{
|
||||
mEffect->Preview();
|
||||
}
|
||||
|
||||
// Indentation settings for Vim and Emacs and unique identifier for Arch, a
|
||||
// version control system. Please do not modify past this point.
|
||||
//
|
||||
// Local Variables:
|
||||
// c-basic-offset: 3
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
//
|
||||
// vim: et sts=3 sw=3
|
||||
// arch-tag: 21aef079-ec47-4ff9-a359-7d159e2ba0e6
|
||||
91
src/effects/audiounits/AudioUnitEffect.h
Normal file
91
src/effects/audiounits/AudioUnitEffect.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
AudioUnitEffect.h
|
||||
|
||||
Dominic Mazzoni
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include <wx/dialog.h>
|
||||
|
||||
#include "../Effect.h"
|
||||
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <AudioUnit/AUNTComponent.h>
|
||||
#include <AudioUnit/AudioUnitProperties.h>
|
||||
#include <AudioUnit/AudioUnitCarbonView.h>
|
||||
|
||||
class AudioUnitEffect:public Effect {
|
||||
|
||||
public:
|
||||
|
||||
AudioUnitEffect(wxString name, Component component);
|
||||
virtual ~AudioUnitEffect();
|
||||
|
||||
virtual wxString GetEffectName();
|
||||
|
||||
virtual std::set<wxString> GetEffectCategories();
|
||||
|
||||
virtual wxString GetEffectIdentifier();
|
||||
|
||||
virtual wxString GetEffectAction();
|
||||
|
||||
virtual bool Init();
|
||||
|
||||
virtual bool PromptUser();
|
||||
|
||||
virtual bool Process();
|
||||
|
||||
virtual void End();
|
||||
|
||||
private:
|
||||
bool SetRateAndChannels(AudioUnit unit,
|
||||
int numChannels, Float64 sampleRate);
|
||||
|
||||
bool ProcessStereo(int count, WaveTrack * left, WaveTrack *right,
|
||||
sampleCount lstart, sampleCount rstart,
|
||||
sampleCount len);
|
||||
|
||||
bool DoRender(AudioUnit unit, int numChannels,
|
||||
float *leftBuffer, float *rightBuffer,
|
||||
int len, int unitBlockSize,
|
||||
AudioTimeStamp *timeStamp,
|
||||
AudioBufferList *bufferList);
|
||||
|
||||
bool CopyParameters(AudioUnit srcUnit, AudioUnit dstUnit);
|
||||
|
||||
static OSStatus
|
||||
SimpleAudioRenderCallback(void *inRefCon,
|
||||
AudioUnitRenderActionFlags *inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumFrames,
|
||||
AudioBufferList *ioData);
|
||||
|
||||
Component GetCarbonViewComponent(OSType subtype);
|
||||
|
||||
wxString mName;
|
||||
Component mComponent;
|
||||
AudioUnit mUnit;
|
||||
bool mSupportsMono;
|
||||
bool mSupportsStereo;
|
||||
float *mLeftBufferForCallback;
|
||||
float *mRightBufferForCallback;
|
||||
};
|
||||
|
||||
|
||||
// Indentation settings for Vim and Emacs and unique identifier for Arch, a
|
||||
// version control system. Please do not modify past this point.
|
||||
//
|
||||
// Local Variables:
|
||||
// c-basic-offset: 3
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
//
|
||||
// vim: et sts=3 sw=3
|
||||
// arch-tag:
|
||||
|
||||
56
src/effects/audiounits/LoadAudioUnits.cpp
Normal file
56
src/effects/audiounits/LoadAudioUnits.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
LoadAudioUnits.cpp
|
||||
|
||||
Dominic Mazzoni
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/wx.h>
|
||||
|
||||
#include "../EffectManager.h"
|
||||
#include "AudioUnitEffect.h"
|
||||
|
||||
void LoadAudioUnits()
|
||||
{
|
||||
ComponentDescription desc;
|
||||
Component component;
|
||||
|
||||
desc.componentType = kAudioUnitType_Effect; //'aufx'
|
||||
desc.componentSubType = 0;
|
||||
desc.componentManufacturer = 0;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
|
||||
component = FindNextComponent(NULL, &desc);
|
||||
while (component != NULL) {
|
||||
ComponentDescription found;
|
||||
Handle nameHandle = NewHandle(0);
|
||||
GetComponentInfo(component, &found, nameHandle, 0, 0);
|
||||
HLock(nameHandle);
|
||||
int len = ((const char *)(*nameHandle))[0];
|
||||
wxString name(((const char *)(*nameHandle)+1), wxConvISO8859_1, len);
|
||||
HUnlock(nameHandle);
|
||||
DisposeHandle(nameHandle);
|
||||
|
||||
EffectManager::Get().RegisterEffect(new AudioUnitEffect(name, component));
|
||||
|
||||
component = FindNextComponent (component, &desc);
|
||||
}
|
||||
}
|
||||
|
||||
// Indentation settings for Vim and Emacs and unique identifier for Arch, a
|
||||
// version control system. Please do not modify past this point.
|
||||
//
|
||||
// Local Variables:
|
||||
// c-basic-offset: 3
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
//
|
||||
// vim: et sts=3 sw=3
|
||||
// arch-tag:
|
||||
|
||||
|
||||
23
src/effects/audiounits/LoadAudioUnits.h
Normal file
23
src/effects/audiounits/LoadAudioUnits.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
LoadAudioUnits.h
|
||||
|
||||
Dominic Mazzoni
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
void LoadAudioUnits();
|
||||
|
||||
// Indentation settings for Vim and Emacs and unique identifier for Arch, a
|
||||
// version control system. Please do not modify past this point.
|
||||
//
|
||||
// Local Variables:
|
||||
// c-basic-offset: 3
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
//
|
||||
// vim: et sts=3 sw=3
|
||||
// arch-tag:
|
||||
|
||||
Reference in New Issue
Block a user