mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-06 07:09:39 +02:00
AudioUnits rework...
They now work on Yosemite. AudioUnits with a custom Cocoa UI now display graphically instead of reverting to the generic view The Cocoa version of the generic view is now used when needed...instead of the Carbon version. The order of UI preference is Cocoa, Carbon, Generic, unless force to Generic view user setting. They now support realtime preview. They also support dialog resizing as I found many that scaled nicely (mostly Apple's). Uses the new Effect format so now supports user and factory presets. NOTE: Be VERY critical when testing this as I've never written Objective-C or Cocoa code before!
This commit is contained in:
parent
b16db7ca2b
commit
540f5c78c9
@ -324,7 +324,6 @@
|
||||
1790B12C09883BFD008A330A /* Dither.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790AFF909883BFD008A330A /* Dither.cpp */; };
|
||||
1790B12E09883BFD008A330A /* Amplify.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790AFFE09883BFD008A330A /* Amplify.cpp */; };
|
||||
1790B12F09883BFD008A330A /* AudioUnitEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B00109883BFD008A330A /* AudioUnitEffect.cpp */; };
|
||||
1790B13009883BFD008A330A /* LoadAudioUnits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B00409883BFD008A330A /* LoadAudioUnits.cpp */; };
|
||||
1790B13409883BFD008A330A /* ChangePitch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B00C09883BFD008A330A /* ChangePitch.cpp */; };
|
||||
1790B13509883BFD008A330A /* ChangeSpeed.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B00E09883BFD008A330A /* ChangeSpeed.cpp */; };
|
||||
1790B13609883BFD008A330A /* ChangeTempo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B01009883BFD008A330A /* ChangeTempo.cpp */; };
|
||||
@ -484,6 +483,7 @@
|
||||
28105DAC0AD09FC500BB4269 /* px_mixer.h in Headers */ = {isa = PBXBuildFile; fileRef = 28105DA20AD09FC500BB4269 /* px_mixer.h */; };
|
||||
2810644B1818EEB5004F678B /* cpu_detect_x86.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2810644A1818EEB5004F678B /* cpu_detect_x86.cpp */; };
|
||||
2810644D1818EED3004F678B /* cpu_detect.h in Headers */ = {isa = PBXBuildFile; fileRef = 2810644C1818EED3004F678B /* cpu_detect.h */; };
|
||||
2812E9D91A1F773A001C24D3 /* AudioUnitCocoaHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2812E9D81A1F773A001C24D3 /* AudioUnitCocoaHelper.m */; };
|
||||
2816372E0BAE3B6C0079C746 /* LinkingHtmlWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2816372C0BAE3B6C0079C746 /* LinkingHtmlWindow.cpp */; };
|
||||
282D474C0B9E8D900034BC49 /* Snap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 282D474A0B9E8D900034BC49 /* Snap.cpp */; };
|
||||
283135EC0DFB9D110076D551 /* ImportFFmpeg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 283135EA0DFB9D110076D551 /* ImportFFmpeg.cpp */; };
|
||||
@ -1312,7 +1312,6 @@
|
||||
ED663B9A16543647007F53A5 /* Dither.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790AFF909883BFD008A330A /* Dither.cpp */; };
|
||||
ED663B9B16543647007F53A5 /* Amplify.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790AFFE09883BFD008A330A /* Amplify.cpp */; };
|
||||
ED663B9C16543647007F53A5 /* AudioUnitEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B00109883BFD008A330A /* AudioUnitEffect.cpp */; };
|
||||
ED663B9D16543647007F53A5 /* LoadAudioUnits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B00409883BFD008A330A /* LoadAudioUnits.cpp */; };
|
||||
ED663BA016543647007F53A5 /* ChangePitch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B00C09883BFD008A330A /* ChangePitch.cpp */; };
|
||||
ED663BA116543647007F53A5 /* ChangeSpeed.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B00E09883BFD008A330A /* ChangeSpeed.cpp */; };
|
||||
ED663BA216543647007F53A5 /* ChangeTempo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B01009883BFD008A330A /* ChangeTempo.cpp */; };
|
||||
@ -1637,7 +1636,6 @@
|
||||
ED85B47316A47353006DA21D /* Dither.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790AFF909883BFD008A330A /* Dither.cpp */; };
|
||||
ED85B47416A47353006DA21D /* Amplify.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790AFFE09883BFD008A330A /* Amplify.cpp */; };
|
||||
ED85B47516A47353006DA21D /* AudioUnitEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B00109883BFD008A330A /* AudioUnitEffect.cpp */; };
|
||||
ED85B47616A47353006DA21D /* LoadAudioUnits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B00409883BFD008A330A /* LoadAudioUnits.cpp */; };
|
||||
ED85B47816A47353006DA21D /* ChangePitch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B00C09883BFD008A330A /* ChangePitch.cpp */; };
|
||||
ED85B47916A47353006DA21D /* ChangeSpeed.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B00E09883BFD008A330A /* ChangeSpeed.cpp */; };
|
||||
ED85B47A16A47353006DA21D /* ChangeTempo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1790B01009883BFD008A330A /* ChangeTempo.cpp */; };
|
||||
@ -2846,8 +2844,6 @@
|
||||
1790AFFF09883BFD008A330A /* Amplify.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = Amplify.h; sourceTree = "<group>"; tabWidth = 3; };
|
||||
1790B00109883BFD008A330A /* AudioUnitEffect.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = AudioUnitEffect.cpp; sourceTree = "<group>"; tabWidth = 3; };
|
||||
1790B00209883BFD008A330A /* AudioUnitEffect.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = AudioUnitEffect.h; sourceTree = "<group>"; tabWidth = 3; };
|
||||
1790B00409883BFD008A330A /* LoadAudioUnits.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = LoadAudioUnits.cpp; sourceTree = "<group>"; tabWidth = 3; };
|
||||
1790B00509883BFD008A330A /* LoadAudioUnits.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = LoadAudioUnits.h; sourceTree = "<group>"; tabWidth = 3; };
|
||||
1790B00C09883BFD008A330A /* ChangePitch.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = ChangePitch.cpp; sourceTree = "<group>"; tabWidth = 3; };
|
||||
1790B00D09883BFD008A330A /* ChangePitch.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = ChangePitch.h; sourceTree = "<group>"; tabWidth = 3; };
|
||||
1790B00E09883BFD008A330A /* ChangeSpeed.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = ChangeSpeed.cpp; sourceTree = "<group>"; tabWidth = 3; };
|
||||
@ -3177,6 +3173,8 @@
|
||||
2812A5B90DF63FF000576305 /* Debug_Static.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug_Static.xcconfig; sourceTree = "<group>"; };
|
||||
2812A5BB0DF63FFD00576305 /* Release_Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Release_Shared.xcconfig; sourceTree = "<group>"; };
|
||||
2812A5BD0DF6400E00576305 /* Release_Static.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Release_Static.xcconfig; sourceTree = "<group>"; };
|
||||
2812E9D71A1F773A001C24D3 /* AudioUnitCocoaHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioUnitCocoaHelper.h; sourceTree = "<group>"; };
|
||||
2812E9D81A1F773A001C24D3 /* AudioUnitCocoaHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioUnitCocoaHelper.m; sourceTree = "<group>"; };
|
||||
2813897919E6163C004111ED /* SelectedRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectedRegion.h; sourceTree = "<group>"; };
|
||||
2816372C0BAE3B6C0079C746 /* LinkingHtmlWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = LinkingHtmlWindow.cpp; sourceTree = "<group>"; tabWidth = 3; };
|
||||
2816372D0BAE3B6C0079C746 /* LinkingHtmlWindow.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = LinkingHtmlWindow.h; sourceTree = "<group>"; tabWidth = 3; };
|
||||
@ -5276,10 +5274,10 @@
|
||||
1790B00009883BFD008A330A /* audiounits */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2812E9D71A1F773A001C24D3 /* AudioUnitCocoaHelper.h */,
|
||||
2812E9D81A1F773A001C24D3 /* AudioUnitCocoaHelper.m */,
|
||||
1790B00109883BFD008A330A /* AudioUnitEffect.cpp */,
|
||||
1790B00209883BFD008A330A /* AudioUnitEffect.h */,
|
||||
1790B00409883BFD008A330A /* LoadAudioUnits.cpp */,
|
||||
1790B00509883BFD008A330A /* LoadAudioUnits.h */,
|
||||
);
|
||||
path = audiounits;
|
||||
sourceTree = "<group>";
|
||||
@ -8860,7 +8858,6 @@
|
||||
1790B12C09883BFD008A330A /* Dither.cpp in Sources */,
|
||||
1790B12E09883BFD008A330A /* Amplify.cpp in Sources */,
|
||||
1790B12F09883BFD008A330A /* AudioUnitEffect.cpp in Sources */,
|
||||
1790B13009883BFD008A330A /* LoadAudioUnits.cpp in Sources */,
|
||||
1790B13409883BFD008A330A /* ChangePitch.cpp in Sources */,
|
||||
1790B13509883BFD008A330A /* ChangeSpeed.cpp in Sources */,
|
||||
1790B13609883BFD008A330A /* ChangeTempo.cpp in Sources */,
|
||||
@ -9159,6 +9156,7 @@
|
||||
28001B3E1A0F0E5D007DD161 /* NumericTextCtrl.cpp in Sources */,
|
||||
28001B4B1A0F0EB6007DD161 /* SpectralSelectionBar.cpp in Sources */,
|
||||
28BB98051A15BE6800D1CC80 /* NoiseReduction.cpp in Sources */,
|
||||
2812E9D91A1F773A001C24D3 /* AudioUnitCocoaHelper.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -9373,7 +9371,6 @@
|
||||
ED663B9A16543647007F53A5 /* Dither.cpp in Sources */,
|
||||
ED663B9B16543647007F53A5 /* Amplify.cpp in Sources */,
|
||||
ED663B9C16543647007F53A5 /* AudioUnitEffect.cpp in Sources */,
|
||||
ED663B9D16543647007F53A5 /* LoadAudioUnits.cpp in Sources */,
|
||||
ED663BA016543647007F53A5 /* ChangePitch.cpp in Sources */,
|
||||
ED663BA116543647007F53A5 /* ChangeSpeed.cpp in Sources */,
|
||||
ED663BA216543647007F53A5 /* ChangeTempo.cpp in Sources */,
|
||||
@ -9681,7 +9678,6 @@
|
||||
ED85B47316A47353006DA21D /* Dither.cpp in Sources */,
|
||||
ED85B47416A47353006DA21D /* Amplify.cpp in Sources */,
|
||||
ED85B47516A47353006DA21D /* AudioUnitEffect.cpp in Sources */,
|
||||
ED85B47616A47353006DA21D /* LoadAudioUnits.cpp in Sources */,
|
||||
ED85B47816A47353006DA21D /* ChangePitch.cpp in Sources */,
|
||||
ED85B47916A47353006DA21D /* ChangeSpeed.cpp in Sources */,
|
||||
ED85B47A16A47353006DA21D /* ChangeTempo.cpp in Sources */,
|
||||
@ -10474,6 +10470,8 @@
|
||||
"-framework",
|
||||
CoreAudio,
|
||||
"-framework",
|
||||
CoreAudioKit,
|
||||
"-framework",
|
||||
CoreMIDI,
|
||||
"-framework",
|
||||
AudioUnit,
|
||||
@ -10825,6 +10823,8 @@
|
||||
"-framework",
|
||||
CoreAudio,
|
||||
"-framework",
|
||||
CoreAudioKit,
|
||||
"-framework",
|
||||
CoreMIDI,
|
||||
"-framework",
|
||||
AudioUnit,
|
||||
@ -11142,6 +11142,8 @@
|
||||
"-framework",
|
||||
CoreAudio,
|
||||
"-framework",
|
||||
CoreAudioKit,
|
||||
"-framework",
|
||||
CoreMIDI,
|
||||
"-framework",
|
||||
AudioUnit,
|
||||
@ -11650,6 +11652,8 @@
|
||||
"-framework",
|
||||
CoreAudio,
|
||||
"-framework",
|
||||
CoreAudioKit,
|
||||
"-framework",
|
||||
CoreMIDI,
|
||||
"-framework",
|
||||
AudioUnit,
|
||||
|
@ -1869,6 +1869,10 @@ const PluginDescriptor *PluginManager::GetFirstPluginForEffectType(EffectType ty
|
||||
{
|
||||
PluginDescriptor & plug = mPluginsIter->second;
|
||||
bool familyEnabled;
|
||||
if (type == PluginTypeEffect)
|
||||
{
|
||||
gPrefs->Read(plug.GetEffectFamily() + wxT("/Enable"), &familyEnabled, true);
|
||||
}
|
||||
gPrefs->Read(plug.GetEffectFamily() + wxT("/Enable"), &familyEnabled, true);
|
||||
if (plug.IsEnabled() && plug.GetEffectType() == type && familyEnabled)
|
||||
{
|
||||
|
@ -1669,7 +1669,24 @@ sampleCount Effect::RealtimeProcess(int group,
|
||||
}
|
||||
|
||||
// Finally call the plugin to process the block
|
||||
len = mClient->RealtimeProcess(mCurrentGroup++, clientIn, clientOut, numSamples);
|
||||
len = 0;
|
||||
sampleCount maxBlock = mClient->GetBlockSize(numSamples);
|
||||
for (sampleCount block = 0; block < numSamples; block += maxBlock)
|
||||
{
|
||||
sampleCount cnt = (block + maxBlock > numSamples ? numSamples - block : maxBlock);
|
||||
len += mClient->RealtimeProcess(mCurrentGroup, clientIn, clientOut, cnt);
|
||||
|
||||
for (int i = 0 ; i < mNumAudioIn; i++)
|
||||
{
|
||||
clientIn[i] += cnt;
|
||||
}
|
||||
|
||||
for (int i = 0 ; i < mNumAudioOut; i++)
|
||||
{
|
||||
clientOut[i] += cnt;
|
||||
}
|
||||
}
|
||||
mCurrentGroup++;
|
||||
}
|
||||
|
||||
return len;
|
||||
@ -1993,7 +2010,8 @@ END_EVENT_TABLE()
|
||||
EffectUIHost::EffectUIHost(wxWindow *parent,
|
||||
EffectHostInterface *host,
|
||||
EffectUIClientInterface *client)
|
||||
: wxDialog(parent, wxID_ANY, host->GetName())
|
||||
: wxDialog(parent, wxID_ANY, host->GetName(),
|
||||
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
|
||||
{
|
||||
SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
|
||||
|
||||
@ -2019,6 +2037,7 @@ EffectUIHost::~EffectUIHost()
|
||||
bool EffectUIHost::Initialize()
|
||||
{
|
||||
wxBoxSizer *vs = new wxBoxSizer(wxVERTICAL);
|
||||
wxBoxSizer *hs = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
EffectPanel *w = new EffectPanel(this);
|
||||
|
||||
@ -2030,7 +2049,8 @@ bool EffectUIHost::Initialize()
|
||||
|
||||
wxSizer *s = CreateStdButtonSizer(this, eSettingsButton | eOkButton | eCancelButton);
|
||||
|
||||
vs->Add(w, 1, wxEXPAND);
|
||||
hs->Add(w, 1, wxEXPAND);
|
||||
vs->Add(hs, 1, wxEXPAND);
|
||||
vs->Add(s, 0, wxEXPAND | wxALIGN_CENTER_VERTICAL);
|
||||
SetSizer(vs);
|
||||
|
||||
@ -2048,7 +2068,7 @@ bool EffectUIHost::Initialize()
|
||||
#else
|
||||
(w->GetChildren().GetCount() > 1 ? w : FindWindowById(wxID_OK))->SetFocus();
|
||||
#endif
|
||||
|
||||
|
||||
LoadUserPresets();
|
||||
|
||||
mClient->LoadUserPreset(mHost->GetCurrentSettingsGroup());
|
||||
|
@ -57,15 +57,6 @@
|
||||
#include "ChangeTempo.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_AUDIO_UNITS
|
||||
#include "audiounits/LoadAudioUnits.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_VAMP
|
||||
#include "vamp/LoadVamp.h"
|
||||
#endif
|
||||
|
||||
|
||||
void LoadEffects()
|
||||
{
|
||||
|
||||
@ -270,12 +261,6 @@ void LoadEffects()
|
||||
|
||||
// Analyze menu
|
||||
em.RegisterEffect(new EffectFindClipping());
|
||||
|
||||
#ifdef USE_AUDIO_UNITS
|
||||
if (gPrefs->Read(wxT("/AudioUnits/Enable"), true)) {
|
||||
LoadAudioUnits();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UnloadEffects()
|
||||
|
@ -554,7 +554,7 @@ bool VSTEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxStrin
|
||||
bool VSTEffectsModule::IsPluginValid(const PluginID & ID,
|
||||
const wxString & path)
|
||||
{
|
||||
return wxFileName::FileExists(path);
|
||||
return wxFileName::FileExists(path) || wxFileName::DirExists(path);
|
||||
}
|
||||
|
||||
IdentInterface *VSTEffectsModule::CreateInstance(const PluginID & WXUNUSED(ID),
|
||||
|
28
src/effects/audiounits/AudioUnitCocoaHelper.h
Normal file
28
src/effects/audiounits/AudioUnitCocoaHelper.h
Normal file
@ -0,0 +1,28 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
AudioUnitCocoaHelper.h
|
||||
|
||||
Leland Lucius
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef AUDACITY_AUDIOUNIT_COCOA_HELPER_H
|
||||
#define AUDACITY_AUDIOUNIT_COCOA_HELPER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <AudioUnit/AudioUnitCarbonView.h>
|
||||
|
||||
HIViewRef createGeneric(AudioUnit unit);
|
||||
HIViewRef createCocoa(AudioUnit unit);
|
||||
HIViewRef createCarbon(AudioUnit unit, WindowRef window, AudioUnitCarbonView *carbonView);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
301
src/effects/audiounits/AudioUnitCocoaHelper.m
Normal file
301
src/effects/audiounits/AudioUnitCocoaHelper.m
Normal file
@ -0,0 +1,301 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
AudioUnitCocoaHelper.m
|
||||
|
||||
Leland Lucius
|
||||
|
||||
*******************************************************************//**
|
||||
|
||||
\class AUScrollView
|
||||
\brief An NSScrollView subclass that hosts AUs
|
||||
|
||||
NOTE: I do NOT to Objective-C(++), so if you see ANYTHING wrong do
|
||||
not hesitate to let me know. -Leland
|
||||
|
||||
*//*******************************************************************/
|
||||
|
||||
#import <Carbon/Carbon.h>
|
||||
#import <AudioUnit/AudioUnit.h>
|
||||
#import <AudioUnit/AUCocoaUIView.h>
|
||||
#import <CoreAudioKit/CoreAudioKit.h>
|
||||
#import <AppKit/NSScrollView.h>
|
||||
|
||||
#import "AudioUnitCocoaHelper.h"
|
||||
|
||||
@interface AUScrollView: NSScrollView
|
||||
{
|
||||
NSView *auView;
|
||||
HIViewRef hiViewRef;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(NSRect)frameRect;
|
||||
|
||||
/* Might be useful for improved resizing
|
||||
- (void)auResized:(NSNotification *)notification;
|
||||
- (void)myResized:(NSNotification *)notification;
|
||||
*/
|
||||
|
||||
@end
|
||||
|
||||
@implementation AUScrollView
|
||||
|
||||
- (id)initWithFrame:(NSRect)frameRect
|
||||
{
|
||||
self = [super initWithFrame:frameRect];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)reflectScrolledClipView:(NSClipView *)aClipView
|
||||
{
|
||||
[super reflectScrolledClipView:aClipView];
|
||||
|
||||
// Force a full refresh as some effects seem to need it
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (BOOL)autoresizesSubviews
|
||||
{
|
||||
// Let NSView automatically resize our children
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
/* Might be useful for improved resizing. I'd worked up this
|
||||
really elaborate resizing stuff that "almost" worked. Rather
|
||||
than spend even more time, I decided to get rid of it all and
|
||||
let resizing happen as it will. This code should be short
|
||||
lived anyway as it will probably not be needed once we convert
|
||||
to wxWidgets 3+.
|
||||
|
||||
-(void) setViews:(NSView *)aView hiViewRef:(HIViewRef)hView
|
||||
{
|
||||
auView = aView;
|
||||
hiViewRef = hView;
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(myResized:) name:NSViewFrameDidChangeNotification object:self];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(auResized:) name:NSViewFrameDidChangeNotification object:auView];
|
||||
|
||||
}
|
||||
|
||||
- (void)myResized:(NSNotification *)notification
|
||||
{
|
||||
}
|
||||
|
||||
- (void)auResized:(NSNotification *)notification
|
||||
{
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Create a Cocoa based generic AU view wrapped in a Carbon view
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
HIViewRef createGeneric(AudioUnit unit)
|
||||
{
|
||||
HIViewRef hiView = NULL;
|
||||
OSStatus result;
|
||||
|
||||
// Create a generic AU view
|
||||
NSView *auView = [[AUGenericView alloc] initWithAudioUnit: unit];
|
||||
if (auView != nil)
|
||||
{
|
||||
// Allow expert parameters to be used
|
||||
[(AUGenericView *) auView setShowsExpertParameters:YES];
|
||||
|
||||
// Get the AU view's frame for later
|
||||
NSRect viewFrame = [auView frame];
|
||||
|
||||
// Create the view that will host the AU view
|
||||
AUScrollView *scrollView =
|
||||
[[[AUScrollView alloc] initWithFrame:viewFrame] autorelease];
|
||||
|
||||
// Not sure if this is necessary, but crashes seemed to occur
|
||||
// without it.
|
||||
[scrollView retain];
|
||||
|
||||
// Set the scroller options
|
||||
[scrollView setDrawsBackground:YES];
|
||||
[scrollView setAutohidesScrollers:YES];
|
||||
[scrollView setHasHorizontalScroller:YES];
|
||||
[scrollView setHasVerticalScroller:YES];
|
||||
[scrollView setBorderType:NSNoBorder];
|
||||
[scrollView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
|
||||
|
||||
// Let the scrollview know about the AU view
|
||||
//
|
||||
// Should the AU view be released after this???
|
||||
[scrollView setDocumentView:auView];
|
||||
// [auView release];
|
||||
|
||||
// Carbonize it
|
||||
result = HICocoaViewCreate(scrollView, 0, &hiView);
|
||||
if (result == noErr)
|
||||
{
|
||||
// Resize the HIView to match the AU view
|
||||
SizeControl(hiView, viewFrame.size.width, viewFrame.size.height);
|
||||
}
|
||||
}
|
||||
|
||||
return hiView;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Create a Cocoa based custom AU view wrapped in a Carbon view
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
HIViewRef createCocoa(AudioUnit unit)
|
||||
{
|
||||
HIViewRef hiView = NULL;
|
||||
OSStatus result;
|
||||
|
||||
AudioUnitCocoaViewInfo cocoaViewInfo;
|
||||
UInt32 dataSize = sizeof(AudioUnitCocoaViewInfo);
|
||||
|
||||
// Get info about first Cocoa view
|
||||
result = AudioUnitGetProperty(unit,
|
||||
kAudioUnitProperty_CocoaUI,
|
||||
kAudioUnitScope_Global,
|
||||
0,
|
||||
&cocoaViewInfo,
|
||||
&dataSize);
|
||||
if (result != noErr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Looks like the AU has a Cocoa UI, so load the factory class
|
||||
NSURL *bundleLoc = (NSURL *) cocoaViewInfo.mCocoaAUViewBundleLocation;
|
||||
NSString *className = (NSString *) cocoaViewInfo.mCocoaAUViewClass[0];
|
||||
if (!bundleLoc || !className)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Load the bundle
|
||||
NSBundle *bundle = [NSBundle bundleWithPath: [bundleLoc path]];
|
||||
if (bundle != nil)
|
||||
{
|
||||
// Load the class from the bundle
|
||||
Class factoryClass = [bundle classNamed: className];
|
||||
if (factoryClass != nil)
|
||||
{
|
||||
// Create an instance of the class
|
||||
id factoryInst = [[[factoryClass alloc] init] autorelease];
|
||||
if (factoryInst != nil)
|
||||
{
|
||||
// Suggest a resonable size
|
||||
NSSize size = {800, 600};
|
||||
|
||||
// Create the view
|
||||
NSView *auView = [factoryInst uiViewForAudioUnit: unit withSize: size];
|
||||
if (auView != nil)
|
||||
{
|
||||
// Get the AU views frame for later
|
||||
NSRect viewFrame = [auView frame];
|
||||
|
||||
// Create the view that will host the AU view
|
||||
AUScrollView *scrollView =
|
||||
[[[AUScrollView alloc] initWithFrame:viewFrame] autorelease];
|
||||
|
||||
// Not sure if this is necessary, but crashes seemed to occur
|
||||
// without it.
|
||||
[scrollView retain];
|
||||
|
||||
// Set the scroller options
|
||||
[scrollView setDrawsBackground:YES];
|
||||
[scrollView setAutohidesScrollers:YES];
|
||||
[scrollView setHasHorizontalScroller:YES];
|
||||
[scrollView setHasVerticalScroller:YES];
|
||||
[scrollView setBorderType:NSNoBorder];
|
||||
|
||||
// Let the scrollview know about the AU view
|
||||
//
|
||||
// Should the AU view be released after this???
|
||||
[scrollView setDocumentView:auView];
|
||||
|
||||
// Carbonize it
|
||||
result = HICocoaViewCreate(scrollView, 0, &hiView);
|
||||
if (result == noErr)
|
||||
{
|
||||
// Resize the HIView to match the AU view
|
||||
SizeControl(hiView, viewFrame.size.width, viewFrame.size.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Release the bundle???
|
||||
// [bundle release];
|
||||
}
|
||||
|
||||
// Release the bundle path
|
||||
[bundleLoc release];
|
||||
|
||||
return hiView;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Create a Carbon based AU view
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
HIViewRef createCarbon(AudioUnit unit, WindowRef window, AudioUnitCarbonView *carbonView)
|
||||
{
|
||||
HIViewRef hiView = NULL;
|
||||
OSStatus result;
|
||||
|
||||
// Retrieve the view component description
|
||||
ComponentDescription compDesc;
|
||||
UInt32 dataSize = sizeof(compDesc);
|
||||
result = AudioUnitGetProperty(unit,
|
||||
kAudioUnitProperty_GetUIComponentList,
|
||||
kAudioUnitScope_Global,
|
||||
0,
|
||||
&compDesc,
|
||||
&dataSize);
|
||||
if (result != noErr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Try to open it
|
||||
Component comp = FindNextComponent(NULL, &compDesc);
|
||||
result = OpenAComponent(comp, carbonView);
|
||||
if (result != noErr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the root control
|
||||
ControlRef root = HIViewGetRoot(window);
|
||||
GetRootControl(window, &root);
|
||||
|
||||
// Find the content view within our window
|
||||
HIViewRef content;
|
||||
result = HIViewFindByID(root, kHIViewWindowContentID, &content);
|
||||
if (result != noErr)
|
||||
{
|
||||
CloseComponent(*carbonView);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Suggest a reasonable size
|
||||
Float32Point loc = {0.0, 0.0};
|
||||
Float32Point size = {800.0, 600.0};
|
||||
|
||||
// And create it
|
||||
result = AudioUnitCarbonViewCreate(*carbonView,
|
||||
unit,
|
||||
window,
|
||||
root,
|
||||
&loc,
|
||||
&size,
|
||||
&hiView);
|
||||
|
||||
return hiView;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@
|
||||
AudioUnitEffect.h
|
||||
|
||||
Dominic Mazzoni
|
||||
Leland Lucius
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
@ -18,61 +19,255 @@
|
||||
#include <AudioUnit/AUNTComponent.h>
|
||||
#include <AudioUnit/AudioUnitProperties.h>
|
||||
#include <AudioUnit/AudioUnitCarbonView.h>
|
||||
#include <AudioToolbox/AudioUnitUtilities.h>
|
||||
|
||||
class AudioUnitEffect:public Effect {
|
||||
#include "audacity/EffectInterface.h"
|
||||
#include "audacity/ModuleInterface.h"
|
||||
#include "audacity/PluginInterface.h"
|
||||
|
||||
public:
|
||||
#define AUDIOUNITEFFECTS_VERSION wxT("1.0.0.0");
|
||||
#define AUDIOUNITEFFECTS_FAMILY L"AudioUnit"
|
||||
|
||||
AudioUnitEffect(wxString name, Component component);
|
||||
class AudioUnitEffect;
|
||||
|
||||
WX_DEFINE_ARRAY_PTR(AudioUnitEffect *, AudioUnitEffectArray);
|
||||
|
||||
class AudioUnitEffectEventHelper;
|
||||
|
||||
class AudioUnitEffect : public EffectClientInterface,
|
||||
public EffectUIClientInterface
|
||||
{
|
||||
public:
|
||||
AudioUnitEffect(const wxString & path,
|
||||
const wxString & name,
|
||||
Component component,
|
||||
AudioUnitEffect *master = NULL);
|
||||
virtual ~AudioUnitEffect();
|
||||
|
||||
virtual wxString GetEffectName();
|
||||
// IdentInterface implementation
|
||||
|
||||
virtual std::set<wxString> GetEffectCategories();
|
||||
virtual PluginID GetID();
|
||||
virtual wxString GetPath();
|
||||
virtual wxString GetName();
|
||||
virtual wxString GetVendor();
|
||||
virtual wxString GetVersion();
|
||||
virtual wxString GetDescription();
|
||||
|
||||
virtual wxString GetEffectIdentifier();
|
||||
// EffectIdentInterface implementation
|
||||
|
||||
virtual wxString GetEffectAction();
|
||||
virtual EffectType GetType();
|
||||
virtual wxString GetFamily();
|
||||
virtual bool IsInteractive();
|
||||
virtual bool IsDefault();
|
||||
virtual bool IsLegacy();
|
||||
virtual bool SupportsRealtime();
|
||||
virtual bool SupportsAutomation();
|
||||
|
||||
virtual bool Init();
|
||||
// EffectClientInterface implementation
|
||||
|
||||
virtual bool PromptUser();
|
||||
virtual bool SetHost(EffectHostInterface *host);
|
||||
|
||||
virtual bool Process();
|
||||
virtual int GetAudioInCount();
|
||||
virtual int GetAudioOutCount();
|
||||
|
||||
virtual void End();
|
||||
virtual int GetMidiInCount();
|
||||
virtual int GetMidiOutCount();
|
||||
|
||||
private:
|
||||
bool SetRateAndChannels(AudioUnit unit,
|
||||
int numChannels, Float64 sampleRate);
|
||||
virtual void SetSampleRate(sampleCount rate);
|
||||
virtual sampleCount GetBlockSize(sampleCount maxBlockSize);
|
||||
|
||||
bool ProcessStereo(int count, WaveTrack * left, WaveTrack *right,
|
||||
sampleCount lstart, sampleCount rstart,
|
||||
sampleCount len);
|
||||
virtual sampleCount GetLatency();
|
||||
virtual sampleCount GetTailSize();
|
||||
|
||||
bool DoRender(AudioUnit unit, int numChannels,
|
||||
float *leftBuffer, float *rightBuffer,
|
||||
int len, int unitBlockSize,
|
||||
AudioTimeStamp *timeStamp,
|
||||
AudioBufferList *bufferList);
|
||||
virtual bool IsReady();
|
||||
virtual bool ProcessInitialize();
|
||||
virtual bool ProcessFinalize();
|
||||
virtual sampleCount ProcessBlock(float **inbuf, float **outbuf, sampleCount size);
|
||||
|
||||
virtual bool RealtimeInitialize();
|
||||
virtual bool RealtimeAddProcessor(int numChannels, float sampleRate);
|
||||
virtual bool RealtimeFinalize();
|
||||
virtual bool RealtimeSuspend();
|
||||
virtual bool RealtimeResume();
|
||||
virtual sampleCount RealtimeProcess(int group,
|
||||
float **inbuf,
|
||||
float **outbuf,
|
||||
sampleCount numSamples);
|
||||
|
||||
virtual bool ShowInterface(wxWindow *parent, bool forceModal = false);
|
||||
|
||||
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
|
||||
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
|
||||
|
||||
// EffectUIClientInterface implementation
|
||||
|
||||
virtual void SetUIHost(EffectUIHostInterface *host);
|
||||
virtual bool PopulateUI(wxWindow *parent);
|
||||
virtual bool ValidateUI();
|
||||
virtual bool HideUI();
|
||||
virtual bool CloseUI();
|
||||
|
||||
virtual void LoadUserPreset(const wxString & name);
|
||||
virtual void SaveUserPreset(const wxString & name);
|
||||
|
||||
virtual void LoadFactoryPreset(int id);
|
||||
virtual void LoadFactoryDefaults();
|
||||
|
||||
virtual wxArrayString GetFactoryPresets();
|
||||
|
||||
virtual void ExportPresets();
|
||||
virtual void ImportPresets();
|
||||
virtual void ShowOptions();
|
||||
|
||||
// AudioUnitEffect implementation
|
||||
|
||||
private:
|
||||
bool SetRateAndChannels();
|
||||
|
||||
bool CopyParameters(AudioUnit srcUnit, AudioUnit dstUnit);
|
||||
|
||||
static OSStatus
|
||||
SimpleAudioRenderCallback(void *inRefCon,
|
||||
AudioUnitRenderActionFlags *inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumFrames,
|
||||
AudioBufferList *ioData);
|
||||
// Realtime
|
||||
int GetChannelCount();
|
||||
void SetChannelCount(int numChannels);
|
||||
|
||||
static OSStatus RenderCallback(void *inRefCon,
|
||||
AudioUnitRenderActionFlags *inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumFrames,
|
||||
AudioBufferList *ioData);
|
||||
OSStatus Render(AudioUnitRenderActionFlags *inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumFrames,
|
||||
AudioBufferList *ioData);
|
||||
|
||||
Component GetCarbonViewComponent(OSType subtype);
|
||||
static void EventListenerCallback(void *inCallbackRefCon,
|
||||
void *inObject,
|
||||
const AudioUnitEvent *inEvent,
|
||||
UInt64 inEventHostTime,
|
||||
AudioUnitParameterValue inParameterValue);
|
||||
void EventListener(const AudioUnitEvent *inEvent,
|
||||
AudioUnitParameterValue inParameterValue);
|
||||
|
||||
static pascal OSStatus WindowEventHandlerCallback(EventHandlerCallRef handler,
|
||||
EventRef event,
|
||||
void *data);
|
||||
OSStatus WindowEventHandler(EventRef event);
|
||||
|
||||
static pascal OSStatus ControlEventHandlerCallback(EventHandlerCallRef handler,
|
||||
EventRef event,
|
||||
void *data);
|
||||
OSStatus ControlEventHandler(EventRef event);
|
||||
|
||||
void GetChannelCounts();
|
||||
|
||||
void LoadParameters(const wxString & group);
|
||||
void SaveParameters(const wxString & group);
|
||||
|
||||
wxString mPath;
|
||||
wxString mName;
|
||||
wxString mVendor;
|
||||
Component mComponent;
|
||||
AudioUnit mUnit;
|
||||
bool mSupportsMono;
|
||||
bool mSupportsStereo;
|
||||
float *mLeftBufferForCallback;
|
||||
float *mRightBufferForCallback;
|
||||
|
||||
EffectHostInterface *mHost;
|
||||
int mAudioIns;
|
||||
int mAudioOuts;
|
||||
bool mInteractive;
|
||||
bool mLatencyDone;
|
||||
Float64 mLatency; // in seconds...multiply by samplerate
|
||||
Float64 mTailTime; // in seconds...multiply by samplerate
|
||||
UInt32 mBlockSize;
|
||||
double mSampleRate;
|
||||
|
||||
int mBufferSize;
|
||||
bool mUseBufferDelay;
|
||||
|
||||
AudioTimeStamp mTimeStamp;
|
||||
bool mReady;
|
||||
|
||||
AudioBufferList *mInputList;
|
||||
AudioBufferList *mOutputList;
|
||||
|
||||
EffectUIHostInterface *mUIHost;
|
||||
wxWindow *mParent;
|
||||
wxDialog *mDialog;
|
||||
wxSizerItem *mContainer;
|
||||
AudioUnitCarbonView mCarbonView;
|
||||
bool mUseGUI;
|
||||
HIViewRef mAUView;
|
||||
EventTargetRef mEventRef;
|
||||
bool mIsCocoa;
|
||||
bool mIsCarbon;
|
||||
bool mIsGeneric;
|
||||
|
||||
AudioUnitEffect *mMaster; // non-NULL if a slave
|
||||
AudioUnitEffectArray mSlaves;
|
||||
int mNumChannels;
|
||||
float **mMasterIn;
|
||||
int mMasterInLen;
|
||||
float **mMasterOut;
|
||||
int mMasterOutLen;
|
||||
|
||||
AUEventListenerRef mEventListenerRef;
|
||||
|
||||
EventHandlerRef mHandlerRef;
|
||||
EventHandlerUPP mHandlerUPP;
|
||||
EventHandlerRef mControlHandlerRef;
|
||||
EventHandlerUPP mControlHandlerUPP;
|
||||
|
||||
AudioUnitEffectEventHelper *mEventHelper;
|
||||
friend class AudioUnitEffectEventHelper;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// AudioUnitEffectsModule
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AudioUnitEffectsModule : public ModuleInterface
|
||||
{
|
||||
public:
|
||||
AudioUnitEffectsModule(ModuleManagerInterface *moduleManager, const wxString *path);
|
||||
virtual ~AudioUnitEffectsModule();
|
||||
|
||||
// IdentInterface implementatino
|
||||
|
||||
virtual wxString GetID();
|
||||
virtual wxString GetPath();
|
||||
virtual wxString GetName();
|
||||
virtual wxString GetVendor();
|
||||
virtual wxString GetVersion();
|
||||
virtual wxString GetDescription();
|
||||
|
||||
// ModuleInterface implementation
|
||||
|
||||
virtual bool Initialize();
|
||||
virtual void Terminate();
|
||||
|
||||
virtual bool AutoRegisterPlugins(PluginManagerInterface & pm);
|
||||
virtual wxArrayString FindPlugins(PluginManagerInterface & pm);
|
||||
virtual bool RegisterPlugin(PluginManagerInterface & pm, const wxString & path);
|
||||
|
||||
virtual bool IsPluginValid(const PluginID & ID, const wxString & path);
|
||||
|
||||
virtual IdentInterface *CreateInstance(const PluginID & ID, const wxString & path);
|
||||
virtual void DeleteInstance(IdentInterface *instance);
|
||||
|
||||
// AudioUnitEffectModule implementation
|
||||
|
||||
void LoadAudioUnitsOfType(OSType inAUType, wxArrayString & effects);
|
||||
Component FindAudioUnit(const wxString & path, wxString & name);
|
||||
|
||||
wxString FromOSType(OSType type);
|
||||
OSType ToOSType(const wxString & type);
|
||||
|
||||
private:
|
||||
ModuleManagerInterface *mModMan;
|
||||
wxString mPath;
|
||||
};
|
||||
|
||||
|
@ -1,49 +0,0 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
LoadAudioUnits.cpp
|
||||
|
||||
Dominic Mazzoni
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/wx.h>
|
||||
|
||||
#include "../EffectManager.h"
|
||||
#include "AudioUnitEffect.h"
|
||||
|
||||
void LoadAudioUnitsOfType(OSType inAUType)
|
||||
{
|
||||
ComponentDescription desc;
|
||||
Component component;
|
||||
|
||||
desc.componentType = inAUType;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadAudioUnits()
|
||||
{
|
||||
LoadAudioUnitsOfType(kAudioUnitType_Effect); //'aufx'
|
||||
LoadAudioUnitsOfType(kAudioUnitType_MusicEffect); //'aumf'
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
LoadAudioUnits.h
|
||||
|
||||
Dominic Mazzoni
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
void LoadAudioUnits();
|
@ -59,7 +59,7 @@ void EffectsPrefs::PopulateOrExchange(ShuttleGui & S)
|
||||
|
||||
#if USE_AUDIO_UNITS
|
||||
S.TieCheckBox(_("Audio Unit"),
|
||||
wxT("/AudioUnits/Enable"),
|
||||
wxT("/AudioUnit/Enable"),
|
||||
true);
|
||||
#endif
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user