Migrating the remaining effects

This brings the builtin, LV2, and VAMP effects inline with the
Audio Units, LADSPA, and VST effects.  All effects now share
a common UI.

This gives all effects (though not implemented for all):

User and factory preset capability
Preset import/export capability
Shared or private configuration options

Builtin effects can now be migrated to RTP, depending on algorithm.
LV2 effects now support graphical interfaces if the plugin supplies one.
Nyquist prompt enhanced to provide some features of the Nyquist Workbench.

It may not look like it, but this was a LOT of work, so trust me, there
WILL be problems and everything effect related should be suspect.  Keep
a sharp eye (or two) open.
This commit is contained in:
Leland Lucius 2015-04-16 22:53:42 -05:00
parent 40e6bcc56a
commit 8fbfa460c4
140 changed files with 17288 additions and 20367 deletions

View File

@ -1,165 +1,3 @@
/* XPM */
static const char * effect_disable_xpm[] = {
"16 16 51 1",
" c None",
". c #F3D3D3",
"+ c #E19393",
"@ c #D25C5C",
"# c #C73636",
"$ c #E7A8A8",
"% c #CD4B4B",
"& c #C32727",
"* c #C63333",
"= c #CF5353",
"- c #F0CACA",
"; c #EFC6C6",
"> c #DA7A7A",
", c #C83939",
"' c #DB7E7E",
") c #F5DBDB",
"! c #F2CFCF",
"~ c #CF5454",
"{ c #C42B2B",
"] c #C42A2A",
"^ c #F9EBEB",
"/ c #D56767",
"( c #C83A3A",
"_ c #CB4343",
": c #FCF6F6",
"< c #DF8D8D",
"[ c #C52E2E",
"} c #C52F2F",
"| c #E08F8F",
"1 c #FEFBFB",
"2 c #E8AEAE",
"3 c #D76E6E",
"4 c #F9E9E9",
"5 c #F1CBCB",
"6 c #CB4545",
"7 c #C32828",
"8 c #CE5050",
"9 c #F3D5D5",
"0 c #E19292",
"a c #F0C9C9",
"b c #C32929",
"c c #C93D3D",
"d c #ECBCBC",
"e c #FEFCFC",
"f c #CC4646",
"g c #C63232",
"h c #E49E9E",
"i c #FEFAFA",
"j c #FBEFEF",
"k c #D36161",
"l c #EDBFBF",
" .+@####@+. ",
" $%&&&&&&&&%$ ",
" $*&&&&&&&&&&*$ ",
".%&&&=+-;>,&&&%.",
"+&&&') !~{]&&&+",
"@&&=) ^/]&(_&&@",
"#&&+ :<[&}|<&&#",
"#&&- 12#&]34-&&#",
"#&&- 567789 -&&#",
"#&&0a=b&cde +&&#",
"@&&f6b&ghi )=&&@",
"+&&&77*<j )'&&&+",
".%&&&[kl-+=&&&%.",
" $*&&&&&&&&&&*$ ",
" $%&&&&&&&&%$ ",
" .+@####@+. "};
/* XPM */
static const char * effect_enable_xpm[] = {
"16 16 71 1",
" c None",
". c #C8E5C9",
"+ c #8FCA92",
"@ c #61B565",
"# c #41A646",
"$ c #E6F3E6",
"% c #90CB93",
"& c #3FA443",
"* c #35A03A",
"= c #7EC281",
"- c #36A03B",
"; c #39A23E",
"> c #37A13C",
", c #61B564",
"' c #96CD99",
") c #6BBA6F",
"! c #3CA341",
"~ c #3AA23F",
"{ c #6EBB72",
"] c #D3EAD5",
"^ c #FAFCFA",
"/ c #C4E3C5",
"( c #4EAC52",
"_ c #38A13D",
": c #3DA442",
"< c #67B76A",
"[ c #D5EBD5",
"} c #FDFEFD",
"| c #FAFDFB",
"1 c #ADD8AE",
"2 c #42A647",
"3 c #3EA442",
"4 c #70BC74",
"5 c #A3D4A6",
"6 c #84C486",
"7 c #49A94D",
"8 c #53AE56",
"9 c #C1E2C2",
"0 c #FAFDFA",
"a c #FBFDFB",
"b c #CAE6CC",
"c c #5BB260",
"d c #4DAB51",
"e c #BCE0BE",
"f c #F9FCFA",
"g c #EFF7EF",
"h c #B1DAB2",
"i c #A9D7AB",
"j c #F5FAF6",
"k c #FCFEFC",
"l c #D5EBD6",
"m c #63B566",
"n c #85C688",
"o c #E9F5EA",
"p c #FFFFFF",
"q c #F8FCF8",
"r c #F4FAF4",
"s c #FEFFFE",
"t c #E9F4E9",
"u c #7DC280",
"v c #8CC98F",
"w c #E8F4E9",
"x c #F6FBF6",
"y c #A1D3A3",
"z c #81C384",
"A c #D6ECD7",
"B c #E2F2E3",
"C c #A4D4A6",
"D c #4AAA4F",
"E c #54AE58",
"F c #5EB463",
" .+@##@+. ",
" $%&******&%$ ",
" $=**********=$ ",
" %********-;-*% ",
".&*******>,')!&.",
"+*******~{]^/(*+",
"@**_:_*><[}|12*@",
"#*34567890abc-*#",
"#*defghijklm-**#",
"@*&nopqrstu_***@",
"+**2vwssxy:****+",
".&**3zABCD****&.",
" %***!EF2*****% ",
" $=****-*****=$ ",
" $%&******&%$ ",
" .+@##@+. "};
/* XPM */
static const char * effect_menu_xpm[] = {
"16 16 2 1",
@ -523,153 +361,6 @@ static const char * effect_ffwd_xpm[] = {
" MN MN ",
" "};
/* XPM */
static const char * effect_disable_disabled_xpm[] = {
"16 16 46 1",
" c None",
". c #E3E3E3",
"+ c #BABABA",
"@ c #979797",
"# c #7E7E7E",
"$ c #C7C7C7",
"% c #8C8C8C",
"& c #757575",
"* c #7C7C7C",
"= c #919191",
"- c #DDDDDD",
"; c #DADADA",
"> c #AAAAAA",
", c #808080",
"' c #ACACAC",
") c #E8E8E8",
"! c #E0E0E0",
"~ c #777777",
"{ c #F2F2F2",
"] c #9E9E9E",
"^ c #818181",
"/ c #878787",
"( c #F9F9F9",
"_ c #B6B6B6",
": c #797979",
"< c #7A7A7A",
"[ c #B7B7B7",
"} c #FCFCFC",
"| c #CBCBCB",
"1 c #A2A2A2",
"2 c #F1F1F1",
"3 c #DEDEDE",
"4 c #888888",
"5 c #8F8F8F",
"6 c #E4E4E4",
"7 c #B9B9B9",
"8 c #DCDCDC",
"9 c #767676",
"0 c #838383",
"a c #D4D4D4",
"b c #FDFDFD",
"c c #898989",
"d c #C1C1C1",
"e c #F5F5F5",
"f c #9A9A9A",
"g c #D6D6D6",
" .+@####@+. ",
" $%&&&&&&&&%$ ",
" $*&&&&&&&&&&*$ ",
".%&&&=+-;>,&&&%.",
"+&&&') !=~~&&&+",
"@&&=) {]~&^/&&@",
"#&&+ (_:&<[_&&#",
"#&&- }|#&~12-&&#",
"#&&- 34&&56 -&&#",
"#&&78=9&0ab +&&#",
"@&&c49&*d} )=&&@",
"+&&&&&*_e )'&&&+",
".%&&&:fg-+=&&&%.",
" $*&&&&&&&&&&*$ ",
" $%&&&&&&&&%$ ",
" .+@####@+. "};
/* XPM */
static const char * effect_enable_disabled_xpm[] = {
"16 16 61 1",
" c None",
". c #D6D6D6",
"+ c #ACACAC",
"@ c #8B8B8B",
"# c #737373",
"$ c #ECECEC",
"% c #ADADAD",
"& c #717171",
"* c #6A6A6A",
"= c #A0A0A0",
"- c #6B6B6B",
"; c #6D6D6D",
"> c #6C6C6C",
", c #B1B1B1",
"' c #929292",
") c #6F6F6F",
"! c #6E6E6E",
"~ c #949494",
"{ c #DEDEDE",
"] c #FBFBFB",
"^ c #D3D3D3",
"/ c #7D7D7D",
"( c #707070",
"_ c #8F8F8F",
": c #E0E0E0",
"< c #FDFDFD",
"[ c #C2C2C2",
"} c #747474",
"| c #969696",
"1 c #BBBBBB",
"2 c #A4A4A4",
"3 c #797979",
"4 c #808080",
"5 c #D1D1D1",
"6 c #FCFCFC",
"7 c #D8D8D8",
"8 c #868686",
"9 c #7C7C7C",
"0 c #CECECE",
"a c #FAFAFA",
"b c #F3F3F3",
"c c #C5C5C5",
"d c #C0C0C0",
"e c #F7F7F7",
"f c #8C8C8C",
"g c #A5A5A5",
"h c #EFEFEF",
"i c #FFFFFF",
"j c #FEFEFE",
"k c #EEEEEE",
"l c #9F9F9F",
"m c #AAAAAA",
"n c #F8F8F8",
"o c #BABABA",
"p c #A2A2A2",
"q c #E1E1E1",
"r c #EAEAEA",
"s c #BCBCBC",
"t c #7A7A7A",
"u c #818181",
"v c #898989",
" .+@##@+. ",
" $%&******&%$ ",
" $=**********=$ ",
" %********-;-*% ",
".&*******>@,')&.",
"+*******!~{]^/*+",
"@**>(>*>_:<][}*@",
"#*&|12345]678-*#",
"#*90abcde<:f-**#",
"@*&ghiaejkl>***@",
"+**}mkjjno(****+",
".&**&pqrst****&.",
" %***)uv}*****% ",
" $=****-*****=$ ",
" $%&******&%$ ",
" .+@##@+. "};
/* XPM */
static const char * effect_play_disabled_xpm[] = {
"16 16 48 1",

View File

@ -48,13 +48,14 @@
class EffectAutomationParameters : public wxFileConfig
{
public:
EffectAutomationParameters()
EffectAutomationParameters(const wxString & parms = wxEmptyString)
: wxFileConfig(wxEmptyString,
wxEmptyString,
wxEmptyString,
wxEmptyString,
0)
{
SetParameters(parms);
}
virtual ~EffectAutomationParameters()
@ -81,19 +82,40 @@ public:
return wxFileConfig::DoWriteLong(NormalizeName(key), lValue);
}
bool ReadFloat(const wxString & key, float *pf) const
{
double d = *pf;
bool success = Read(key, &d);
if (success)
{
*pf = (float) d;
}
return success;
}
bool ReadFloat(const wxString & key, float *pf, float defVal) const
{
if (!ReadFloat(key, pf))
{
*pf = defVal;
}
return true;
}
bool WriteFloat(const wxString & key, float f)
{
return Write(key, f);
}
bool ReadEnum(const wxString & key, int *pi, const wxArrayString & choices) const
{
wxString s;
if (wxFileConfig::Read(key, &s))
if (!wxFileConfig::Read(key, &s))
{
int i = choices.Index(s);
if (i != wxNOT_FOUND)
{
*pi = i;
return true;
}
return false;
}
return false;
*pi = choices.Index(s);
return true;
}
bool ReadEnum(const wxString & key, int *pi, int defVal, const wxArrayString & choices) const
@ -105,6 +127,15 @@ public:
return true;
}
bool ReadEnum(const wxString & key, int *pi, const wxString & defVal, const wxArrayString & choices) const
{
if (!ReadEnum(key, pi, choices))
{
*pi = choices.Index(defVal);
}
return true;
}
bool WriteEnum(const wxString & key, int value, const wxArrayString & choices)
{
if (value < 0 || value >= (int) choices.GetCount())
@ -115,6 +146,54 @@ public:
return wxFileConfig::Write(key, choices[value]);
}
bool ReadAndVerify(const wxString & key, float *val, float defVal, float min, float max) const
{
ReadFloat(key, val, defVal);
return (*val >= min && *val <= max);
}
bool ReadAndVerify(const wxString & key, double *val, double defVal, double min, double max) const
{
Read(key, val, defVal);
return (*val >= min && *val <= max);
}
bool ReadAndVerify(const wxString & key, int *val, int defVal, int min, int max) const
{
Read(key, val, defVal);
return (*val >= min && *val <= max);
}
bool ReadAndVerify(const wxString & key, long *val, long defVal, long min, long max) const
{
Read(key, val, defVal);
return (*val >= min && *val <= max);
}
bool ReadAndVerify(const wxString & key, bool *val, bool defVal) const
{
Read(key, val, defVal);
return true;
}
bool ReadAndVerify(const wxString & key, wxString *val, const wxString & defVal) const
{
Read(key, val, defVal);
return true;
}
bool ReadAndVerify(const wxString & key, int *val, int defVal, const wxArrayString & choices) const
{
ReadEnum(key, val, defVal, choices);
return (*val != wxNOT_FOUND);
}
bool ReadAndVerify(const wxString & key, int *val, const wxString & defVal, const wxArrayString & choices) const
{
ReadEnum(key, val, defVal, choices);
return (*val != wxNOT_FOUND);
}
wxString NormalizeName(const wxString & name) const
{
wxString cleaned = name;
@ -145,7 +224,7 @@ public:
return false;
}
str += key + wxT("=\"") + val + wxT("\" ");
str += key + wxT("=\"") + Escape(val) + wxT("\" ");
res = wxFileConfig::GetNextEntry(key, ndx);
}
@ -167,7 +246,7 @@ public:
wxString key = parsed[i].BeforeFirst(wxT('=')).Trim(false).Trim(true);
wxString val = parsed[i].AfterFirst(wxT('=')).Trim(false).Trim(true);
if (!wxFileConfig::Write(key, val))
if (!wxFileConfig::Write(key, Unescape(val)))
{
return false;
}
@ -175,6 +254,22 @@ public:
return true;
}
wxString Escape(wxString val)
{
val.Replace(wxT("\\"), wxT("\\\\"), true);
val.Replace(wxT("\""), wxT("\\\""), true);
return val;
}
wxString Unescape(wxString val)
{
val.Replace(wxT("\\\""), wxT("\""), true);
val.Replace(wxT("\\\\"), wxT("\\"), true);
return val;
}
};
#endif

View File

@ -87,12 +87,12 @@ public:
class EffectUIHostInterface;
class EffectUIClientInterface;
class AUDACITY_DLL_API EffectHostInterface : public EffectIdentInterface,
public ConfigClientInterface
class AUDACITY_DLL_API EffectHostInterface : public ConfigClientInterface
{
public:
virtual ~EffectHostInterface() {};
virtual double GetDefaultDuration() = 0;
virtual double GetDuration() = 0;
virtual bool SetDuration(double seconds) = 0;
@ -108,7 +108,7 @@ public:
virtual wxString GetFactoryDefaultsGroup() = 0;
};
class EffectClientInterface : public EffectIdentInterface
class AUDACITY_DLL_API EffectClientInterface : public EffectIdentInterface
{
public:
virtual ~EffectClientInterface() {};
@ -122,15 +122,15 @@ public:
virtual int GetMidiOutCount() = 0;
virtual void SetSampleRate(sampleCount rate) = 0;
virtual sampleCount GetBlockSize(sampleCount maxBlockSize) = 0;
virtual sampleCount SetBlockSize(sampleCount maxBlockSize) = 0;
virtual sampleCount GetLatency() = 0;
virtual sampleCount GetTailSize() = 0;
virtual bool IsReady() = 0;
virtual bool ProcessInitialize() = 0;
virtual bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap = NULL) = 0;
virtual bool ProcessFinalize() = 0;
virtual sampleCount ProcessBlock(float **inbuf, float **outbuf, sampleCount size) = 0;
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen) = 0;
virtual bool RealtimeInitialize() = 0;
virtual bool RealtimeAddProcessor(int numChannels, float sampleRate) = 0;
@ -138,41 +138,41 @@ public:
virtual bool RealtimeSuspend() = 0;
virtual bool RealtimeResume() = 0;
virtual bool RealtimeProcessStart() = 0;
virtual sampleCount RealtimeProcess(int group, float **inbuf, float **outbuf, sampleCount numSamples) = 0;
virtual sampleCount RealtimeProcess(int group, float **inBuf, float **outBuf, sampleCount numSamples) = 0;
virtual bool RealtimeProcessEnd() = 0;
virtual bool ShowInterface(wxWindow *parent, bool forceModal = false) = 0;
virtual bool GetAutomationParameters(EffectAutomationParameters & parms) = 0;
virtual bool SetAutomationParameters(EffectAutomationParameters & parms) = 0;
virtual bool LoadUserPreset(const wxString & name) = 0;
virtual bool SaveUserPreset(const wxString & name) = 0;
virtual wxArrayString GetFactoryPresets() = 0;
virtual bool LoadFactoryPreset(int id) = 0;
virtual bool LoadFactoryDefaults() = 0;
};
class EffectUIHostInterface
class AUDACITY_DLL_API EffectUIHostInterface
{
public:
virtual ~EffectUIHostInterface() {};
};
class EffectUIClientInterface
class AUDACITY_DLL_API EffectUIClientInterface
{
public:
virtual ~EffectUIClientInterface() {};
virtual void SetUIHost(EffectUIHostInterface *host) = 0;
virtual bool PopulateUI(wxWindow *parent) = 0;
virtual void SetHostUI(EffectUIHostInterface *host) = 0;
virtual bool IsGraphicalUI() = 0;
virtual bool PopulateUI(wxWindow *parent) = 0;
virtual bool ValidateUI() = 0;
virtual bool HideUI() = 0;
virtual bool CloseUI() = 0;
virtual void LoadUserPreset(const wxString & name) = 0;
virtual void SaveUserPreset(const wxString & name) = 0;
virtual wxArrayString GetFactoryPresets() = 0;
virtual void LoadFactoryPreset(int id) = 0;
virtual void LoadFactoryDefaults() = 0;
virtual bool CanExport() = 0;
virtual bool CanExportPresets() = 0;
virtual void ExportPresets() = 0;
virtual void ImportPresets() = 0;
@ -180,7 +180,7 @@ public:
virtual void ShowOptions() = 0;
};
class EffectManagerInterface
class AUDACITY_DLL_API EffectManagerInterface
{
public:
virtual ~EffectManagerInterface() {};

View File

@ -56,9 +56,9 @@ class PluginManagerInterface
public:
virtual ~PluginManagerInterface() {};
virtual const PluginID & RegisterModulePlugin(ModuleInterface *module) = 0;
virtual const PluginID & RegisterEffectPlugin(ModuleInterface *provider, EffectIdentInterface *effect) = 0;
virtual const PluginID & RegisterImporterPlugin(ModuleInterface *provider, ImporterInterface *importer) = 0;
virtual const PluginID & RegisterPlugin(ModuleInterface *module) = 0;
virtual const PluginID & RegisterPlugin(ModuleInterface *provider, EffectIdentInterface *effect) = 0;
virtual const PluginID & RegisterPlugin(ModuleInterface *provider, ImporterInterface *importer) = 0;
virtual void FindFilesInPathList(const wxString & pattern,
const wxArrayString & pathList,

View File

@ -120,7 +120,7 @@ typedef enum
ChannelNameBottomFrontCenter,
ChannelNameBottomFrontLeft,
ChannelNameBottomFrontRight,
} ChannelName;
} ChannelName, *ChannelNames;
// LLL FIXME: Until a complete API is devised, we have to use
// AUDACITY_DLL_API when defining API classes. This

View File

@ -690,8 +690,8 @@ NyqBench::NyqBench(wxWindow * parent)
mOutput = NULL;
// No need to delete...EffectManager will do it
mEffect = new EffectNyquist(wxT("===nyquistworker==="));
EffectManager::Get().RegisterEffect(mEffect, HIDDEN_EFFECT);
mEffect = new NyquistEffect(wxT("===nyquistworker==="));
EffectManager::Get().RegisterEffect(mEffect);
mPath = gPrefs->Read(wxT("NyqBench/Path"), wxEmptyString);
mAutoLoad = (gPrefs->Read(wxT("NyqBench/AutoLoad"), 0L) != 0);
@ -1366,7 +1366,7 @@ void NyqBench::OnGo(wxCommandEvent & e)
UpdateWindowUI();
const PluginID & id = EffectManager::Get().GetEffectByIdentifier(mEffect->GetSymbol());
p->OnEffect(ALL_EFFECTS, id);
p->OnEffect(id);
mRunning = false;
UpdateWindowUI();

View File

@ -191,7 +191,7 @@ class NyqBench:public wxFrame
wxFindReplaceData mFindData;
NyqTextCtrl *mFindText;
EffectNyquist *mEffect;
NyquistEffect *mEffect;
wxFont mScriptFont;
wxFont mOutputFont;

View File

@ -273,8 +273,6 @@ src/effects/Echo.cpp
src/effects/Echo.h
src/effects/Effect.cpp
src/effects/Effect.h
src/effects/EffectCategory.cpp
src/effects/EffectCategory.h
src/effects/EffectManager.cpp
src/effects/EffectManager.h
src/effects/EffectRack.cpp
@ -352,13 +350,8 @@ src/effects/ladspa/LadspaEffect.h
src/effects/ladspa/ladspa.h
src/effects/lv2/LV2Effect.cpp
src/effects/lv2/LV2Effect.h
src/effects/lv2/LV2PortGroup.cpp
src/effects/lv2/LV2PortGroup.h
src/effects/lv2/LoadLV2.cpp
src/effects/lv2/LoadLV2.h
src/effects/lv2/lv2_event.h
src/effects/lv2/lv2_event_helpers.h
src/effects/lv2/lv2_uri_map.h
src/effects/nyquist/LoadNyquist.cpp
src/effects/nyquist/LoadNyquist.h
src/effects/nyquist/Nyquist.cpp

View File

@ -1182,7 +1182,6 @@
28ED7B7D1A1C77BF008A01D9 /* SpectralEditParametricEQ.ny in Resources */ = {isa = PBXBuildFile; fileRef = 28ED7B771A1C77BF008A01D9 /* SpectralEditParametricEQ.ny */; };
28ED7B7E1A1C77BF008A01D9 /* SpectralEditShelves.ny in Resources */ = {isa = PBXBuildFile; fileRef = 28ED7B781A1C77BF008A01D9 /* SpectralEditShelves.ny */; };
28ED7B7F1A1C77BF008A01D9 /* StudioFadeOut.ny in Resources */ = {isa = PBXBuildFile; fileRef = 28ED7B791A1C77BF008A01D9 /* StudioFadeOut.ny */; };
28EDC8DF0E5550750034BBE7 /* LV2PortGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 28EDC8DD0E5550750034BBE7 /* LV2PortGroup.cpp */; };
28F00A930A3E2FF100A3E5F5 /* FileNames.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 28F00A900A3E2FF100A3E5F5 /* FileNames.cpp */; };
28F1D81D0A2D0019005506A7 /* AttachableScrollBar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 28F1D8170A2D0018005506A7 /* AttachableScrollBar.cpp */; };
28F1D81E0A2D0019005506A7 /* ExpandingToolBar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 28F1D8190A2D0018005506A7 /* ExpandingToolBar.cpp */; };
@ -1258,7 +1257,6 @@
ED2707460EF9C550007D4FFD /* libsbsms.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ED2706F40EF9C3C6007D4FFD /* libsbsms.a */; };
ED2707500EF9C64F007D4FFD /* SBSMSEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED27074B0EF9C64F007D4FFD /* SBSMSEffect.cpp */; };
ED2707510EF9C64F007D4FFD /* TimeScale.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED27074D0EF9C64F007D4FFD /* TimeScale.cpp */; };
ED3D7FF00DF73889000F43E3 /* EffectCategory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED3D7FEC0DF73889000F43E3 /* EffectCategory.cpp */; };
ED3D7FF10DF73889000F43E3 /* EffectManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED3D7FEE0DF73889000F43E3 /* EffectManager.cpp */; };
ED64C823124567ED007CF2FC /* ScoreAlignDialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED64C821124567ED007CF2FC /* ScoreAlignDialog.cpp */; };
ED85B3DA16A46FC9006DA21D /* hr.po in Sources */ = {isa = PBXBuildFile; fileRef = ED85B3CF16A46DDA006DA21D /* hr.po */; };
@ -2931,11 +2929,6 @@
28ED7B771A1C77BF008A01D9 /* SpectralEditParametricEQ.ny */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = SpectralEditParametricEQ.ny; path = "../plug-ins/SpectralEditParametricEQ.ny"; sourceTree = SOURCE_ROOT; };
28ED7B781A1C77BF008A01D9 /* SpectralEditShelves.ny */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = SpectralEditShelves.ny; path = "../plug-ins/SpectralEditShelves.ny"; sourceTree = SOURCE_ROOT; };
28ED7B791A1C77BF008A01D9 /* StudioFadeOut.ny */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = StudioFadeOut.ny; path = "../plug-ins/StudioFadeOut.ny"; sourceTree = SOURCE_ROOT; };
28EDC8DA0E5550750034BBE7 /* lv2_event.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = lv2_event.h; path = lv2/lv2_event.h; sourceTree = "<group>"; tabWidth = 3; };
28EDC8DB0E5550750034BBE7 /* lv2_event_helpers.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = lv2_event_helpers.h; path = lv2/lv2_event_helpers.h; sourceTree = "<group>"; tabWidth = 3; };
28EDC8DC0E5550750034BBE7 /* lv2_uri_map.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = lv2_uri_map.h; path = lv2/lv2_uri_map.h; sourceTree = "<group>"; tabWidth = 3; };
28EDC8DD0E5550750034BBE7 /* LV2PortGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; name = LV2PortGroup.cpp; path = lv2/LV2PortGroup.cpp; sourceTree = "<group>"; tabWidth = 3; };
28EDC8DE0E5550750034BBE7 /* LV2PortGroup.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = LV2PortGroup.h; path = lv2/LV2PortGroup.h; sourceTree = "<group>"; tabWidth = 3; };
28F00A900A3E2FF100A3E5F5 /* FileNames.cpp */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = FileNames.cpp; sourceTree = "<group>"; tabWidth = 3; };
28F00A910A3E2FF100A3E5F5 /* FileNames.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = FileNames.h; sourceTree = "<group>"; tabWidth = 3; };
28F00A920A3E2FF100A3E5F5 /* ThemeAsCeeCode.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = ThemeAsCeeCode.h; sourceTree = "<group>"; tabWidth = 3; };
@ -3065,8 +3058,6 @@
ED27074C0EF9C64F007D4FFD /* SBSMSEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = SBSMSEffect.h; sourceTree = "<group>"; tabWidth = 3; };
ED27074D0EF9C64F007D4FFD /* TimeScale.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = TimeScale.cpp; sourceTree = "<group>"; tabWidth = 3; };
ED27074E0EF9C64F007D4FFD /* TimeScale.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = TimeScale.h; sourceTree = "<group>"; tabWidth = 3; };
ED3D7FEC0DF73889000F43E3 /* EffectCategory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = EffectCategory.cpp; sourceTree = "<group>"; tabWidth = 3; };
ED3D7FED0DF73889000F43E3 /* EffectCategory.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = EffectCategory.h; sourceTree = "<group>"; tabWidth = 3; };
ED3D7FEE0DF73889000F43E3 /* EffectManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = EffectManager.cpp; sourceTree = "<group>"; tabWidth = 3; };
ED3D7FEF0DF73889000F43E3 /* EffectManager.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = EffectManager.h; sourceTree = "<group>"; tabWidth = 3; };
ED64C821124567ED007CF2FC /* ScoreAlignDialog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = ScoreAlignDialog.cpp; sourceTree = "<group>"; tabWidth = 3; };
@ -4076,8 +4067,6 @@
1790B01809883BFD008A330A /* Echo.h */,
1790B01909883BFD008A330A /* Effect.cpp */,
1790B01A09883BFD008A330A /* Effect.h */,
ED3D7FEC0DF73889000F43E3 /* EffectCategory.cpp */,
ED3D7FED0DF73889000F43E3 /* EffectCategory.h */,
ED3D7FEE0DF73889000F43E3 /* EffectManager.cpp */,
ED3D7FEF0DF73889000F43E3 /* EffectManager.h */,
280A8B4819F440880091DE70 /* EffectRack.cpp */,
@ -5357,11 +5346,6 @@
28D587C80E264CF3009C7DEA /* LoadLV2.h */,
28D587C90E264CF4009C7DEA /* LV2Effect.cpp */,
28D587CA0E264CF4009C7DEA /* LV2Effect.h */,
28EDC8DD0E5550750034BBE7 /* LV2PortGroup.cpp */,
28EDC8DE0E5550750034BBE7 /* LV2PortGroup.h */,
28EDC8DA0E5550750034BBE7 /* lv2_event.h */,
28EDC8DB0E5550750034BBE7 /* lv2_event_helpers.h */,
28EDC8DC0E5550750034BBE7 /* lv2_uri_map.h */,
);
name = lv2;
sourceTree = "<group>";
@ -7512,7 +7496,6 @@
288052C20DEA73F500671EA4 /* NonGuiThread.cpp in Sources */,
28530C4C0DF2105200555C94 /* HtmlWindow.cpp in Sources */,
28530C4D0DF2105200555C94 /* ProgressDialog.cpp in Sources */,
ED3D7FF00DF73889000F43E3 /* EffectCategory.cpp in Sources */,
ED3D7FF10DF73889000F43E3 /* EffectManager.cpp in Sources */,
283135EC0DFB9D110076D551 /* ImportFFmpeg.cpp in Sources */,
283135FF0DFBA2E80076D551 /* FFmpeg.cpp in Sources */,
@ -7532,7 +7515,6 @@
186CCE720E51F48500659159 /* ODDecodeFlacTask.cpp in Sources */,
186CCE730E51F48500659159 /* ODDecodeTask.cpp in Sources */,
186CCEA40E523C8E00659159 /* Profiler.cpp in Sources */,
28EDC8DF0E5550750034BBE7 /* LV2PortGroup.cpp in Sources */,
18D8314E0ED0F56300FD870D /* Contrast.cpp in Sources */,
ED2707500EF9C64F007D4FFD /* SBSMSEffect.cpp in Sources */,
ED2707510EF9C64F007D4FFD /* TimeScale.cpp in Sources */,
@ -8163,7 +8145,7 @@
);
PRODUCT_NAME = Audacity;
SKIP_INSTALL = NO;
USER_HEADER_SEARCH_PATHS = "$(TOPLEVEL)/include $(TOPLEVEL)/mac $(TOPLEVEL)/src/** $(TOPLEVEL)/lib-src/FileDialog $(TOPLEVEL)/lib-src/libflac/include $(TOPLEVEL)/lib-src/libid3tag $(TOPLEVEL)/lib-src/lame $(TOPLEVEL)/lib-src/libmad $(TOPLEVEL)/lib-src/libogg/include $(TOPLEVEL)/lib-src/libnyquist/nyq $(TOPLEVEL)/lib-src/libresample/include $(TOPLEVEL)/lib-src/libsndfile/src $(TOPLEVEL)/lib-src/libsoxr/src $(TOPLEVEL)/lib-src/libvamp $(TOPLEVEL)/lib-src/libvorbis/include $(TOPLEVEL)/lib-src/portaudio-v19/include $(TOPLEVEL)/lib-src/portmixer/px_common $(TOPLEVEL)/lib-src/portsmf $(TOPLEVEL)/lib-src/soundtouch/include $(TOPLEVEL)/lib-src/lv2/include $(TOPLEVEL)/lib-src/twolame/libtwolame";
USER_HEADER_SEARCH_PATHS = "$(TOPLEVEL)/include $(TOPLEVEL)/mac $(TOPLEVEL)/src/** $(TOPLEVEL)/lib-src/FileDialog $(TOPLEVEL)/lib-src/libflac/include $(TOPLEVEL)/lib-src/libid3tag $(TOPLEVEL)/lib-src/lame $(TOPLEVEL)/lib-src/libmad $(TOPLEVEL)/lib-src/libogg/include $(TOPLEVEL)/lib-src/libnyquist/nyq $(TOPLEVEL)/lib-src/libsndfile/src $(TOPLEVEL)/lib-src/libsoxr/src $(TOPLEVEL)/lib-src/libvamp $(TOPLEVEL)/lib-src/libvorbis/include $(TOPLEVEL)/lib-src/portaudio-v19/include $(TOPLEVEL)/lib-src/portmixer/px_common $(TOPLEVEL)/lib-src/portsmf $(TOPLEVEL)/lib-src/soundtouch/include $(TOPLEVEL)/lib-src/lv2/include $(TOPLEVEL)/lib-src/twolame/libtwolame";
};
name = "Debug Static";
};
@ -8524,7 +8506,7 @@
);
PRODUCT_NAME = Audacity;
SKIP_INSTALL = NO;
USER_HEADER_SEARCH_PATHS = "$(TOPLEVEL)/include $(TOPLEVEL)/mac $(TOPLEVEL)/src/** $(TOPLEVEL)/lib-src/FileDialog $(TOPLEVEL)/lib-src/libflac/include $(TOPLEVEL)/lib-src/libid3tag $(TOPLEVEL)/lib-src/lame $(TOPLEVEL)/lib-src/libmad $(TOPLEVEL)/lib-src/libogg/include $(TOPLEVEL)/lib-src/libnyquist/nyq $(TOPLEVEL)/lib-src/libresample/include $(TOPLEVEL)/lib-src/libsndfile/src $(TOPLEVEL)/lib-src/libsoxr/src $(TOPLEVEL)/lib-src/libvamp $(TOPLEVEL)/lib-src/libvorbis/include $(TOPLEVEL)/lib-src/portaudio-v19/include $(TOPLEVEL)/lib-src/portmixer/px_common $(TOPLEVEL)/lib-src/portsmf $(TOPLEVEL)/lib-src/soundtouch/include $(TOPLEVEL)/lib-src/lv2/include $(TOPLEVEL)/lib-src/twolame/libtwolame";
USER_HEADER_SEARCH_PATHS = "$(TOPLEVEL)/include $(TOPLEVEL)/mac $(TOPLEVEL)/src/** $(TOPLEVEL)/lib-src/FileDialog $(TOPLEVEL)/lib-src/libflac/include $(TOPLEVEL)/lib-src/libid3tag $(TOPLEVEL)/lib-src/lame $(TOPLEVEL)/lib-src/libmad $(TOPLEVEL)/lib-src/libogg/include $(TOPLEVEL)/lib-src/libnyquist/nyq $(TOPLEVEL)/lib-src/libsndfile/src $(TOPLEVEL)/lib-src/libsoxr/src $(TOPLEVEL)/lib-src/libvamp $(TOPLEVEL)/lib-src/libvorbis/include $(TOPLEVEL)/lib-src/portaudio-v19/include $(TOPLEVEL)/lib-src/portmixer/px_common $(TOPLEVEL)/lib-src/portsmf $(TOPLEVEL)/lib-src/soundtouch/include $(TOPLEVEL)/lib-src/lv2/include $(TOPLEVEL)/lib-src/twolame/libtwolame";
};
name = "Debug Shared";
};
@ -8835,7 +8817,7 @@
);
PRODUCT_NAME = Audacity;
SKIP_INSTALL = NO;
USER_HEADER_SEARCH_PATHS = "$(TOPLEVEL)/include $(TOPLEVEL)/mac $(TOPLEVEL)/src/** $(TOPLEVEL)/lib-src/FileDialog $(TOPLEVEL)/lib-src/libflac/include $(TOPLEVEL)/lib-src/libid3tag $(TOPLEVEL)/lib-src/lame $(TOPLEVEL)/lib-src/libmad $(TOPLEVEL)/lib-src/libogg/include $(TOPLEVEL)/lib-src/libnyquist/nyq $(TOPLEVEL)/lib-src/libresample/include $(TOPLEVEL)/lib-src/libsndfile/src $(TOPLEVEL)/lib-src/libsoxr/src $(TOPLEVEL)/lib-src/libvamp $(TOPLEVEL)/lib-src/libvorbis/include $(TOPLEVEL)/lib-src/portaudio-v19/include $(TOPLEVEL)/lib-src/portmixer/px_common $(TOPLEVEL)/lib-src/portsmf $(TOPLEVEL)/lib-src/soundtouch/include $(TOPLEVEL)/lib-src/lv2/include $(TOPLEVEL)/lib-src/twolame/libtwolame";
USER_HEADER_SEARCH_PATHS = "$(TOPLEVEL)/include $(TOPLEVEL)/mac $(TOPLEVEL)/src/** $(TOPLEVEL)/lib-src/FileDialog $(TOPLEVEL)/lib-src/libflac/include $(TOPLEVEL)/lib-src/libid3tag $(TOPLEVEL)/lib-src/lame $(TOPLEVEL)/lib-src/libmad $(TOPLEVEL)/lib-src/libogg/include $(TOPLEVEL)/lib-src/libnyquist/nyq $(TOPLEVEL)/lib-src/libsndfile/src $(TOPLEVEL)/lib-src/libsoxr/src $(TOPLEVEL)/lib-src/libvamp $(TOPLEVEL)/lib-src/libvorbis/include $(TOPLEVEL)/lib-src/portaudio-v19/include $(TOPLEVEL)/lib-src/portmixer/px_common $(TOPLEVEL)/lib-src/portsmf $(TOPLEVEL)/lib-src/soundtouch/include $(TOPLEVEL)/lib-src/lv2/include $(TOPLEVEL)/lib-src/twolame/libtwolame";
};
name = "Release Shared";
};
@ -9329,7 +9311,7 @@
);
PRODUCT_NAME = Audacity;
SKIP_INSTALL = NO;
USER_HEADER_SEARCH_PATHS = "$(TOPLEVEL)/include $(TOPLEVEL)/mac $(TOPLEVEL)/src/** $(TOPLEVEL)/lib-src/FileDialog $(TOPLEVEL)/lib-src/libflac/include $(TOPLEVEL)/lib-src/libid3tag $(TOPLEVEL)/lib-src/lame $(TOPLEVEL)/lib-src/libmad $(TOPLEVEL)/lib-src/libogg/include $(TOPLEVEL)/lib-src/libnyquist/nyq $(TOPLEVEL)/lib-src/libresample/include $(TOPLEVEL)/lib-src/libsndfile/src $(TOPLEVEL)/lib-src/libsoxr/src $(TOPLEVEL)/lib-src/libvamp $(TOPLEVEL)/lib-src/libvorbis/include $(TOPLEVEL)/lib-src/portaudio-v19/include $(TOPLEVEL)/lib-src/portmixer/px_common $(TOPLEVEL)/lib-src/portsmf $(TOPLEVEL)/lib-src/soundtouch/include $(TOPLEVEL)/lib-src/lv2/include $(TOPLEVEL)/lib-src/twolame/libtwolame";
USER_HEADER_SEARCH_PATHS = "$(TOPLEVEL)/include $(TOPLEVEL)/mac $(TOPLEVEL)/src/** $(TOPLEVEL)/lib-src/FileDialog $(TOPLEVEL)/lib-src/libflac/include $(TOPLEVEL)/lib-src/libid3tag $(TOPLEVEL)/lib-src/lame $(TOPLEVEL)/lib-src/libmad $(TOPLEVEL)/lib-src/libogg/include $(TOPLEVEL)/lib-src/libnyquist/nyq $(TOPLEVEL)/lib-src/libsndfile/src $(TOPLEVEL)/lib-src/libsoxr/src $(TOPLEVEL)/lib-src/libvamp $(TOPLEVEL)/lib-src/libvorbis/include $(TOPLEVEL)/lib-src/portaudio-v19/include $(TOPLEVEL)/lib-src/portmixer/px_common $(TOPLEVEL)/lib-src/portsmf $(TOPLEVEL)/lib-src/soundtouch/include $(TOPLEVEL)/lib-src/lv2/include $(TOPLEVEL)/lib-src/twolame/libtwolame";
};
name = "Release Static";
};

View File

@ -152,22 +152,6 @@ void QuitAudacity();
#endif
#endif
// For compilers that support precompilation, includes "wx/wx.h".
// Mainly for MSVC developers.
//
// This precompilation is only done for non-unicode debug builds.
// The rationale is that this is where there is the big time saving
// because that's what you build whilst debugging.
// Whilst disabling precompilation for other builds will ensure
// that missing headers that would affect other platforms do get
// seen by MSVC developers too.
#ifndef UNICODE
#ifdef __WXDEBUG__
//#include <wx/wxprec.h>
#endif
#endif
// This macro is used widely, so declared here.
#define QUANTIZED_TIME(time, rate) ((double)((sampleCount)floor(((double)(time) * (rate)) + 0.5))) / (rate)

View File

@ -67,7 +67,6 @@ It handles initialization and termination by subclassing wxApp.
#include "DirManager.h"
#include "commands/CommandHandler.h"
#include "commands/AppCommandEvent.h"
#include "effects/LoadEffects.h"
#include "effects/Contrast.h"
#include "widgets/ASlider.h"
#include "FFmpeg.h"
@ -1320,8 +1319,6 @@ Click the 'Help' button for known issue."),
InitDitherers();
InitAudioIO();
LoadEffects();
#ifdef __WXMAC__
// On the Mac, users don't expect a program to quit when you close the last window.
@ -1926,8 +1923,6 @@ int AudacityApp::OnExit()
DropFFmpegLibs();
#endif
UnloadEffects();
DeinitFFT();
BlockFile::Deinit();

View File

@ -1383,7 +1383,6 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
}
} while(!bDone);
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
if (mNumPlaybackChannels > 0)
{
EffectManager & em = EffectManager::Get();
@ -1407,7 +1406,6 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
em.RealtimeAddProcessor(group++, chanCnt, vt->GetRate());
}
}
#endif
#ifdef AUTOMATED_INPUT_LEVEL_ADJUSTMENT
AILASetStartTime();
@ -1500,12 +1498,10 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
void AudioIO::StartStreamCleanup(bool bOnlyBuffers)
{
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
if (mNumPlaybackChannels > 0)
{
EffectManager::Get().RealtimeFinalize();
}
#endif
if(mPlaybackBuffers)
{
@ -1709,13 +1705,11 @@ void AudioIO::StopStream()
wxMutexLocker locker(mSuspendAudioThread);
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
// No longer need effects processing
if (mNumPlaybackChannels > 0)
{
EffectManager::Get().RealtimeFinalize();
}
#endif
//
// We got here in one of two ways:
@ -1964,7 +1958,6 @@ void AudioIO::StopStream()
void AudioIO::SetPaused(bool state)
{
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
if (state != mPaused)
{
if (state)
@ -1976,7 +1969,6 @@ void AudioIO::SetPaused(bool state)
EffectManager::Get().RealtimeResume();
}
}
#endif
mPaused = state;
}
@ -3632,10 +3624,8 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
tempBufs[c] = (float *) alloca(framesPerBuffer * sizeof(float));
}
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
EffectManager & em = EffectManager::Get();
em.RealtimeProcessStart();
#endif
bool selected = false;
int group = 0;
@ -3718,13 +3708,12 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
}
#endif
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
if( !cut && selected )
{
len = em.RealtimeProcess(group, chanCnt, tempBufs, len);
}
group++;
#endif
// If our buffer is empty and the time indicator is past
// the end, then we've actually finished playing the entire
// selection.
@ -3783,9 +3772,7 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
chanCnt = 0;
}
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
em.RealtimeProcessEnd();
#endif
gAudioIO->mLastPlaybackTimeMillis = ::wxGetLocalTimeMillis();

View File

@ -57,7 +57,6 @@ static wxString SpecialCommands[] = {
// wxT("Import"), // non-functioning
wxT("ExportMP3_56k_before"),
wxT("ExportMP3_56k_after"),
wxT("StereoToMono"),
wxT("ExportFLAC"),
wxT("ExportMP3"),
wxT("ExportOgg"),
@ -381,6 +380,53 @@ bool BatchCommands::IsMono()
return mono;
}
wxString BatchCommands::BuildCleanFileName(wxString fileName, wxString extension)
{
wxFileName newFileName(fileName);
wxString justName = newFileName.GetName();
wxString pathName = newFileName.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
if (justName == wxT("")) {
wxDateTime now = wxDateTime::Now();
int year = now.GetYear();
wxDateTime::Month month = now.GetMonth();
wxString monthName = now.GetMonthName(month);
int dom = now.GetDay();
int hour = now.GetHour();
int minute = now.GetMinute();
int second = now.GetSecond();
justName = wxString::Format(wxT("%d-%s-%02d-%02d-%02d-%02d"),
year, monthName.c_str(), dom, hour, minute, second);
// SetName(cleanedFileName);
// bool isStereo;
// double endTime = project->mTracks->GetEndTime();
// double startTime = 0.0;
//OnSelectAll();
pathName = gPrefs->Read(wxT("/DefaultOpenPath"), ::wxGetCwd());
::wxMessageBox(wxString::Format(wxT("Export recording to %s\n/cleaned/%s%s"),
pathName.c_str(), justName.c_str(), extension.c_str()),
wxT("Export recording"),
wxOK | wxCENTRE);
pathName += wxT("/");
}
wxString cleanedName = pathName;
cleanedName += wxT("cleaned");
bool flag = ::wxFileName::FileExists(cleanedName);
if (flag == true) {
::wxMessageBox(wxT("Cannot create directory 'cleaned'. \nFile already exists that is not a directory"));
return wxT("");
}
::wxFileName::Mkdir(cleanedName, 0777, wxPATH_MKDIR_FULL); // make sure it exists
cleanedName += wxT("/");
cleanedName += justName;
cleanedName += extension;
wxGetApp().AddFileToHistory(cleanedName);
return cleanedName;
}
bool BatchCommands::WriteMp3File( const wxString Name, int bitrate )
{ //check if current project is mono or stereo
int numChannels = 2;
@ -450,10 +496,10 @@ bool BatchCommands::ApplySpecialCommand(int WXUNUSED(iCommand), const wxString c
else extension = wxT(".mp3");
if (mFileName.IsEmpty()) {
filename = project->BuildCleanFileName(project->GetFileName(), extension);
filename = BuildCleanFileName(project->GetFileName(), extension);
}
else {
filename = project->BuildCleanFileName(mFileName, extension);
filename = BuildCleanFileName(mFileName, extension);
}
// We have a command index, but we don't use it!
@ -470,14 +516,6 @@ bool BatchCommands::ApplySpecialCommand(int WXUNUSED(iCommand), const wxString c
} else if (command == wxT("ExportMP3_56k_after")) {
filename.Replace(wxT("cleaned/"), wxT("cleaned/MasterAfter_"), false);
return WriteMp3File(filename, 56);
} else if (command == wxT("StereoToMono")) {
// StereoToMono is an effect masquerading as a menu item.
const PluginID & ID = EffectManager::Get().GetEffectByIdentifier(wxT("StereoToMono"));
if (!ID.empty()) {
return ApplyEffectCommand(ID, command, params);
}
wxMessageBox(_("Stereo to Mono Effect not found"));
return false;
} else if (command == wxT("ExportMP3")) {
return WriteMp3File(filename, 0); // 0 bitrate means use default/current
} else if (command == wxT("ExportWAV")) {
@ -551,8 +589,12 @@ bool BatchCommands::ApplyEffectCommand(const PluginID & ID, const wxString comma
// (most effects require that you have something selected).
project->SelectAllIfNone();
if (!SetCurrentParametersFor(command, params))
return false;
// NOW actually apply the effect.
return project->OnEffect(ALL_EFFECTS | CONFIGURED_EFFECT , ID, params, false);
return project->OnEffect(ID, AudacityProject::OnEffectFlags::kConfigured |
AudacityProject::OnEffectFlags::kSkipState);
}
bool BatchCommands::ApplyCommand(const wxString command, const wxString params)

View File

@ -33,6 +33,7 @@ class BatchCommands {
void AbortBatch();
// Utility functions for the special commands.
wxString BuildCleanFileName(wxString fileName, wxString extension);
bool WriteMp3File( const wxString Name, int bitrate );
double GetEndTime();
bool IsMono();

View File

@ -39,7 +39,7 @@
#define EXPERIMENTAL_FULL_WASAPI
// JKC (effect by Norm C, 02 Oct 2013)
//#define EXPERIMENTAL_SCIENCE_FILTERS
#define EXPERIMENTAL_SCIENCE_FILTERS
// LLL, 01 Oct 2013:
// new key assignment view for preferences
@ -73,6 +73,8 @@
// As a minimum, if this is turned on for a release,
// it should have an easy mechanism to disable it at run-time, such as a menu item or a pref,
// preferrably disabled until other work is done. Martyn 22/12/2008.
//
// All code removed after 2.1.0 release since it was unmaintained. LLL
//#define EFFECT_CATEGORIES
// Andreas Micheler, 20.Nov 2007:
@ -150,10 +152,7 @@
// Module prefs provides a panel in prefs where users can choose which modules
// to enable.
// #define EXPERIMENTAL_MODULE_PREFS
// Define to include realtime effects processing.
#define EXPERIMENTAL_REALTIME_EFFECTS
#define EXPERIMENTAL_MODULE_PREFS
// Define to include the effects rack (such as it is).
//#define EXPERIMENTAL_EFFECTS_RACK

View File

@ -321,8 +321,6 @@ audacity_SOURCES = \
effects/Echo.h \
effects/Effect.cpp \
effects/Effect.h \
effects/EffectCategory.cpp \
effects/EffectCategory.h \
effects/EffectManager.cpp \
effects/EffectManager.h \
effects/EffectRack.cpp \
@ -656,11 +654,6 @@ audacity_SOURCES += \
effects/lv2/LoadLV2.h \
effects/lv2/LV2Effect.cpp \
effects/lv2/LV2Effect.h \
effects/lv2/lv2_event.h \
effects/lv2/lv2_event_helpers.h \
effects/lv2/LV2PortGroup.cpp \
effects/lv2/LV2PortGroup.h \
effects/lv2/lv2_uri_map.h \
$(NULL)
endif

View File

@ -148,11 +148,6 @@ bin_PROGRAMS = audacity$(EXEEXT)
@USE_LV2_TRUE@ effects/lv2/LoadLV2.h \
@USE_LV2_TRUE@ effects/lv2/LV2Effect.cpp \
@USE_LV2_TRUE@ effects/lv2/LV2Effect.h \
@USE_LV2_TRUE@ effects/lv2/lv2_event.h \
@USE_LV2_TRUE@ effects/lv2/lv2_event_helpers.h \
@USE_LV2_TRUE@ effects/lv2/LV2PortGroup.cpp \
@USE_LV2_TRUE@ effects/lv2/LV2PortGroup.h \
@USE_LV2_TRUE@ effects/lv2/lv2_uri_map.h \
@USE_LV2_TRUE@ $(NULL)
@USE_PORTSMF_TRUE@am__append_34 = $(PORTSMF_CFLAGS)
@ -354,7 +349,6 @@ am__audacity_SOURCES_DIST = BlockFile.cpp BlockFile.h DirManager.cpp \
effects/Compressor.h effects/Contrast.cpp effects/Contrast.h \
effects/DtmfGen.cpp effects/DtmfGen.h effects/Echo.cpp \
effects/Echo.h effects/Effect.cpp effects/Effect.h \
effects/EffectCategory.cpp effects/EffectCategory.h \
effects/EffectManager.cpp effects/EffectManager.h \
effects/EffectRack.cpp effects/EffectRack.h \
effects/Equalization.cpp effects/Equalization.h \
@ -469,14 +463,12 @@ am__audacity_SOURCES_DIST = BlockFile.cpp BlockFile.h DirManager.cpp \
effects/nyquist/Nyquist.cpp effects/nyquist/Nyquist.h \
effects/lv2/LoadLV2.cpp effects/lv2/LoadLV2.h \
effects/lv2/LV2Effect.cpp effects/lv2/LV2Effect.h \
effects/lv2/lv2_event.h effects/lv2/lv2_event_helpers.h \
effects/lv2/LV2PortGroup.cpp effects/lv2/LV2PortGroup.h \
effects/lv2/lv2_uri_map.h NoteTrack.cpp NoteTrack.h \
import/ImportMIDI.cpp import/ImportMIDI.h import/ImportQT.cpp \
import/ImportQT.h effects/vamp/LoadVamp.cpp \
effects/vamp/LoadVamp.h effects/vamp/VampEffect.cpp \
effects/vamp/VampEffect.h effects/VST/aeffectx.h \
effects/VST/VSTEffect.cpp effects/VST/VSTEffect.h
NoteTrack.cpp NoteTrack.h import/ImportMIDI.cpp \
import/ImportMIDI.h import/ImportQT.cpp import/ImportQT.h \
effects/vamp/LoadVamp.cpp effects/vamp/LoadVamp.h \
effects/vamp/VampEffect.cpp effects/vamp/VampEffect.h \
effects/VST/aeffectx.h effects/VST/VSTEffect.cpp \
effects/VST/VSTEffect.h
am__objects_1 = audacity-BlockFile.$(OBJEXT) \
audacity-DirManager.$(OBJEXT) audacity-Dither.$(OBJEXT) \
audacity-FileFormats.$(OBJEXT) audacity-Internat.$(OBJEXT) \
@ -502,8 +494,7 @@ am__objects_1 = audacity-BlockFile.$(OBJEXT) \
@USE_LIBNYQUIST_TRUE@am__objects_7 = effects/nyquist/audacity-LoadNyquist.$(OBJEXT) \
@USE_LIBNYQUIST_TRUE@ effects/nyquist/audacity-Nyquist.$(OBJEXT)
@USE_LV2_TRUE@am__objects_8 = effects/lv2/audacity-LoadLV2.$(OBJEXT) \
@USE_LV2_TRUE@ effects/lv2/audacity-LV2Effect.$(OBJEXT) \
@USE_LV2_TRUE@ effects/lv2/audacity-LV2PortGroup.$(OBJEXT)
@USE_LV2_TRUE@ effects/lv2/audacity-LV2Effect.$(OBJEXT)
@USE_PORTSMF_TRUE@am__objects_9 = audacity-NoteTrack.$(OBJEXT) \
@USE_PORTSMF_TRUE@ import/audacity-ImportMIDI.$(OBJEXT)
@USE_QUICKTIME_TRUE@am__objects_10 = \
@ -595,7 +586,6 @@ am_audacity_OBJECTS = $(am__objects_1) audacity-AboutDialog.$(OBJEXT) \
effects/audacity-DtmfGen.$(OBJEXT) \
effects/audacity-Echo.$(OBJEXT) \
effects/audacity-Effect.$(OBJEXT) \
effects/audacity-EffectCategory.$(OBJEXT) \
effects/audacity-EffectManager.$(OBJEXT) \
effects/audacity-EffectRack.$(OBJEXT) \
effects/audacity-Equalization.$(OBJEXT) \
@ -1217,7 +1207,6 @@ audacity_SOURCES = $(libaudacity_la_SOURCES) AboutDialog.cpp \
effects/Compressor.h effects/Contrast.cpp effects/Contrast.h \
effects/DtmfGen.cpp effects/DtmfGen.h effects/Echo.cpp \
effects/Echo.h effects/Effect.cpp effects/Effect.h \
effects/EffectCategory.cpp effects/EffectCategory.h \
effects/EffectManager.cpp effects/EffectManager.h \
effects/EffectRack.cpp effects/EffectRack.h \
effects/Equalization.cpp effects/Equalization.h \
@ -1592,8 +1581,6 @@ effects/audacity-Echo.$(OBJEXT): effects/$(am__dirstamp) \
effects/$(DEPDIR)/$(am__dirstamp)
effects/audacity-Effect.$(OBJEXT): effects/$(am__dirstamp) \
effects/$(DEPDIR)/$(am__dirstamp)
effects/audacity-EffectCategory.$(OBJEXT): effects/$(am__dirstamp) \
effects/$(DEPDIR)/$(am__dirstamp)
effects/audacity-EffectManager.$(OBJEXT): effects/$(am__dirstamp) \
effects/$(DEPDIR)/$(am__dirstamp)
effects/audacity-EffectRack.$(OBJEXT): effects/$(am__dirstamp) \
@ -1908,9 +1895,6 @@ effects/lv2/audacity-LoadLV2.$(OBJEXT): effects/lv2/$(am__dirstamp) \
effects/lv2/$(DEPDIR)/$(am__dirstamp)
effects/lv2/audacity-LV2Effect.$(OBJEXT): effects/lv2/$(am__dirstamp) \
effects/lv2/$(DEPDIR)/$(am__dirstamp)
effects/lv2/audacity-LV2PortGroup.$(OBJEXT): \
effects/lv2/$(am__dirstamp) \
effects/lv2/$(DEPDIR)/$(am__dirstamp)
import/audacity-ImportMIDI.$(OBJEXT): import/$(am__dirstamp) \
import/$(DEPDIR)/$(am__dirstamp)
import/audacity-ImportQT.$(OBJEXT): import/$(am__dirstamp) \
@ -2104,7 +2088,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@effects/$(DEPDIR)/audacity-DtmfGen.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@effects/$(DEPDIR)/audacity-Echo.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@effects/$(DEPDIR)/audacity-Effect.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@effects/$(DEPDIR)/audacity-EffectCategory.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@effects/$(DEPDIR)/audacity-EffectManager.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@effects/$(DEPDIR)/audacity-EffectRack.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@effects/$(DEPDIR)/audacity-Equalization.Po@am__quote@
@ -2141,7 +2124,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@effects/audiounits/$(DEPDIR)/audacity-AudioUnitEffect.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@effects/ladspa/$(DEPDIR)/audacity-LadspaEffect.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@effects/lv2/$(DEPDIR)/audacity-LV2Effect.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@effects/lv2/$(DEPDIR)/audacity-LV2PortGroup.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@effects/lv2/$(DEPDIR)/audacity-LoadLV2.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@effects/nyquist/$(DEPDIR)/audacity-LoadNyquist.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@effects/nyquist/$(DEPDIR)/audacity-Nyquist.Po@am__quote@
@ -4125,20 +4107,6 @@ effects/audacity-Effect.obj: effects/Effect.cpp
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o effects/audacity-Effect.obj `if test -f 'effects/Effect.cpp'; then $(CYGPATH_W) 'effects/Effect.cpp'; else $(CYGPATH_W) '$(srcdir)/effects/Effect.cpp'; fi`
effects/audacity-EffectCategory.o: effects/EffectCategory.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT effects/audacity-EffectCategory.o -MD -MP -MF effects/$(DEPDIR)/audacity-EffectCategory.Tpo -c -o effects/audacity-EffectCategory.o `test -f 'effects/EffectCategory.cpp' || echo '$(srcdir)/'`effects/EffectCategory.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) effects/$(DEPDIR)/audacity-EffectCategory.Tpo effects/$(DEPDIR)/audacity-EffectCategory.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='effects/EffectCategory.cpp' object='effects/audacity-EffectCategory.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o effects/audacity-EffectCategory.o `test -f 'effects/EffectCategory.cpp' || echo '$(srcdir)/'`effects/EffectCategory.cpp
effects/audacity-EffectCategory.obj: effects/EffectCategory.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT effects/audacity-EffectCategory.obj -MD -MP -MF effects/$(DEPDIR)/audacity-EffectCategory.Tpo -c -o effects/audacity-EffectCategory.obj `if test -f 'effects/EffectCategory.cpp'; then $(CYGPATH_W) 'effects/EffectCategory.cpp'; else $(CYGPATH_W) '$(srcdir)/effects/EffectCategory.cpp'; fi`
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) effects/$(DEPDIR)/audacity-EffectCategory.Tpo effects/$(DEPDIR)/audacity-EffectCategory.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='effects/EffectCategory.cpp' object='effects/audacity-EffectCategory.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o effects/audacity-EffectCategory.obj `if test -f 'effects/EffectCategory.cpp'; then $(CYGPATH_W) 'effects/EffectCategory.cpp'; else $(CYGPATH_W) '$(srcdir)/effects/EffectCategory.cpp'; fi`
effects/audacity-EffectManager.o: effects/EffectManager.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT effects/audacity-EffectManager.o -MD -MP -MF effects/$(DEPDIR)/audacity-EffectManager.Tpo -c -o effects/audacity-EffectManager.o `test -f 'effects/EffectManager.cpp' || echo '$(srcdir)/'`effects/EffectManager.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) effects/$(DEPDIR)/audacity-EffectManager.Tpo effects/$(DEPDIR)/audacity-EffectManager.Po
@ -5889,20 +5857,6 @@ effects/lv2/audacity-LV2Effect.obj: effects/lv2/LV2Effect.cpp
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o effects/lv2/audacity-LV2Effect.obj `if test -f 'effects/lv2/LV2Effect.cpp'; then $(CYGPATH_W) 'effects/lv2/LV2Effect.cpp'; else $(CYGPATH_W) '$(srcdir)/effects/lv2/LV2Effect.cpp'; fi`
effects/lv2/audacity-LV2PortGroup.o: effects/lv2/LV2PortGroup.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT effects/lv2/audacity-LV2PortGroup.o -MD -MP -MF effects/lv2/$(DEPDIR)/audacity-LV2PortGroup.Tpo -c -o effects/lv2/audacity-LV2PortGroup.o `test -f 'effects/lv2/LV2PortGroup.cpp' || echo '$(srcdir)/'`effects/lv2/LV2PortGroup.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) effects/lv2/$(DEPDIR)/audacity-LV2PortGroup.Tpo effects/lv2/$(DEPDIR)/audacity-LV2PortGroup.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='effects/lv2/LV2PortGroup.cpp' object='effects/lv2/audacity-LV2PortGroup.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o effects/lv2/audacity-LV2PortGroup.o `test -f 'effects/lv2/LV2PortGroup.cpp' || echo '$(srcdir)/'`effects/lv2/LV2PortGroup.cpp
effects/lv2/audacity-LV2PortGroup.obj: effects/lv2/LV2PortGroup.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT effects/lv2/audacity-LV2PortGroup.obj -MD -MP -MF effects/lv2/$(DEPDIR)/audacity-LV2PortGroup.Tpo -c -o effects/lv2/audacity-LV2PortGroup.obj `if test -f 'effects/lv2/LV2PortGroup.cpp'; then $(CYGPATH_W) 'effects/lv2/LV2PortGroup.cpp'; else $(CYGPATH_W) '$(srcdir)/effects/lv2/LV2PortGroup.cpp'; fi`
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) effects/lv2/$(DEPDIR)/audacity-LV2PortGroup.Tpo effects/lv2/$(DEPDIR)/audacity-LV2PortGroup.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='effects/lv2/LV2PortGroup.cpp' object='effects/lv2/audacity-LV2PortGroup.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o effects/lv2/audacity-LV2PortGroup.obj `if test -f 'effects/lv2/LV2PortGroup.cpp'; then $(CYGPATH_W) 'effects/lv2/LV2PortGroup.cpp'; else $(CYGPATH_W) '$(srcdir)/effects/lv2/LV2PortGroup.cpp'; fi`
audacity-NoteTrack.o: NoteTrack.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-NoteTrack.o -MD -MP -MF $(DEPDIR)/audacity-NoteTrack.Tpo -c -o audacity-NoteTrack.o `test -f 'NoteTrack.cpp' || echo '$(srcdir)/'`NoteTrack.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-NoteTrack.Tpo $(DEPDIR)/audacity-NoteTrack.Po

View File

@ -178,28 +178,10 @@ AudacityProjectCommandFunctor::AudacityProjectCommandFunctor(AudacityProject *pr
mPluginID = pluginID;
}
#if defined(EFFECT_CATEGORIES)
AudacityProjectCommandFunctor::AudacityProjectCommandFunctor(AudacityProject *project,
audCommandListFunction commandFunction,
wxArrayInt explicitIndices)
{
mProject = project;
mCommandFunction = NULL;
mCommandKeyFunction = NULL;
mCommandListFunction = commandFunction;
mCommandPluginFunction = NULL;
mExplicitIndices = explicitIndices;
}
#endif
void AudacityProjectCommandFunctor::operator()(int index, const wxEvent * evt)
{
if (mCommandPluginFunction)
(mProject->*(mCommandPluginFunction)) (mPluginID);
#if defined(EFFECT_CATEGORIES)
else if (mCommandListFunction && mExplicitIndices.GetCount() > 0)
(mProject->*(mCommandListFunction)) (mExplicitIndices[index]);
#endif
(mProject->*(mCommandPluginFunction)) (mPluginID, AudacityProject::OnEffectFlags::kNone);
else if (mCommandListFunction)
(mProject->*(mCommandListFunction)) (index);
else if (mCommandKeyFunction)
@ -992,44 +974,10 @@ void AudacityProject::CreateMenusAndCommands()
c->BeginMenu(_("&Generate"));
c->SetDefaultFlags(AudioIONotBusyFlag, AudioIONotBusyFlag);
#ifndef EFFECT_CATEGORIES
PopulateEffectsMenu(c,
EffectTypeGenerate,
AudioIONotBusyFlag,
AudioIONotBusyFlag);
#else
int flags;
flags = INSERT_EFFECT | BUILTIN_EFFECT | PLUGIN_EFFECT;
EffectCategory* ac =
em.LookupCategory(wxT("http://lv2plug.in/ns/lv2core#GeneratorPlugin"));
CategorySet roots = ac->GetSubCategories();
EffectSet generators = ac->GetEffects();
EffectSet topLevel = CreateEffectSubmenus(c, roots, flags, 0);
std::copy(generators.begin(), generators.end(),
std::insert_iterator<EffectSet>(topLevel, topLevel.begin()));
AddEffectsToMenu(c, topLevel);
// Add all uncategorised effects in a special submenu
EffectSet unsorted =
em.GetUnsortedEffects(flags);
if (unsorted.size() > 0) {
c->AddSeparator();
c->BeginSubMenu(_("Unsorted"));
names.Clear();
indices.Clear();
EffectSet::const_iterator iter;
for (iter = unsorted.begin(); iter != unsorted.end(); ++iter) {
names.Add((*iter)->GetEffectName());
indices.Add((*iter)->GetEffectID());
}
c->AddItemList(wxT("Generate"), names,
FNI(OnProcessAny, indices), true);
c->EndSubMenu();
}
#endif // EFFECT_CATEGORIES
c->EndMenu();
@ -1040,7 +988,7 @@ void AudacityProject::CreateMenusAndCommands()
c->BeginMenu(_("Effe&ct"));
wxString buildMenuLabel;
if (mLastEffectType != 0) {
if (!mLastEffect.IsEmpty()) {
buildMenuLabel.Printf(_("Repeat %s"),
EffectManager::Get().GetEffectName(mLastEffect).c_str());
}
@ -1053,40 +1001,10 @@ void AudacityProject::CreateMenusAndCommands()
c->AddSeparator();
// this is really ugly but we need to keep all the old code to get any
// effects at all in the menu when EFFECT_CATEGORIES is undefined
#ifndef EFFECT_CATEGORIES
PopulateEffectsMenu(c,
EffectTypeProcess,
AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag,
TracksExistFlag | IsRealtimeNotActiveFlag);
#else
int flags = PROCESS_EFFECT | BUILTIN_EFFECT | PLUGIN_EFFECT | ADVANCED_EFFECT;
// The categories form a DAG, so we start at the roots (the categories
// without incoming links)
CategorySet roots = em.GetRootCategories();
EffectSet topLevel = CreateEffectSubmenus(c, roots, flags, 0);
AddEffectsToMenu(c, topLevel);
// Add all uncategorised effects in a special submenu
EffectSet unsorted =
em.GetUnsortedEffects(flags);
if (unsorted.size() > 0) {
c->AddSeparator();
c->BeginSubMenu(_("Unsorted"));
names.Clear();
indices.Clear();
EffectSet::const_iterator iter;
for (iter = unsorted.begin(); iter != unsorted.end(); ++iter) {
names.Add((*iter)->GetEffectName());
indices.Add((*iter)->GetEffectID());
}
c->AddItemList(wxT("Effect"), names, FNI(OnProcessAny, indices), true);
c->EndSubMenu();
}
#endif
c->EndMenu();
@ -1103,42 +1021,10 @@ void AudacityProject::CreateMenusAndCommands()
AudioIONotBusyFlag | WaveTracksSelectedFlag | TimeSelectedFlag,
AudioIONotBusyFlag | WaveTracksSelectedFlag | TimeSelectedFlag);
#ifndef EFFECT_CATEGORIES
PopulateEffectsMenu(c,
EffectTypeAnalyze,
AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag,
TracksExistFlag | IsRealtimeNotActiveFlag);
#else
flags = ANALYZE_EFFECT | BUILTIN_EFFECT | PLUGIN_EFFECT;
EffectCategory* ac =
em.LookupCategory(wxT("http://lv2plug.in/ns/lv2core#AnalyserPlugin"));
CategorySet roots = ac->GetSubCategories();
EffectSet analyzers = ac->GetEffects();
EffectSet topLevel = CreateEffectSubmenus(c, roots, flags, 0);
std::copy(analyzers.begin(), analyzers.end(),
std::insert_iterator<EffectSet>(topLevel, topLevel.begin()));
AddEffectsToMenu(c, topLevel);
// Add all uncategorised effects in a special submenu
EffectSet unsorted =
em.GetUnsortedEffects(flags);
if (unsorted.size() > 0) {
c->AddSeparator();
c->BeginSubMenu(_("Unsorted"));
names.Clear();
indices.Clear();
EffectSet::const_iterator iter;
for (iter = unsorted.begin(); iter != unsorted.end(); ++iter) {
names.Add((*iter)->GetEffectName());
indices.Add((*iter)->GetEffectID());
}
c->AddItemList(wxT("Analyze"), names,
FNI(OnProcessAny, indices), true);
c->EndSubMenu();
}
#endif // EFFECT_CATEGORIES
c->EndMenu();
@ -1381,7 +1267,7 @@ void AudacityProject::PopulateEffectsMenu(CommandManager* c,
AddEffectMenuItems(c, defplugs, batchflags, realflags, true);
if (optplugs.GetCount())
if (defplugs.GetCount() && optplugs.GetCount())
{
c->AddSeparator();
}
@ -1421,13 +1307,6 @@ void AudacityProject::AddEffectMenuItems(CommandManager *c,
wxString name = plug->GetName();
// This goes away once everything has been converted to new format
wxString stripped;
if (name.EndsWith(wxT("..."), &stripped))
{
name = stripped;
}
if (plug->IsEffectInteractive())
{
name += wxT("...");
@ -1492,13 +1371,6 @@ void AudacityProject::AddEffectMenuItems(CommandManager *c,
wxString name = plug->GetName();
// This goes away once everything has been converted to new format
wxString stripped;
if (name.EndsWith(wxT("..."), &stripped))
{
name = stripped;
}
if (plug->IsEffectInteractive())
{
name += wxT("...");
@ -1635,73 +1507,6 @@ void AudacityProject::AddEffectMenuItemGroup(CommandManager *c,
return;
}
#ifdef EFFECT_CATEGORIES
EffectSet AudacityProject::CreateEffectSubmenus(CommandManager* c,
const CategorySet& categories,
int flags,
unsigned submenuThreshold) {
EffectSet topLevel;
CategorySet::const_iterator iter;
for (iter = categories.begin(); iter != categories.end(); ++iter) {
EffectSet effects = (*iter)->GetAllEffects(flags);
// If the subgraph for this category only contains a single effect,
// add it directly in this menu
if (effects.size() <= submenuThreshold)
topLevel.insert(effects.begin(), effects.end());
// If there are more than one effect, add a submenu for the category
else if (effects.size() > 0) {
EffectSet directEffects = (*iter)->GetEffects(flags);
CategorySet subCategories = (*iter)->GetSubCategories();
CategorySet nonEmptySubCategories;
CategorySet::const_iterator sci;
for (sci = subCategories.begin(); sci != subCategories.end(); ++sci) {
if ((*sci)->GetAllEffects(flags).size() > 0)
nonEmptySubCategories.insert(*sci);
}
// If there are no direct effects and only one subcategory,
// add the contents of that subcategory directly in this menu.
if (directEffects.size() == 0 && nonEmptySubCategories.size() == 1) {
EffectSet a = CreateEffectSubmenus(c, nonEmptySubCategories,
flags);
topLevel.insert(a.begin(), a.end());
}
// Else, add submenus for the subcategories
else {
c->BeginSubMenu((*iter)->GetName());
EffectSet a = CreateEffectSubmenus(c, subCategories, flags);
a.insert(directEffects.begin(), directEffects.end());
AddEffectsToMenu(c, a);
c->EndSubMenu();
}
}
}
return topLevel;
}
void AudacityProject::AddEffectsToMenu(CommandManager* c,
const EffectSet& effects) {
wxArrayString names;
wxArrayInt indices;
EffectSet::const_iterator iter;
for (iter = effects.begin(); iter != effects.end(); ++iter) {
names.Add((*iter)->GetEffectName());
indices.Add((*iter)->GetEffectID());
}
c->AddItemList(wxT("Effects"), names, FNI(OnProcessAny, indices), true);
}
#endif
void AudacityProject::CreateRecentFilesMenu(CommandManager *c)
{
// Recent Files and Recent Projects menus
@ -1907,7 +1712,7 @@ wxUint32 AudacityProject::GetUpdateFlags()
if (mUndoManager.UnsavedChanges())
flags |= UnsavedChangesFlag;
if (!mLastEffect.empty())
if (!mLastEffect.IsEmpty())
flags |= HasLastEffectFlag;
if (mUndoManager.UndoAvailable())
@ -1948,10 +1753,8 @@ wxUint32 AudacityProject::GetUpdateFlags()
else
flags |= IsNotSyncLockedFlag;
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
if (!EffectManager::Get().RealtimeIsActive())
flags |= IsRealtimeNotActiveFlag;
#endif
return flags;
}
@ -3258,23 +3061,23 @@ void AudacityProject::OnZeroCrossing()
/// OnEffect() takes a PluginID and has the EffectManager execute the assocated effect.
///
/// At the moment flags are used only to indicate
/// whether to prompt for parameters or whether to
/// use the most recently stored values.
///
/// At some point we should change to specifying a
/// parameter source - one of:
/// + Prompt
/// + Use previous values
/// + Parse from a string that is passed in
///
/// DanH: I've added the third option as a temporary measure. I think this
/// should eventually be done by having effects as Command objects.
bool AudacityProject::OnEffect(int type,
const PluginID & ID,
wxString params,
bool saveState)
/// At the moment flags are used only to indicate whether to prompt for parameters and
/// whether to save the state to history.
bool AudacityProject::OnEffect(const PluginID & ID, int flags)
{
const PluginDescriptor *plug = PluginManager::Get().GetPlugin(ID);
wxASSERT(plug != NULL);
EffectType type = plug->GetEffectType();
// Make sure there's no activity since the effect is about to be applied
// to the project's tracks. Mainly for Apply during RTP, but also used
// for batch commands
if (flags & OnEffectFlags::kConfigured)
{
OnStop();
SelectAllIfNone();
}
wxGetApp().SetMissingAliasedFileWarningShouldShow(true);
TrackListIterator iter(mTracks);
@ -3295,7 +3098,7 @@ bool AudacityProject::OnEffect(int type,
if (count == 0) {
// No tracks were selected...
if (type & INSERT_EFFECT) {
if (type == EffectTypeGenerate) {
// Create a new track for the generated audio...
newTrack = mTrackFactory->NewWaveTrack();
mTracks->Add(newTrack);
@ -3309,154 +3112,77 @@ bool AudacityProject::OnEffect(int type,
EffectManager & em = EffectManager::Get();
if (em.DoEffect(ID, this, type, mRate, mTracks, mTrackFactory,
&mViewInfo.selectedRegion, params))
{
if (saveState)
{
wxString longDesc = em.GetEffectDescription(ID);
wxString shortDesc = em.GetEffectName(ID);
bool success = em.DoEffect(ID, this, mRate,
mTracks, mTrackFactory,
&mViewInfo.selectedRegion,
!(flags & OnEffectFlags::kConfigured));
if (shortDesc.Length() > 3 && shortDesc.Right(3)==wxT("..."))
shortDesc = shortDesc.Left(shortDesc.Length()-3);
PushState(longDesc, shortDesc);
// Only remember a successful effect, don't rmemeber insert,
// or analyze effects.
if ((type & (INSERT_EFFECT | ANALYZE_EFFECT))==0) {
mLastEffect = ID;
mLastEffectType = type;
wxString lastEffectDesc;
/* i18n-hint: %s will be the name of the effect which will be
* repeated if this menu item is chosen */
lastEffectDesc.Printf(_("Repeat %s"), shortDesc.c_str());
mCommandManager.Modify(wxT("RepeatLastEffect"), lastEffectDesc);
}
}
//STM:
//The following automatically re-zooms after sound was generated.
// IMO, it was disorienting, removing to try out without re-fitting
//mchinen:12/14/08 reapplying for generate effects
if ( type & INSERT_EFFECT)
{
if (count == 0 || (clean && mViewInfo.selectedRegion.t0() == 0.0))
OnZoomFit();
// mTrackPanel->Refresh(false);
}
RedrawProject();
if (focus != NULL) {
focus->SetFocus();
}
mTrackPanel->EnsureVisible(mTrackPanel->GetFirstSelectedTrack());
mTrackPanel->Refresh(false);
} else {
if (!success) {
if (newTrack) {
mTracks->Remove(newTrack);
delete newTrack;
mTrackPanel->Refresh(false);
}
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
// For now, we're limiting realtime preview to a single effect, so
// make sure the menus reflect that fact that one may have just been
// opened.
UpdateMenus(false);
#endif
return false;
}
if (!(flags & OnEffectFlags::kSkipState))
{
wxString shortDesc = em.GetEffectName(ID);
wxString longDesc = em.GetEffectDescription(ID);
PushState(longDesc, shortDesc);
// Only remember a successful effect, don't rmemeber insert,
// or analyze effects.
if (type == EffectTypeProcess) {
mLastEffect = ID;
wxString lastEffectDesc;
/* i18n-hint: %s will be the name of the effect which will be
* repeated if this menu item is chosen */
lastEffectDesc.Printf(_("Repeat %s"), shortDesc.c_str());
mCommandManager.Modify(wxT("RepeatLastEffect"), lastEffectDesc);
}
}
//STM:
//The following automatically re-zooms after sound was generated.
// IMO, it was disorienting, removing to try out without re-fitting
//mchinen:12/14/08 reapplying for generate effects
if (type == EffectTypeGenerate)
{
if (count == 0 || (clean && mViewInfo.selectedRegion.t0() == 0.0))
OnZoomFit();
// mTrackPanel->Refresh(false);
}
RedrawProject();
if (focus != NULL) {
focus->SetFocus();
}
mTrackPanel->EnsureVisible(mTrackPanel->GetFirstSelectedTrack());
mTrackPanel->Refresh(false);
return true;
}
void AudacityProject::OnEffect(const PluginID & pluginID)
{
PluginManager & pm = PluginManager::Get();
const PluginDescriptor *plug = pm.GetPlugin(pluginID);
int type;
switch (plug->GetEffectType())
{
case EffectTypeGenerate:
type = INSERT_EFFECT;
break;
case EffectTypeProcess:
type = PROCESS_EFFECT;
break;
case EffectTypeAnalyze:
type = ANALYZE_EFFECT;
break;
case EffectTypeNone:
type = 0;
break;
}
type |= plug->IsEffectDefault() ? BUILTIN_EFFECT : PLUGIN_EFFECT;
OnEffect(type, pluginID);
}
// Warning...complete hackage ahead
void AudacityProject::OnEffect(const PluginID & pluginID, bool configured)
{
PluginManager & pm = PluginManager::Get();
const PluginDescriptor *plug = pm.GetPlugin(pluginID);
int type;
switch (plug->GetEffectType())
{
case EffectTypeGenerate:
type = INSERT_EFFECT;
break;
case EffectTypeProcess:
type = PROCESS_EFFECT;
break;
case EffectTypeAnalyze:
type = ANALYZE_EFFECT;
break;
case EffectTypeNone:
type = 0;
break;
}
type |= plug->IsEffectDefault() ? BUILTIN_EFFECT : PLUGIN_EFFECT;
type |= configured ? CONFIGURED_EFFECT : 0;
OnStop();
SelectAllIfNone();
OnEffect(type, pluginID);
}
void AudacityProject::OnRepeatLastEffect(int WXUNUSED(index))
{
if (!mLastEffect.empty()) {
// Setting the CONFIGURED_EFFECT bit prevents
// prompting for parameters.
OnEffect(mLastEffectType | CONFIGURED_EFFECT, mLastEffect);
if (!mLastEffect.IsEmpty())
{
OnEffect(mLastEffect, OnEffectFlags::kConfigured);
}
}
#ifdef EFFECT_CATEGORIES
void AudacityProject::OnProcessAny(int index)
{
Effect* e = EffectManager::Get().GetEffect(index);
OnEffect(ALL_EFFECTS, e);
}
#endif
void AudacityProject::OnStereoToMono(int WXUNUSED(index))
{
OnEffect(ALL_EFFECTS,
EffectManager::Get().GetEffectByIdentifier(wxT("StereoToMono")));
OnEffect(EffectManager::Get().GetEffectByIdentifier(wxT("StereoToMono")),
OnEffectFlags::kConfigured);
}
//
@ -6359,53 +6085,6 @@ void AudacityProject::OnEditChains()
dlg.ShowModal();
}
wxString AudacityProject::BuildCleanFileName(wxString fileName, wxString extension)
{
wxFileName newFileName(fileName);
wxString justName = newFileName.GetName();
wxString pathName = newFileName.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
if (justName == wxT("")) {
wxDateTime now = wxDateTime::Now();
int year = now.GetYear();
wxDateTime::Month month = now.GetMonth();
wxString monthName = now.GetMonthName(month);
int dom = now.GetDay();
int hour = now.GetHour();
int minute = now.GetMinute();
int second = now.GetSecond();
justName = wxString::Format(wxT("%d-%s-%02d-%02d-%02d-%02d"),
year, monthName.c_str(), dom, hour, minute, second);
// SetName(cleanedFileName);
// bool isStereo;
// double endTime = project->mTracks->GetEndTime();
// double startTime = 0.0;
//OnSelectAll();
pathName = gPrefs->Read(wxT("/DefaultOpenPath"), ::wxGetCwd());
::wxMessageBox(wxString::Format(wxT("Export recording to %s\n/cleaned/%s%s"),
pathName.c_str(), justName.c_str(), extension.c_str()),
wxT("Export recording"),
wxOK | wxCENTRE);
pathName += wxT("/");
}
wxString cleanedName = pathName;
cleanedName += wxT("cleaned");
bool flag = ::wxFileName::FileExists(cleanedName);
if (flag == true) {
::wxMessageBox(wxT("Cannot create directory 'cleaned'. \nFile already exists that is not a directory"));
return wxT("");
}
::wxFileName::Mkdir(cleanedName, 0777, wxPATH_MKDIR_FULL); // make sure it exists
cleanedName += wxT("/");
cleanedName += justName;
cleanedName += extension;
wxGetApp().AddFileToHistory(cleanedName);
return cleanedName;
}
void AudacityProject::OnRemoveTracks()
{
TrackListIterator iter(mTracks);

View File

@ -24,20 +24,6 @@
private:
void CreateMenusAndCommands();
#ifdef EFFECT_CATEGORIES
/** Generate submenus for the categories that contain more than one effect
and return the effects from the categories that do not contain more than
submenuThreshold effects so the caller can add them to the current menu. */
EffectSet CreateEffectSubmenus(CommandManager* c,
const CategorySet& categories, int flags,
unsigned submenuThreshold = 1);
/** Add the set of effects to the current menu. */
void AddEffectsToMenu(CommandManager* c, const EffectSet& effects);
#endif
void PopulateEffectsMenu(CommandManager *c, EffectType type, int batchflags, int realflags);
void AddEffectMenuItems(CommandManager *c, EffectPlugs & plugs, int batchflags, int realflags, bool isDefault);
void AddEffectMenuItemGroup(CommandManager *c, const wxArrayString & names, const PluginIDList & plugs, const wxArrayInt & flags, bool isDefault);
@ -361,17 +347,22 @@ void OnEditLabels();
// Effect Menu
bool OnEffect(int type, const PluginID & ID, wxString params = wxEmptyString, bool saveState = true);
void OnEffect(const PluginID & pluginID);
void OnEffect(const PluginID & pluginID, bool configured = false);
class OnEffectFlags
{
public:
// No flags specified
static const int kNone = 0x00;
// Flag used to disable prompting for configuration parameteres.
static const int kConfigured = 0x01;
// Flag used to disable saving the state after processing.
static const int kSkipState = 0x02;
};
bool OnEffect(const PluginID & ID, int flags = OnEffectFlags::kNone);
void OnRepeatLastEffect(int index);
#ifdef EFFECT_CATEGORIES
void OnProcessAny(int index);
#endif
void OnApplyChain();
void OnEditChains();
void OnStereoToMono(int index);
wxString BuildCleanFileName(wxString fileName, wxString extension);
// Help Menu

View File

@ -413,7 +413,7 @@ bool ModuleManager::DiscoverProviders()
if (module)
{
// Register the provider
pm.RegisterModulePlugin(module);
pm.RegisterPlugin(module);
// Now, allow the module to auto-register children
module->AutoRegisterPlugins(pm);
@ -434,7 +434,7 @@ void ModuleManager::InitializeBuiltins()
if (module->Initialize())
{
// Register the provider
const PluginID & id = pm.RegisterModulePlugin(module);
const PluginID & id = pm.RegisterPlugin(module);
// Need to remember it
mDynModules[id] = module;
@ -508,7 +508,7 @@ void ModuleManager::RegisterModule(ModuleInterface *module)
mDynModules[id] = module;
PluginManager::Get().RegisterModulePlugin(module);
PluginManager::Get().RegisterPlugin(module);
}
void ModuleManager::FindAllPlugins(PluginIDList & providers, wxArrayString & paths)

View File

@ -608,7 +608,11 @@ void PluginRegistrationDialog::PopulateOrExchange(ShuttleGui &S)
}
Layout();
Fit();
SetSizeHints(GetSize());
wxRect r = wxGetClientDisplayRect();
wxSize sz = GetSize();
sz.SetWidth(wxMin(sz.GetWidth(), r.GetWidth()));
sz.SetHeight(wxMin(sz.GetHeight(), r.GetHeight()));
SetMinSize(sz);
// Parent window is usually not there yet, so centre on screen rather than on parent.
CenterOnScreen();
@ -790,7 +794,7 @@ PluginDescriptor::~PluginDescriptor()
return;
}
bool PluginDescriptor::IsInstantiated()
bool PluginDescriptor::IsInstantiated() const
{
return mInstance != NULL;
}
@ -1083,7 +1087,7 @@ void PluginDescriptor::SetImporterExtensions(const wxArrayString & extensions)
//
// ============================================================================
const PluginID & PluginManager::RegisterModulePlugin(ModuleInterface *module)
const PluginID & PluginManager::RegisterPlugin(ModuleInterface *module)
{
PluginDescriptor & plug = CreatePlugin(GetID(module), module, PluginTypeModule);
@ -1093,7 +1097,7 @@ const PluginID & PluginManager::RegisterModulePlugin(ModuleInterface *module)
return plug.GetID();
}
const PluginID & PluginManager::RegisterEffectPlugin(ModuleInterface *provider, EffectIdentInterface *effect)
const PluginID & PluginManager::RegisterPlugin(ModuleInterface *provider, EffectIdentInterface *effect)
{
PluginDescriptor & plug = CreatePlugin(GetID(effect), effect, PluginTypeEffect);
@ -1112,7 +1116,7 @@ const PluginID & PluginManager::RegisterEffectPlugin(ModuleInterface *provider,
return plug.GetID();
}
const PluginID & PluginManager::RegisterImporterPlugin(ModuleInterface *provider, ImporterInterface *importer)
const PluginID & PluginManager::RegisterPlugin(ModuleInterface *provider, ImporterInterface *importer)
{
PluginDescriptor & plug = CreatePlugin(GetID(importer), importer, PluginTypeImporter);
@ -1963,6 +1967,11 @@ const PluginDescriptor *PluginManager::GetFirstPluginForEffectType(EffectType ty
gPrefs->Read(plug.GetEffectFamily() + wxT("/Enable"), &familyEnabled, true);
if (plug.IsValid() && plug.IsEnabled() && plug.GetEffectType() == type && familyEnabled)
{
if (plug.IsInstantiated() && ((Effect *)plug.GetInstance())->IsHidden())
{
continue;
}
return &plug;
}
}
@ -1979,6 +1988,11 @@ const PluginDescriptor *PluginManager::GetNextPluginForEffectType(EffectType typ
gPrefs->Read(plug.GetEffectFamily() + wxT("/Enable"), &familyEnabled, true);
if (plug.IsValid() && plug.IsEnabled() && plug.GetEffectType() == type && familyEnabled)
{
if (plug.IsInstantiated() && ((Effect *)plug.GetInstance())->IsHidden())
{
continue;
}
return &plug;
}
}
@ -1996,7 +2010,7 @@ bool PluginManager::IsRegistered(const PluginID & ID)
return true;
}
const PluginID & PluginManager::RegisterLegacyEffectPlugin(EffectIdentInterface *effect)
const PluginID & PluginManager::RegisterPlugin(EffectIdentInterface *effect)
{
PluginDescriptor & plug = CreatePlugin(GetID(effect), effect, PluginTypeEffect);
@ -2404,7 +2418,7 @@ bool PluginManager::SetConfig(const wxString & key, const sampleCount & value)
return result;
}
wxString PluginManager::SettingsID(const PluginID & ID)
wxString PluginManager::SettingsPath(const PluginID & ID, bool shared)
{
if (mPlugins.find(ID) == mPlugins.end())
{
@ -2412,23 +2426,25 @@ wxString PluginManager::SettingsID(const PluginID & ID)
}
const PluginDescriptor & plug = mPlugins[ID];
wxString id = GetPluginTypeString(plug.GetPluginType()) +
wxT("_") +
plug.GetEffectFamily() + // is empty for non-Effects
wxT("_") +
plug.GetVendor() +
wxT("_") +
(shared ? wxT("") : plug.GetName());
return wxString::Format(wxT("%s_%s_%s_%s"),
GetPluginTypeString(plug.GetPluginType()).c_str(),
plug.GetEffectFamily().c_str(), // is empty for non-Effects
plug.GetVendor().c_str(),
plug.GetName().c_str());
return SETROOT +
ConvertID(id) +
wxCONFIG_PATH_SEPARATOR +
(shared ? wxT("shared") : wxT("private")) +
wxCONFIG_PATH_SEPARATOR;
}
wxString PluginManager::SharedGroup(const PluginID & ID, const wxString & group)
{
wxString settingsID = SettingsID(ID);
wxString path = SETROOT +
ConvertID(settingsID) +
wxCONFIG_PATH_SEPARATOR +
wxT("shared") +
wxCONFIG_PATH_SEPARATOR;
wxString path = SettingsPath(ID, true);
wxFileName f(group);
if (!f.GetName().IsEmpty())
@ -2452,13 +2468,7 @@ wxString PluginManager::SharedKey(const PluginID & ID, const wxString & group, c
wxString PluginManager::PrivateGroup(const PluginID & ID, const wxString & group)
{
wxString settingsID = SettingsID(ID);
wxString path = SETROOT +
ConvertID(settingsID) +
wxCONFIG_PATH_SEPARATOR +
wxT("private") +
wxCONFIG_PATH_SEPARATOR;
wxString path = SettingsPath(ID, false);
wxFileName f(group);
if (!f.GetName().IsEmpty())

View File

@ -45,7 +45,7 @@ public:
PluginDescriptor();
virtual ~PluginDescriptor();
bool IsInstantiated();
bool IsInstantiated() const;
IdentInterface *GetInstance();
void SetInstance(IdentInterface *instance);
@ -173,14 +173,14 @@ public:
// PluginManagerInterface implementation
const PluginID & RegisterModulePlugin(ModuleInterface *module);
const PluginID & RegisterEffectPlugin(ModuleInterface *provider, EffectIdentInterface *effect);
const PluginID & RegisterImporterPlugin(ModuleInterface *provider, ImporterInterface *importer);
virtual const PluginID & RegisterPlugin(ModuleInterface *module);
virtual const PluginID & RegisterPlugin(ModuleInterface *provider, EffectIdentInterface *effect);
virtual const PluginID & RegisterPlugin(ModuleInterface *provider, ImporterInterface *importer);
void FindFilesInPathList(const wxString & pattern,
const wxArrayString & pathList,
wxArrayString & files,
bool directories = false);
virtual void FindFilesInPathList(const wxString & pattern,
const wxArrayString & pathList,
wxArrayString & files,
bool directories = false);
virtual bool GetSharedConfigSubgroups(const PluginID & ID, const wxString & group, wxArrayString & subgroups);
@ -256,8 +256,8 @@ public:
IdentInterface *GetInstance(const PluginID & ID);
void SetInstance(const PluginID & ID, IdentInterface *instance); // TODO: Remove after conversion
//
const PluginID & RegisterLegacyEffectPlugin(EffectIdentInterface *effect);
// For builtin effects
const PluginID & RegisterPlugin(EffectIdentInterface *effect);
private:
void Load();
@ -289,7 +289,7 @@ private:
bool SetConfig(const wxString & key, const double & value);
bool SetConfig(const wxString & key, const sampleCount & value);
wxString SettingsID(const PluginID & ID);
wxString SettingsPath(const PluginID & ID, bool shared);
wxString SharedGroup(const PluginID & ID, const wxString & group);
wxString SharedKey(const PluginID & ID, const wxString & group, const wxString & key);
wxString PrivateGroup(const PluginID & ID, const wxString & group);

View File

@ -772,7 +772,6 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id,
mImportedDependencies(false),
mWantSaveCompressed(false),
mLastEffect(wxEmptyString),
mLastEffectType(0),
mTimerRecordCanceled(false),
mMenuClose(false)
, mbInitializingScrollbar(false)
@ -3656,8 +3655,8 @@ bool AudacityProject::Import(wxString fileName, WaveTrackArray* pTrackArray /*=
//TODO: All we want is a SelectAll()
SelectNone();
SelectAllIfNone();
OnEffect(ALL_EFFECTS | CONFIGURED_EFFECT,
EffectManager::Get().GetEffectByIdentifier(wxT("Normalize")));
OnEffect(EffectManager::Get().GetEffectByIdentifier(wxT("Normalize")),
OnEffectFlags::kConfigured);
}
GetDirManager()->FillBlockfilesCache();

View File

@ -605,8 +605,7 @@ class AUDACITY_DLL_API AudacityProject: public wxFrame,
// Last effect applied to this project
PluginID mLastEffect;
int mLastEffectType;
// The screenshot class needs to access internals
friend class ScreenshotCommand;
@ -626,7 +625,7 @@ class AUDACITY_DLL_API AudacityProject: public wxFrame,
typedef void (AudacityProject::*audCommandFunction)();
typedef void (AudacityProject::*audCommandKeyFunction)(const wxEvent *);
typedef void (AudacityProject::*audCommandListFunction)(int);
typedef void (AudacityProject::*audCommandPluginFunction)(const PluginID &);
typedef bool (AudacityProject::*audCommandPluginFunction)(const PluginID &, int);
// Previously this was in menus.cpp, and the declaration of the
// command functor was not visible anywhere else.
@ -642,11 +641,6 @@ public:
AudacityProjectCommandFunctor(AudacityProject *project,
audCommandPluginFunction commandFunction,
const PluginID & pluginID);
#if defined(EFFECT_CATEGORIES)
AudacityProjectCommandFunctor(AudacityProject *project,
audCommandListFunction commandFunction,
wxArrayInt explicitIndices);
#endif
virtual void operator()(int index = 0, const wxEvent *evt = NULL);
@ -657,9 +651,6 @@ private:
audCommandListFunction mCommandListFunction;
audCommandPluginFunction mCommandPluginFunction;
PluginID mPluginID;
#if defined(EFFECT_CATEGORIES)
wxArrayInt mExplicitIndices;
#endif
};
#endif

View File

@ -1456,6 +1456,12 @@ wxSlider * ShuttleGuiBase::TieSlider( const wxString &Prompt, int &pos, const in
return TieSlider( Prompt, WrappedRef, max, min );
}
wxSlider * ShuttleGuiBase::TieSlider( const wxString &Prompt, double &pos, const double max, const double min )
{
WrappedType WrappedRef( pos );
return TieSlider( Prompt, WrappedRef, max, min );
}
wxSlider * ShuttleGuiBase::TieSlider( const wxString &Prompt, float &pos, const float fMin, const float fMax)
{
const float RoundFix=0.0000001f;
@ -2241,12 +2247,12 @@ void ShuttleGui::AddStandardButtons(long buttons, wxButton *extra)
EndVerticalLay();
}
void ShuttleGui::AddSpace( int width, int height )
wxSizerItem * ShuttleGui::AddSpace( int width, int height )
{
if( mShuttleMode != eIsCreating )
return;
return NULL;
mpSizer->Add( width, height, 0);
return mpSizer->Add( width, height, 0);
}
void ShuttleGui::SetSizeHints( wxWindow *window, const wxArrayString & items )

View File

@ -17,6 +17,7 @@
#include "Audacity.h"
#include <wx/grid.h>
#include <wx/sizer.h>
#include <wx/string.h>
#include "WrappedType.h"
@ -176,6 +177,7 @@ public:
wxSlider * TieSlider( const wxString &Prompt, WrappedType & WrappedRef, const int max, const int min = 0 );
wxSlider * TieSlider( const wxString &Prompt, int &pos, const int max, const int min = 0);
wxSlider * TieSlider( const wxString &Prompt, double &pos, const double max, const double min = 0.0);
wxSlider * TieSlider( const wxString &Prompt, float &pos, const float fMin, const float fMax);
wxSlider * TieVSlider( const wxString &Prompt, float &pos, const float fMin, const float fMax);
@ -259,6 +261,8 @@ public:
int GetId() {return miIdNext;};
void UseUpId();
wxSizer * GetSizer() {return mpSizer;};
protected:
void SetProportions( int Default );
void PushSizer();
@ -368,8 +372,8 @@ public:
RulerPanel * AddRulerVertical( float low, float hi, const wxString & Units );
AttachableScrollBar * AddAttachableScrollBar( long style = wxSB_HORIZONTAL );
void AddStandardButtons( long buttons = eOkButton | eCancelButton, wxButton *extra = NULL );
void AddSpace( int width, int height );
void AddSpace( int size ) { AddSpace( size, size ); };
wxSizerItem * AddSpace( int width, int height );
wxSizerItem * AddSpace( int size ) { return AddSpace( size, size ); };
int GetBorder() { return miBorder; };
void SetSizeHints( int minX = -1, int minY = -1 );
@ -377,5 +381,7 @@ public:
void SetSizeHints( const wxArrayInt & items );
static void SetSizeHints( wxWindow *window, const wxArrayString & items );
static void SetSizeHints( wxWindow *window, const wxArrayInt & items );
teShuttleMode GetMode() { return mShuttleMode; };
};
#endif

View File

@ -1,31 +1,31 @@
/**********************************************************************
Audacity: A Digital Audio Editor
SseMathFuncs.h
Stephen Moshier (wrote original C version, The Cephes Library)
Julien Pommier (converted to use SSE)
Andrew Hallendorff (adapted for Audacity)
*******************************************************************//**
\file SseMathfuncs.h
\brief SSE maths functions (for FFTs)
*//****************************************************************/
/* JKC: The trig functions use Taylor's series, on the range 0 to Pi/4
* computing both Sin and Cos, and using one or the other (in the
* solo functions), or both in the more useful for us for FFTs sincos
* function.
* The constants minus_cephes_DP1 to minus_cephes_DP3 are used in the
* angle reduction modulo function.
* 4 sincos are done at a time.
* If we wanted to do just sin or just cos, we could speed things up
* by queuing up the Sines and Cosines into batches of 4 separately.*/
/**********************************************************************
Audacity: A Digital Audio Editor
SseMathFuncs.h
Stephen Moshier (wrote original C version, The Cephes Library)
Julien Pommier (converted to use SSE)
Andrew Hallendorff (adapted for Audacity)
*******************************************************************//**
\file SseMathfuncs.h
\brief SSE maths functions (for FFTs)
*//****************************************************************/
/* JKC: The trig functions use Taylor's series, on the range 0 to Pi/4
* computing both Sin and Cos, and using one or the other (in the
* solo functions), or both in the more useful for us for FFTs sincos
* function.
* The constants minus_cephes_DP1 to minus_cephes_DP3 are used in the
* angle reduction modulo function.
* 4 sincos are done at a time.
* If we wanted to do just sin or just cos, we could speed things up
* by queuing up the Sines and Cosines into batches of 4 separately.*/

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/x-audacity-project">
<sub-class-of type="text/xml"/>
<comment>Audacity project</comment>
<glob pattern="*.aup"/>
</mime-type>
</mime-info>
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/x-audacity-project">
<sub-class-of type="text/xml"/>
<comment>Audacity project</comment>
<glob pattern="*.aup"/>
</mime-type>
</mime-info>

View File

@ -1126,7 +1126,7 @@ bool CommandManager::HandleTextualCommand(wxString & Str, wxUint32 flags, wxUint
{
if (em.GetEffectByIdentifier(plug->GetID()).IsSameAs(Str))
{
return proj->OnEffect( ALL_EFFECTS | CONFIGURED_EFFECT, plug->GetID());
return proj->OnEffect(plug->GetID(), AudacityProject::OnEffectFlags::kConfigured);
}
plug = pm.GetNextPlugin(PluginTypeEffect);
}

View File

@ -10,329 +10,323 @@
*******************************************************************//**
\class EffectAmplify
\brief An EffectSimpleMono
\brief An Effect
This rewritten class supports a smart Amplify effect - it calculates
the maximum amount of gain that can be applied to all tracks without
causing clipping and selects this as the default parameter.
*//****************************************************************//**
\class AmplifyDialog
\brief Dilaog used with EffectAmplify.
*//*******************************************************************/
#include "../Audacity.h"
#include "Amplify.h"
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
#include <math.h>
#include <float.h>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/intl.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/valtext.h>
#include "../WaveTrack.h"
#include "../widgets/valnum.h"
#include "Amplify.h"
enum
{
ID_Amp = 10000,
ID_Peak,
ID_Clip
};
// Define keys, defaults, minimums, and maximums for the effect parameters
//
// Name Type Key Def Min Max Scale
Param( Ratio, float, wxTRANSLATE("Ratio"), 0.9f, -FLT_MAX, FLT_MAX, 1.0f );
Param( NoClip, bool, wxTRANSLATE("Allow Clipping"), false, false, true, 1.0f );
Param( Amp, float, wxT(""), -0.91515f, -50.0, 50.0, 10.0f );
//
// EffectAmplify
//
BEGIN_EVENT_TABLE(EffectAmplify, wxEvtHandler)
EVT_SLIDER(ID_Amp, EffectAmplify::OnAmpSlider)
EVT_TEXT(ID_Amp, EffectAmplify::OnAmpText)
EVT_TEXT(ID_Peak, EffectAmplify::OnPeakText)
EVT_CHECKBOX(ID_Clip, EffectAmplify::OnClipCheckBox)
END_EVENT_TABLE()
EffectAmplify::EffectAmplify()
{
ratio = float(1.0);
peak = float(0.0);
mAmp = DEF_Amp;
mNoClip = DEF_NoClip;
mRatio = pow(10.0, mAmp * 20.0);
mPeak = 0.0;
}
wxString EffectAmplify::GetEffectDescription() {
// Note: This is useful only after ratio has been set.
return wxString::Format(_("Applied effect: %s %.1f dB"),
this->GetEffectName().c_str(), 20*log10(ratio));
EffectAmplify::~EffectAmplify()
{
}
// IdentInterface implementation
wxString EffectAmplify::GetSymbol()
{
return AMPLIFY_PLUGIN_SYMBOL;
}
wxString EffectAmplify::GetDescription()
{
// Note: This is useful only after ratio has been set.
return wxTRANSLATE("Increases or decreases the volume of the audio you have selected");
}
// EffectIdentInterface implementation
EffectType EffectAmplify::GetType()
{
return EffectTypeProcess;
}
// EffectClientInterface implementation
int EffectAmplify::GetAudioInCount()
{
return 1;
}
int EffectAmplify::GetAudioOutCount()
{
return 1;
}
sampleCount EffectAmplify::ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen)
{
for (sampleCount i = 0; i < blockLen; i++)
{
outBlock[0][i] = inBlock[0][i] * mRatio;
}
return blockLen;
}
bool EffectAmplify::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.WriteFloat(KEY_Ratio, mRatio);
parms.Write(KEY_NoClip, !mNoClip);
return true;
}
bool EffectAmplify::SetAutomationParameters(EffectAutomationParameters & parms)
{
float Ratio;
float def = pow(10.0, DEF_Amp / 20.0);
float min = pow(10.0, MIN_Amp / 20.0);
float max = pow(10.0, MAX_Amp / 20.0);
if (!parms.ReadAndVerify(KEY_Ratio, &Ratio, def, min, max))
{
return false;
}
ReadAndVerifyBool(NoClip);
mRatio = Ratio;
mNoClip = !NoClip;
return true;
}
// Effect implementation
bool EffectAmplify::Init()
{
peak = float(0.0);
mPeak = 0.0;
SelectedTrackListOfKindIterator iter(Track::Wave, mTracks);
for (Track *t = iter.First(); t; t = iter.Next()) {
for (Track *t = iter.First(); t; t = iter.Next())
{
float min, max;
((WaveTrack *)t)->GetMinMax(&min, &max, mT0, mT1);
float newpeak = (fabs(min) > fabs(max) ? fabs(min) : fabs(max));
if (newpeak > peak) {
peak = newpeak;
if (newpeak > mPeak)
{
mPeak = newpeak;
}
}
return true;
}
bool EffectAmplify::TransferParameters( Shuttle & shuttle )
void EffectAmplify::PopulateOrExchange(ShuttleGui & S)
{
shuttle.TransferFloat( wxT("Ratio"), ratio, 0.9f );
return true;
}
bool EffectAmplify::PromptUser()
{
AmplifyDialog dlog(this, mParent);
dlog.peak = peak;
if (peak > 0.0)
dlog.ratio = 1.0 / peak;
else
dlog.ratio = 1.0;
dlog.TransferDataToWindow();
dlog.CenterOnParent();
dlog.ShowModal();
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
ratio = dlog.ratio;
if (dlog.noclip && ratio*peak > 1.0)
ratio = 1.0 / peak;
return true;
}
bool EffectAmplify::ProcessSimpleMono(float *buffer, sampleCount len)
{
sampleCount i;
for (i = 0; i < len; i++)
{
buffer[i] = (buffer[i] * ratio);
}
return true;
}
//----------------------------------------------------------------------------
// AmplifyDialog
//----------------------------------------------------------------------------
#define AMP_MIN -500
#define AMP_MAX 500
#define ID_AMP_TEXT 10001
#define ID_PEAK_TEXT 10002
#define ID_AMP_SLIDER 10003
#define ID_CLIP_CHECKBOX 10004
BEGIN_EVENT_TABLE(AmplifyDialog, EffectDialog)
EVT_SLIDER(ID_AMP_SLIDER, AmplifyDialog::OnAmpSlider)
EVT_TEXT(ID_AMP_TEXT, AmplifyDialog::OnAmpText)
EVT_TEXT(ID_PEAK_TEXT, AmplifyDialog::OnPeakText)
EVT_CHECKBOX(ID_CLIP_CHECKBOX, AmplifyDialog::OnClipCheckBox)
EVT_BUTTON(ID_EFFECT_PREVIEW, AmplifyDialog::OnPreview)
END_EVENT_TABLE()
AmplifyDialog::AmplifyDialog(EffectAmplify *effect,
wxWindow * parent)
: EffectDialog(parent, _("Amplify"), PROCESS_EFFECT),
mEffect(effect)
{
ratio = float(1.0);
peak = float(0.0);
Init();
}
void AmplifyDialog::PopulateOrExchange(ShuttleGui & S)
{
wxTextValidator vld(wxFILTER_NUMERIC);
S.AddSpace(0, 5);
// Amplitude
S.StartMultiColumn(2, wxCENTER);
S.StartVerticalLay(0);
{
mAmpT = S.Id(ID_AMP_TEXT).AddTextBox(_("Amplification (dB):"),
wxT(""),
12);
mAmpT->SetValidator(vld);
}
S.EndMultiColumn();
// Amplitude
S.StartMultiColumn(2, wxCENTER);
{
FloatingPointValidator<float> vldAmp(1, &mAmp);
vldAmp.SetRange(MIN_Amp, MAX_Amp);
mAmpT = S.Id(ID_Amp).AddTextBox(_("Amplification (dB):"), wxT(""), 12);
mAmpT->SetValidator(vldAmp);
}
S.EndMultiColumn();
// Amplitude
S.StartHorizontalLay(wxEXPAND);
{
S.SetStyle(wxSL_HORIZONTAL);
mAmpS = S.Id(ID_AMP_SLIDER).AddSlider(wxT(""),
0,
AMP_MAX,
AMP_MIN);
mAmpS->SetName(_("Amplification dB"));
}
S.EndHorizontalLay();
// Amplitude
S.StartHorizontalLay(wxEXPAND);
{
S.SetStyle(wxSL_HORIZONTAL);
mAmpS = S.Id(ID_Amp).AddSlider(wxT(""), 0, MAX_Amp * SCL_Amp, MIN_Amp * SCL_Amp);
mAmpS->SetName(_("Amplification dB"));
}
S.EndHorizontalLay();
// Peek
S.StartMultiColumn(2, wxCENTER);
{
mPeakT = S.Id(ID_PEAK_TEXT).AddTextBox(_("New Peak Amplitude (dB):"),
wxT(""),
12);
mPeakT->SetValidator(vld);
}
S.EndMultiColumn();
// Peek
S.StartMultiColumn(2, wxCENTER);
{
FloatingPointValidator<float> vldNewPeak(1, &mNewPeak);
vldNewPeak.SetRange(20.0 * log10(pow(10.0, MIN_Amp / 20.0) * mPeak),
20.0 * log10(pow(10.0, MAX_Amp / 20.0) * mPeak));
mNewPeakT = S.Id(ID_Peak).AddTextBox(_("New Peak Amplitude (dB):"), wxT(""), 12);
mNewPeakT->SetValidator(vldNewPeak);
}
S.EndMultiColumn();
// Clipping
S.StartHorizontalLay(wxCENTER);
{
mClip = S.Id(ID_Clip).AddCheckBox(_("Allow clipping"), wxT("false"));
}
S.EndHorizontalLay();
// Clipping
S.StartHorizontalLay(wxCENTER);
{
mClip = S.Id(ID_CLIP_CHECKBOX).AddCheckBox(_("Allow clipping"),
wxT("false"));
}
S.EndHorizontalLay();
S.EndVerticalLay();
return;
}
bool AmplifyDialog::TransferDataToWindow()
bool EffectAmplify::TransferDataToWindow()
{
if (mPeak > 0.0)
mRatio = 1.0 / mPeak;
else
mRatio = 1.0;
// limit range of gain
double dB = TrapDouble(200*log10(ratio), AMP_MIN, AMP_MAX)/10.0;
ratio = pow(10.0, dB/20.0);
double dB = TrapDouble(20.0 * log10(mRatio), MIN_Amp, MAX_Amp);
mAmpS->SetValue((int)(200*log10(ratio)+0.5));
mRatio = pow(10.0, dB / 20.0);
mAmpT->ChangeValue(wxString::Format(wxT("%.1f"), 20*log10(ratio)));
mAmp = 20.0 * log10(mRatio);
mAmpT->GetValidator()->TransferToWindow();
wxString str;
if( ratio*peak > 0.0 )
str.Printf(wxT("%.1f"), 20*log10(ratio*peak));
else
str = _("-Infinity"); // the case when the waveform is all zero
mPeakT->ChangeValue(str);
mAmpS->SetValue((int) (mAmp * SCL_Amp + 0.5));
mNewPeak = 20.0 * log10(mRatio * mPeak);
mNewPeakT->GetValidator()->TransferToWindow();
CheckClip();
return true;
}
bool AmplifyDialog::TransferDataFromWindow()
bool EffectAmplify::TransferDataFromWindow()
{
wxString val = mAmpT->GetValue();
double r;
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
val.ToDouble(&r);
ratio = pow(10.0,TrapDouble(r*10, AMP_MIN, AMP_MAX)/200.0);
mRatio = pow(10.0, TrapDouble(mAmp, MIN_Amp, MAX_Amp) / 20.0);
noclip = !mClip->GetValue();
mNoClip = !mClip->GetValue();
return true;
}
bool AmplifyDialog::Validate()
{
TransferDataFromWindow();
if (mClip->GetValue() == false) {
if (ratio * peak > 1.0)
ratio = 1.0 / peak;
if (mNoClip && mRatio * mPeak > 1.0)
{
mRatio = 1.0 / mPeak;
}
return true;
}
// handler implementations for AmplifyDialog
void AmplifyDialog::CheckClip()
// EffectAmplify implementation
void EffectAmplify::CheckClip()
{
wxButton *ok = (wxButton *) FindWindow(wxID_OK);
double peak = mRatio * mPeak;
EnableApply(mClip->GetValue() || (peak > 0.0 && peak <= 1.0));
}
if (!mClip->GetValue() == true) {
ok->Enable(ratio * peak <= 1.0);
void EffectAmplify::OnAmpText(wxCommandEvent & WXUNUSED(evt))
{
if (!mAmpT->GetValidator()->TransferFromWindow())
{
EnableApply(false);
return;
}
else {
ok->Enable(true);
mRatio = pow(10.0, TrapDouble(mAmp, MIN_Amp, MAX_Amp) / 20.0);
mAmpS->SetValue((int) (mAmp * SCL_Amp + 0.5));
mNewPeak = 20.0 * log10(mRatio * mPeak);
mNewPeakT->GetValidator()->TransferToWindow();
CheckClip();
}
void EffectAmplify::OnPeakText(wxCommandEvent & WXUNUSED(evt))
{
if (!mNewPeakT->GetValidator()->TransferFromWindow())
{
EnableApply(false);
return;
}
}
void AmplifyDialog::OnAmpText(wxCommandEvent & WXUNUSED(event))
{
wxString val = mAmpT->GetValue();
double r;
double r = pow(10.0, mNewPeak / 20.0) / mPeak;
val.ToDouble(&r);
ratio = pow(10.0,TrapDouble(r*10, AMP_MIN, AMP_MAX)/200.0);
mAmp = TrapDouble(20.0 * log10(r), MIN_Amp, MAX_Amp);
mRatio = pow(10.0, mAmp / 20.0);
mAmpS->SetValue((int)(200*log10(ratio)+0.5));
mAmpT->GetValidator()->TransferToWindow();
if( ratio*peak > 0.0 )
val.Printf(wxT("%.1f"), 20*log10(ratio*peak));
else
val = _("-Infinity"); // the case when the waveform is all zero
mPeakT->ChangeValue(val);
mAmpS->SetValue((int) (mAmp * SCL_Amp + 0.5));
CheckClip();
}
void AmplifyDialog::OnPeakText(wxCommandEvent & WXUNUSED(event))
void EffectAmplify::OnAmpSlider(wxCommandEvent & evt)
{
wxString val = mPeakT->GetValue();
double r;
double dB = evt.GetInt() / SCL_Amp;
mRatio = pow(10.0, TrapDouble(dB, MIN_Amp, MAX_Amp) / 20.0);
val.ToDouble(&r);
ratio = pow(10.0, r/20.0) / peak;
double dB2 = (evt.GetInt() - 1) / SCL_Amp;
double ratio2 = pow(10.0, TrapDouble(dB2, MIN_Amp, MAX_Amp) / 20.0);
double dB = TrapDouble(200*log10(ratio), AMP_MIN, AMP_MAX)/10.0;
ratio = pow(10.0, dB/20.0);
if (!mClip->GetValue() && mRatio * mPeak > 1.0 && ratio2 * mPeak < 1.0)
{
mRatio = 1.0 / mPeak;
}
mAmpS->SetValue((int)(10*dB+0.5));
mAmp = 20.0 * log10(mRatio);
mAmpT->GetValidator()->TransferToWindow();
val.Printf(wxT("%.1f"), dB);
mAmpT->ChangeValue(val);
mNewPeak = 20.0 * log10(mRatio * mPeak);
mNewPeakT->GetValidator()->TransferToWindow();
CheckClip();
}
void AmplifyDialog::OnAmpSlider(wxCommandEvent & WXUNUSED(event))
{
wxString str;
double dB = mAmpS->GetValue() / 10.0;
ratio = pow(10.0,TrapDouble(dB, AMP_MIN, AMP_MAX)/20.0);
double dB2 = (mAmpS->GetValue()-1) / 10.0;
double ratio2 = pow(10.0,TrapDouble(dB2, AMP_MIN, AMP_MAX)/20.0);
if (!mClip->GetValue() && ratio * peak > 1.0 && ratio2 * peak < 1.0)
ratio = 1.0 / peak;
str.Printf(wxT("%.1f"), 20*log10(ratio));
mAmpT->ChangeValue(str);
if (ratio*peak > 0.0)
str.Printf(wxT("%.1f"), 20*log10(ratio*peak));
else
str = _("-Infinity"); // the case when the waveform is all zero
mPeakT->ChangeValue(str);
CheckClip();
}
void AmplifyDialog::OnClipCheckBox(wxCommandEvent & WXUNUSED(event))
void EffectAmplify::OnClipCheckBox(wxCommandEvent & WXUNUSED(evt))
{
CheckClip();
}
void AmplifyDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
{
TransferDataFromWindow();
// Save & restore parameters around Preview, because we didn't do OK.
float oldRatio = mEffect->ratio;
float oldPeak = mEffect->peak;
mEffect->ratio = ratio;
if (noclip && ratio*peak > 1.0)
mEffect->ratio = 1.0 / peak;
mEffect->peak = peak;
mEffect->Preview();
mEffect->ratio = oldRatio;
mEffect->peak = oldPeak;
}

View File

@ -15,98 +15,71 @@
#ifndef __AUDACITY_EFFECT_AMPLIFY__
#define __AUDACITY_EFFECT_AMPLIFY__
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/dialog.h>
#include <wx/intl.h>
#include <wx/event.h>
#include <wx/slider.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include "SimpleMono.h"
#include "../ShuttleGui.h"
class WaveTrack;
#include "Effect.h"
class EffectAmplify:public EffectSimpleMono
#define AMPLIFY_PLUGIN_SYMBOL wxTRANSLATE("Amplify")
class EffectAmplify : public Effect
{
friend class AmplifyDialog;
public:
public:
EffectAmplify();
virtual ~EffectAmplify();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Amplify..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#AmplifierPlugin"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Amplify"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Amplifying"));
}
virtual EffectType GetType();
// Useful only after PromptUser values have been set.
virtual wxString GetEffectDescription();
// EffectClientInterface implementation
virtual int GetAudioInCount();
virtual int GetAudioOutCount();
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen);
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
// Effect implementation
virtual bool Init();
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
protected:
virtual bool ProcessSimpleMono(float *buffer, sampleCount len);
private:
float ratio;
float peak;
};
//----------------------------------------------------------------------------
// AmplifyDialog
//----------------------------------------------------------------------------
class AmplifyDialog:public EffectDialog
{
public:
// constructors and destructors
AmplifyDialog(EffectAmplify *effect, wxWindow * parent);
// method declarations
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
bool Validate();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
private:
// handlers
void OnAmpText(wxCommandEvent & event);
void OnPeakText(wxCommandEvent & event);
void OnAmpSlider(wxCommandEvent & event);
void OnClipCheckBox(wxCommandEvent & event);
void OnPreview( wxCommandEvent &event );
// EffectAmplify implementation
void OnAmpText(wxCommandEvent & evt);
void OnPeakText(wxCommandEvent & evt);
void OnAmpSlider(wxCommandEvent & evt);
void OnClipCheckBox(wxCommandEvent & evt);
void CheckClip();
private:
private:
float mPeak;
float mRatio;
float mAmp;
float mNewPeak;
bool mNoClip;
wxSlider *mAmpS;
wxTextCtrl *mAmpT;
wxTextCtrl *mPeakT;
wxTextCtrl *mNewPeakT;
wxCheckBox *mClip;
DECLARE_EVENT_TABLE();
public:
EffectAmplify *mEffect;
float ratio;
float peak;
bool noclip;
};
#endif // __AUDACITY_EFFECT_AMPLIFY__

View File

@ -13,41 +13,43 @@
*******************************************************************/
#include "../Audacity.h"
#include <math.h>
#include <wx/sizer.h>
#include <wx/dynarray.h>
#include <float.h>
#include <wx/dcclient.h>
#include <wx/dcmemory.h>
#include <wx/valtext.h>
#include <wx/dynarray.h>
#include <wx/intl.h>
#include <wx/msgdlg.h>
#include "../Audacity.h"
#include "../Prefs.h"
#include "../Internat.h"
#include "../Theme.h"
#include "../AllThemeResources.h"
#include "../AColor.h"
#include "../AllThemeResources.h"
#include "../Internat.h"
#include "../Prefs.h"
#include "../Theme.h"
#include "../widgets/valnum.h"
#include "AutoDuck.h"
#include <wx/arrimpl.cpp>
/*
* Default values for effect params
*/
#define PARAM_DEFAULT_DUCK_AMOUNT_DB -12.0
#define PARAM_DEFAULT_OUTER_FADE_DOWN_LEN 0.5
#define PARAM_DEFAULT_INNER_FADE_DOWN_LEN 0
#define PARAM_DEFAULT_OUTER_FADE_UP_LEN 0.5
#define PARAM_DEFAULT_INNER_FADE_UP_LEN 0
#define PARAM_DEFAULT_THRESHOLD_DB -30.0
#define PARAM_DEFAULT_MAXIMUM_PAUSE 1.0
// Define keys, defaults, minimums, and maximums for the effect parameters
//
// Name Type Key Def Min Max Scale
Param( DuckAmountDb, double, wxTRANSLATE("DuckAmountDb"), -12.0, -24.0, 0.0, 1 );
Param( InnerFadeDownLen, double, wxTRANSLATE("InnerFadeDownLen"), 0.0, 0.0, 3.0, 1 );
Param( InnerFadeUpLen, double, wxTRANSLATE("InnerFadeUpLen"), 0.0, 0.0, 3.0, 1 );
Param( OuterFadeDownLen, double, wxTRANSLATE("OuterFadeDownLen"), 0.5, 0.0, 3.0, 1 );
Param( OuterFadeUpLen, double, wxTRANSLATE("OuterFadeUpLen"), 0.5, 0.0, 3.0, 1 );
Param( ThresholdDb, double, wxTRANSLATE("ThresholdDb"), -30.0, -100.0, 0.0, 1 );
Param( MaximumPause, double, wxTRANSLATE("MaximumPause"), 1.0, 0.0, DBL_MAX, 1 );
/*
* Common constants
*/
#define BUF_SIZE 131072 // number of samples to process at once
#define RMS_WINDOW_SIZE 100 // samples in circular RMS window buffer
static const int kBufSize = 131072; // number of samples to process at once
static const int kRMSWindowSize = 100; // samples in circular RMS window buffer
/*
* A auto duck region and an array of auto duck regions
@ -65,6 +67,8 @@ struct AutoDuckRegion
double t1;
};
#include <wx/arrimpl.cpp>
WX_DECLARE_OBJARRAY(AutoDuckRegion, AutoDuckRegionArray);
WX_DEFINE_OBJARRAY(AutoDuckRegionArray);
@ -72,45 +76,121 @@ WX_DEFINE_OBJARRAY(AutoDuckRegionArray);
* Effect implementation
*/
BEGIN_EVENT_TABLE(EffectAutoDuck, wxEvtHandler)
EVT_TEXT(wxID_ANY, EffectAutoDuck::OnValueChanged)
END_EVENT_TABLE()
EffectAutoDuck::EffectAutoDuck()
{
SetEffectFlags(BUILTIN_EFFECT | PROCESS_EFFECT | ADVANCED_EFFECT);
gPrefs->Read(wxT("/Effects/AutoDuck/DuckAmountDb"),
&mDuckAmountDb, PARAM_DEFAULT_DUCK_AMOUNT_DB);
gPrefs->Read(wxT("/Effects/AutoDuck/InnerFadeDownLen"),
&mInnerFadeDownLen, PARAM_DEFAULT_INNER_FADE_DOWN_LEN);
gPrefs->Read(wxT("/Effects/AutoDuck/InnerFadeUpLen"),
&mInnerFadeUpLen, PARAM_DEFAULT_INNER_FADE_UP_LEN);
gPrefs->Read(wxT("/Effects/AutoDuck/OuterFadeDownLen"),
&mOuterFadeDownLen, PARAM_DEFAULT_OUTER_FADE_DOWN_LEN);
gPrefs->Read(wxT("/Effects/AutoDuck/OuterFadeUpLen"),
&mOuterFadeUpLen, PARAM_DEFAULT_OUTER_FADE_UP_LEN);
gPrefs->Read(wxT("/Effects/AutoDuck/ThresholdDb"),
&mThresholdDb, PARAM_DEFAULT_THRESHOLD_DB);
gPrefs->Read(wxT("/Effects/AutoDuck/MaximumPause"),
&mMaximumPause, PARAM_DEFAULT_MAXIMUM_PAUSE);
mDuckAmountDb = DEF_DuckAmountDb;
mInnerFadeDownLen = DEF_InnerFadeDownLen;
mInnerFadeUpLen = DEF_InnerFadeUpLen;
mOuterFadeDownLen = DEF_OuterFadeDownLen;
mOuterFadeUpLen = DEF_OuterFadeUpLen;
mThresholdDb = DEF_ThresholdDb;
mMaximumPause = DEF_MaximumPause;
mControlTrack = NULL;
mPanel = NULL;
}
EffectAutoDuck::~EffectAutoDuck()
{
}
// IdentInterface implementation
wxString EffectAutoDuck::GetSymbol()
{
return AUTODUCK_PLUGIN_SYMBOL;
}
wxString EffectAutoDuck::GetDescription()
{
return wxTRANSLATE("Reduces (ducks) the volume of one or more tracks whenever the volume of a specified \"control\" track reaches a particular level");
}
// EffectIdentInterface implementation
EffectType EffectAutoDuck::GetType()
{
return EffectTypeProcess;
}
// EffectClientInterface implementation
bool EffectAutoDuck::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.Write(KEY_DuckAmountDb, mDuckAmountDb);
parms.Write(KEY_InnerFadeDownLen, mInnerFadeDownLen);
parms.Write(KEY_InnerFadeUpLen, mInnerFadeUpLen);
parms.Write(KEY_OuterFadeDownLen, mOuterFadeDownLen);
parms.Write(KEY_OuterFadeUpLen, mOuterFadeUpLen);
parms.Write(KEY_ThresholdDb, mThresholdDb);
parms.Write(KEY_MaximumPause, mMaximumPause);
return true;
}
bool EffectAutoDuck::SetAutomationParameters(EffectAutomationParameters & parms)
{
ReadAndVerifyDouble(DuckAmountDb);
ReadAndVerifyDouble(InnerFadeDownLen);
ReadAndVerifyDouble(InnerFadeUpLen);
ReadAndVerifyDouble(OuterFadeDownLen);
ReadAndVerifyDouble(OuterFadeUpLen);
ReadAndVerifyDouble(ThresholdDb);
ReadAndVerifyDouble(MaximumPause);
mDuckAmountDb = DuckAmountDb;
mInnerFadeDownLen = InnerFadeDownLen;
mInnerFadeUpLen = InnerFadeUpLen;
mOuterFadeDownLen = OuterFadeDownLen;
mOuterFadeUpLen = OuterFadeUpLen;
mThresholdDb = ThresholdDb;
mMaximumPause = MaximumPause;
return true;
}
// Effect implementation
bool EffectAutoDuck::Startup()
{
wxString base = wxT("/Effects/AutoDuck/");
// Migrate settings from 2.1.0 or before
// Already migrated, so bail
if (gPrefs->Exists(base + wxT("Migrated")))
{
return true;
}
// Load the old "current" settings
if (gPrefs->Exists(base))
{
gPrefs->Read(base + wxT("DuckAmountDb"), &mDuckAmountDb, DEF_DuckAmountDb);
gPrefs->Read(base + wxT("InnerFadeDownLen"), &mInnerFadeDownLen, DEF_InnerFadeDownLen);
gPrefs->Read(base + wxT("InnerFadeUpLen"), &mInnerFadeUpLen, DEF_InnerFadeUpLen);
gPrefs->Read(base + wxT("OuterFadeDownLen"), &mOuterFadeDownLen, DEF_OuterFadeDownLen);
gPrefs->Read(base + wxT("OuterFadeUpLen"), &mOuterFadeUpLen, DEF_OuterFadeUpLen);
gPrefs->Read(base + wxT("ThresholdDb"), &mThresholdDb, DEF_ThresholdDb);
gPrefs->Read(base + wxT("MaximumPause"), &mMaximumPause, DEF_MaximumPause);
SaveUserPreset(GetCurrentSettingsGroup());
// Do not migrate again
gPrefs->Write(base + wxT("Migrated"), true);
gPrefs->Flush();
}
return true;
}
bool EffectAutoDuck::Init()
{
gPrefs->Read(wxT("/Effects/AutoDuck/DuckAmountDb"),
&mDuckAmountDb, PARAM_DEFAULT_DUCK_AMOUNT_DB);
gPrefs->Read(wxT("/Effects/AutoDuck/InnerFadeDownLen"),
&mInnerFadeDownLen, PARAM_DEFAULT_INNER_FADE_DOWN_LEN);
gPrefs->Read(wxT("/Effects/AutoDuck/InnerFadeUpLen"),
&mInnerFadeUpLen, PARAM_DEFAULT_INNER_FADE_UP_LEN);
gPrefs->Read(wxT("/Effects/AutoDuck/OuterFadeDownLen"),
&mOuterFadeDownLen, PARAM_DEFAULT_OUTER_FADE_DOWN_LEN);
gPrefs->Read(wxT("/Effects/AutoDuck/OuterFadeUpLen"),
&mOuterFadeUpLen, PARAM_DEFAULT_OUTER_FADE_UP_LEN);
gPrefs->Read(wxT("/Effects/AutoDuck/ThresholdDb"),
&mThresholdDb, PARAM_DEFAULT_THRESHOLD_DB);
gPrefs->Read(wxT("/Effects/AutoDuck/MaximumPause"),
&mMaximumPause, PARAM_DEFAULT_MAXIMUM_PAUSE);
mControlTrack = NULL;
TrackListIterator iter(mTracks);
@ -142,7 +222,7 @@ bool EffectAutoDuck::Init()
/* i18n-hint: Auto duck is the name of an effect that 'ducks' (reduces the volume)
* of the audio automatically when there is sound on another track. Not as
* in 'Donald-Duck'!*/
_("Auto Duck"), wxICON_ERROR, mParent);
_("Auto Duck"), wxICON_ERROR, mUIParent);
return false;
}
}
@ -154,7 +234,7 @@ bool EffectAutoDuck::Init()
{
wxMessageBox(
_("Auto Duck needs a control track which must be placed below the selected track(s)."),
_("Auto Duck"), wxICON_ERROR, mParent);
_("Auto Duck"), wxICON_ERROR, mUIParent);
return false;
}
@ -163,55 +243,11 @@ bool EffectAutoDuck::Init()
return true;
}
bool EffectAutoDuck::TransferParameters( Shuttle & shuttle )
{
shuttle.TransferDouble(wxT("DuckAmountDb"), mDuckAmountDb,
PARAM_DEFAULT_DUCK_AMOUNT_DB);
shuttle.TransferDouble(wxT("InnerFadeDownLen"), mInnerFadeDownLen,
PARAM_DEFAULT_INNER_FADE_DOWN_LEN);
shuttle.TransferDouble(wxT("InnerFadeUpLen"), mInnerFadeUpLen,
PARAM_DEFAULT_INNER_FADE_UP_LEN);
shuttle.TransferDouble(wxT("OuterFadeDownLen"), mOuterFadeDownLen,
PARAM_DEFAULT_OUTER_FADE_DOWN_LEN);
shuttle.TransferDouble(wxT("OuterFadeUpLen"), mOuterFadeUpLen,
PARAM_DEFAULT_OUTER_FADE_UP_LEN);
shuttle.TransferDouble(wxT("ThresholdDb"), mThresholdDb,
PARAM_DEFAULT_THRESHOLD_DB);
shuttle.TransferDouble(wxT("MaximumPause"), mMaximumPause,
PARAM_DEFAULT_MAXIMUM_PAUSE);
return true;
}
bool EffectAutoDuck::CheckWhetherSkipEffect()
{
return false;
}
void EffectAutoDuck::End()
{
mControlTrack = NULL;
}
bool EffectAutoDuck::PromptUser()
{
EffectAutoDuckDialog dlog(this, mParent);
if (dlog.ShowModal() != wxID_OK)
return false; // user cancelled dialog
gPrefs->Write(wxT("/Effects/AutoDuck/DuckAmountDb"), mDuckAmountDb);
gPrefs->Write(wxT("/Effects/AutoDuck/OuterFadeDownLen"), mOuterFadeDownLen);
gPrefs->Write(wxT("/Effects/AutoDuck/OuterFadeUpLen"), mOuterFadeUpLen);
gPrefs->Write(wxT("/Effects/AutoDuck/InnerFadeDownLen"), mInnerFadeDownLen);
gPrefs->Write(wxT("/Effects/AutoDuck/InnerFadeUpLen"), mInnerFadeUpLen);
gPrefs->Write(wxT("/Effects/AutoDuck/ThresholdDb"), mThresholdDb);
gPrefs->Write(wxT("/Effects/AutoDuck/MaximumPause"), mMaximumPause);
gPrefs->Flush();
return true;
}
bool EffectAutoDuck::Process()
{
sampleCount i;
@ -243,15 +279,15 @@ bool EffectAutoDuck::Process()
double threshold = pow(10.0, mThresholdDb/20);
// adjust the threshold so we can compare it to the rmsSum value
threshold = threshold * threshold * RMS_WINDOW_SIZE;
threshold = threshold * threshold * kRMSWindowSize;
int rmsPos = 0;
float rmsSum = 0;
float *rmsWindow = new float[RMS_WINDOW_SIZE];
for (i = 0; i < RMS_WINDOW_SIZE; i++)
float *rmsWindow = new float[kRMSWindowSize];
for (i = 0; i < kRMSWindowSize; i++)
rmsWindow[i] = 0;
float *buf = new float[BUF_SIZE];
float *buf = new float[kBufSize];
bool inDuckRegion = false;
@ -267,8 +303,8 @@ bool EffectAutoDuck::Process()
while (pos < end)
{
sampleCount len = end - pos;
if (len > BUF_SIZE)
len = BUF_SIZE;
if (len > kBufSize)
len = kBufSize;
mControlTrack->Get((samplePtr)buf, floatSample, pos, (sampleCount)len);
@ -277,7 +313,7 @@ bool EffectAutoDuck::Process()
rmsSum -= rmsWindow[rmsPos];
rmsWindow[rmsPos] = buf[i - pos] * buf[i - pos];
rmsSum += rmsWindow[rmsPos];
rmsPos = (rmsPos + 1) % RMS_WINDOW_SIZE;
rmsPos = (rmsPos + 1) % kRMSWindowSize;
bool thresholdExceeded = rmsSum > threshold;
@ -343,7 +379,7 @@ bool EffectAutoDuck::Process()
if (!cancel)
{
this->CopyInputTracks(); // Set up mOutputTracks.
CopyInputTracks(); // Set up mOutputTracks.
SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks);
Track *iterTrack = iter.First();
@ -373,10 +409,100 @@ bool EffectAutoDuck::Process()
}
}
this->ReplaceProcessedTracks(!cancel);
ReplaceProcessedTracks(!cancel);
return !cancel;
}
void EffectAutoDuck::PopulateOrExchange(ShuttleGui & S)
{
S.SetBorder(5);
S.StartVerticalLay(true);
{
S.AddSpace(0, 5);
mPanel = new EffectAutoDuckPanel(S.GetParent(), this);
S.AddWindow(mPanel);
S.AddSpace(0, 5);
S.StartMultiColumn(6, wxCENTER);
{
FloatingPointValidator<double> vldDuckAmountDb(1, &mDuckAmountDb, NUM_VAL_NO_TRAILING_ZEROES);
vldDuckAmountDb.SetRange(MIN_DuckAmountDb, MAX_DuckAmountDb);
mDuckAmountDbBox = S.AddTextBox(_("Duck amount:"), wxT(""), 10);
mDuckAmountDbBox->SetValidator(vldDuckAmountDb);
S.AddUnits(_("dB"));
FloatingPointValidator<double> vldMaximumPause(2, &mMaximumPause, NUM_VAL_NO_TRAILING_ZEROES);
vldMaximumPause.SetRange(MIN_MaximumPause, MAX_MaximumPause);
mMaximumPauseBox = S.AddTextBox(_("Maximum pause:"), wxT(""), 10);
mMaximumPauseBox->SetValidator(vldMaximumPause);
S.AddUnits(_("seconds"));
FloatingPointValidator<double> vldOuterFadeDownLen(2, &mOuterFadeDownLen, NUM_VAL_NO_TRAILING_ZEROES);
vldOuterFadeDownLen.SetRange(MIN_OuterFadeDownLen, MAX_OuterFadeDownLen);
mOuterFadeDownLenBox = S.AddTextBox(_("Outer fade down length:"), wxT(""), 10);
mOuterFadeDownLenBox->SetValidator(vldOuterFadeDownLen);
S.AddUnits(_("seconds"));
FloatingPointValidator<double> vldOuterFadeUpLen(2, &mOuterFadeUpLen, NUM_VAL_NO_TRAILING_ZEROES);
vldOuterFadeUpLen.SetRange(MIN_OuterFadeUpLen, MAX_OuterFadeUpLen);
mOuterFadeUpLenBox = S.AddTextBox(_("Outer fade up length:"), wxT(""), 10);
mOuterFadeUpLenBox->SetValidator(vldOuterFadeUpLen);
S.AddUnits(_("seconds"));
FloatingPointValidator<double> vldInnerFadeDownLen(2, &mInnerFadeDownLen, NUM_VAL_NO_TRAILING_ZEROES);
vldInnerFadeDownLen.SetRange(MIN_InnerFadeDownLen, MAX_InnerFadeDownLen);
mInnerFadeDownLenBox = S.AddTextBox(_("Inner fade down length:"), wxT(""), 10);
mInnerFadeDownLenBox->SetValidator(vldInnerFadeDownLen);
S.AddUnits(_("seconds"));
FloatingPointValidator<double> vldInnerFadeUpLen(2, &mInnerFadeUpLen, NUM_VAL_NO_TRAILING_ZEROES);
vldInnerFadeUpLen.SetRange(MIN_InnerFadeUpLen, MAX_InnerFadeUpLen);
mInnerFadeUpLenBox = S.AddTextBox(_("Inner fade up length:"), wxT(""), 10);
mInnerFadeUpLenBox->SetValidator(vldInnerFadeUpLen);
S.AddUnits(_("seconds"));
}
S.EndMultiColumn();
S.StartMultiColumn(3, wxCENTER);
{
FloatingPointValidator<double> vldThresholdDb(2, &mThresholdDb, NUM_VAL_NO_TRAILING_ZEROES);
vldThresholdDb.SetRange(MIN_ThresholdDb, MAX_ThresholdDb);
mThresholdDbBox = S.AddTextBox(_("Threshold:"), wxT(""), 10);
mThresholdDbBox->SetValidator(vldThresholdDb);
S.AddUnits(_("dB"));
}
S.EndMultiColumn();
}
S.EndVerticalLay();
return;
}
bool EffectAutoDuck::TransferDataToWindow()
{
if (!mUIParent->TransferDataToWindow())
{
return false;
}
return true;
}
bool EffectAutoDuck::TransferDataFromWindow()
{
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
return true;
}
// EffectAutoDuck implementation
// this currently does an exponential fade
bool EffectAutoDuck::ApplyDuckFade(int trackNumber, WaveTrack* t,
double t0, double t1)
@ -386,7 +512,7 @@ bool EffectAutoDuck::ApplyDuckFade(int trackNumber, WaveTrack* t,
sampleCount start = t->TimeToLongSamples(t0);
sampleCount end = t->TimeToLongSamples(t1);
float *buf = new float[BUF_SIZE];
float *buf = new float[kBufSize];
sampleCount pos = start;
int fadeDownSamples = t->TimeToLongSamples(
@ -405,8 +531,8 @@ bool EffectAutoDuck::ApplyDuckFade(int trackNumber, WaveTrack* t,
while (pos < end)
{
sampleCount len = end - pos;
if (len > BUF_SIZE)
len = BUF_SIZE;
if (len > kBufSize)
len = kBufSize;
t->Get((samplePtr)buf, floatSample, pos, len);
@ -444,171 +570,13 @@ bool EffectAutoDuck::ApplyDuckFade(int trackNumber, WaveTrack* t,
return cancel;
}
/*
* Effect dialog implementation
*/
#define ID_DUCK_AMOUNT_DB 10001
#define ID_THRESHOLD_DB 10002
#define ID_INNER_FADE_DOWN_LEN 10003
#define ID_INNER_FADE_UP_LEN 10004
#define ID_OUTER_FADE_DOWN_LEN 10005
#define ID_OUTER_FADE_UP_LEN 10006
#define ID_MAXIMUM_PAUSE 10007
#define ID_PANEL 10008
BEGIN_EVENT_TABLE(EffectAutoDuckDialog, wxDialog)
EVT_BUTTON(wxID_OK, EffectAutoDuckDialog::OnOk)
EVT_BUTTON(wxID_CANCEL, EffectAutoDuckDialog::OnCancel)
EVT_TEXT(ID_DUCK_AMOUNT_DB, EffectAutoDuckDialog::OnValueChanged)
EVT_TEXT(ID_THRESHOLD_DB, EffectAutoDuckDialog::OnValueChanged)
EVT_TEXT(ID_INNER_FADE_DOWN_LEN, EffectAutoDuckDialog::OnValueChanged)
EVT_TEXT(ID_INNER_FADE_UP_LEN, EffectAutoDuckDialog::OnValueChanged)
EVT_TEXT(ID_OUTER_FADE_DOWN_LEN, EffectAutoDuckDialog::OnValueChanged)
EVT_TEXT(ID_OUTER_FADE_UP_LEN, EffectAutoDuckDialog::OnValueChanged)
EVT_TEXT(ID_MAXIMUM_PAUSE, EffectAutoDuckDialog::OnValueChanged)
END_EVENT_TABLE()
EffectAutoDuckDialog::EffectAutoDuckDialog(EffectAutoDuck* effect,
wxWindow *parent) : wxDialog(parent, -1, _("Auto Duck"),
wxDefaultPosition, wxDefaultSize)
{
mEffect = effect;
wxTextValidator vld(wxFILTER_NUMERIC);
ShuttleGui S(this, eIsCreating);
S.SetBorder(5);
S.StartVerticalLay(true);
{
S.AddSpace(0, 5);
mPanel = (EffectAutoDuckPanel*)
S.AddWindow(new EffectAutoDuckPanel(this, ID_PANEL));
S.AddSpace(0, 5);
S.StartMultiColumn(6, wxCENTER);
{
mDuckAmountDbBox = S.Id(ID_DUCK_AMOUNT_DB).AddTextBox(
_("Duck amount:"),
Internat::ToDisplayString(mEffect->mDuckAmountDb), 10);
S.AddUnits(_("dB"));
mDuckAmountDbBox->SetValidator(vld);
mMaximumPauseBox = S.Id(ID_MAXIMUM_PAUSE).AddTextBox(
_("Maximum pause:"),
Internat::ToDisplayString(mEffect->mMaximumPause), 10);
S.AddUnits(_("seconds"));
mMaximumPauseBox->SetValidator(vld);
mOuterFadeDownLenBox = S.Id(ID_OUTER_FADE_DOWN_LEN).AddTextBox(
_("Outer fade down length:"),
Internat::ToDisplayString(mEffect->mOuterFadeDownLen), 10);
S.AddUnits(_("seconds"));
mOuterFadeDownLenBox->SetValidator(vld);
mOuterFadeUpLenBox = S.Id(ID_OUTER_FADE_UP_LEN).AddTextBox(
_("Outer fade up length:"),
Internat::ToDisplayString(mEffect->mOuterFadeUpLen), 10);
S.AddUnits(_("seconds"));
mOuterFadeUpLenBox->SetValidator(vld);
mInnerFadeDownLenBox = S.Id(ID_INNER_FADE_DOWN_LEN).AddTextBox(
_("Inner fade down length:"),
Internat::ToDisplayString(mEffect->mInnerFadeDownLen), 10);
S.AddUnits(_("seconds"));
mInnerFadeDownLenBox->SetValidator(vld);
mInnerFadeUpLenBox = S.Id(ID_INNER_FADE_UP_LEN).AddTextBox(
_("Inner fade up length:"),
Internat::ToDisplayString(mEffect->mInnerFadeUpLen), 10);
S.AddUnits(_("seconds"));
mInnerFadeUpLenBox->SetValidator(vld);
}
S.EndMultiColumn();
S.StartMultiColumn(3, wxCENTER);
{
mThresholdDbBox = S.Id(ID_THRESHOLD_DB).AddTextBox(
_("Threshold:"),
Internat::ToDisplayString(mEffect->mThresholdDb), 10);
S.AddUnits(_("dB"));
mThresholdDbBox->SetValidator(vld);
}
S.EndMultiColumn();
}
S.EndVerticalLay();
S.AddStandardButtons();
Layout();
Fit();
SetMinSize(GetSize());
Center();
}
void EffectAutoDuckDialog::OnOk(wxCommandEvent& WXUNUSED(event))
{
double duckAmountDb = 0, thresholdDb = 0;
double innerFadeDownLen = 0, innerFadeUpLen = 0;
double outerFadeDownLen = 0, outerFadeUpLen = 0;
double maximumPause = 0;
bool success =
mDuckAmountDbBox->GetValue().ToDouble(&duckAmountDb) &&
duckAmountDb > -100 &&
duckAmountDb < 0 &&
mThresholdDbBox->GetValue().ToDouble(&thresholdDb) &&
thresholdDb > -100 &&
thresholdDb < 0 &&
mInnerFadeDownLenBox->GetValue().ToDouble(&innerFadeDownLen) &&
innerFadeDownLen >= 0 &&
innerFadeDownLen < 1000 &&
mInnerFadeUpLenBox->GetValue().ToDouble(&innerFadeUpLen) &&
innerFadeUpLen >= 0 &&
innerFadeUpLen < 1000 &&
mOuterFadeDownLenBox->GetValue().ToDouble(&outerFadeDownLen) &&
outerFadeDownLen >= 0 &&
outerFadeDownLen < 1000 &&
mOuterFadeUpLenBox->GetValue().ToDouble(&outerFadeUpLen) &&
outerFadeUpLen >= 0 &&
outerFadeUpLen < 1000 &&
mMaximumPauseBox->GetValue().ToDouble(&maximumPause) &&
maximumPause >= 0 &&
maximumPause < 1000;
if (!success)
{
wxMessageBox(_("Please enter valid values."), _("Auto Duck"),
wxICON_ERROR, this);
return;
}
mEffect->mDuckAmountDb = duckAmountDb;
mEffect->mThresholdDb = thresholdDb;
mEffect->mInnerFadeDownLen = innerFadeDownLen;
mEffect->mInnerFadeUpLen = innerFadeUpLen;
mEffect->mOuterFadeDownLen = outerFadeDownLen;
mEffect->mOuterFadeUpLen = outerFadeUpLen;
mEffect->mMaximumPause = maximumPause;
EndModal(wxID_OK);
}
void EffectAutoDuckDialog::OnCancel(wxCommandEvent& WXUNUSED(event))
{
EndModal(wxID_CANCEL);
}
void EffectAutoDuckDialog::OnValueChanged(wxCommandEvent& WXUNUSED(event))
void EffectAutoDuck::OnValueChanged(wxCommandEvent & WXUNUSED(evt))
{
mPanel->Refresh(false);
}
/*
* Effect dialog panel implementation
* EffectAutoDuckPanel implementation
*/
#define CONTROL_POINT_REGION 10 // pixel distance to click on a control point
@ -620,12 +588,6 @@ void EffectAutoDuckDialog::OnValueChanged(wxCommandEvent& WXUNUSED(event))
#define FADE_UP_START 450 // x coordinate
#define DUCK_AMOUNT_START 50 // y coordinate
#define MAX_DUCK_AMOUNT 0 // db
#define MIN_DUCK_AMOUNT -24 // db
#define MIN_FADE 0 // seconds
#define MAX_FADE 3 // seconds
#define FADE_SCALE 40 // scale factor for second -> pixel conversion
#define DUCK_AMOUNT_SCALE 8 // scale factor for db -> pixel conversion
@ -648,10 +610,11 @@ BEGIN_EVENT_TABLE(EffectAutoDuckPanel, wxPanel)
EVT_MOTION(EffectAutoDuckPanel::OnMotion)
END_EVENT_TABLE()
EffectAutoDuckPanel::EffectAutoDuckPanel(EffectAutoDuckDialog* parent,
wxWindowID id) : wxPanel(parent, id, wxDefaultPosition, wxSize(600, 300))
EffectAutoDuckPanel::EffectAutoDuckPanel(wxWindow *parent, EffectAutoDuck *effect)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(600, 300))
{
mParent = parent;
mEffect = effect;
mCurrentControlPoint = none;
mBackgroundBitmap = NULL;
@ -673,7 +636,7 @@ void EffectAutoDuckPanel::ResetControlPoints()
mControlPoints[duckAmount] = wxPoint(-100,-100);
}
void EffectAutoDuckPanel::OnPaint(wxPaintEvent& WXUNUSED(event))
void EffectAutoDuckPanel::OnPaint(wxPaintEvent & WXUNUSED(evt))
{
int clientWidth, clientHeight;
GetSize(&clientWidth, &clientHeight);
@ -703,17 +666,17 @@ void EffectAutoDuckPanel::OnPaint(wxPaintEvent& WXUNUSED(event))
double innerFadeUpLen = 0;
double outerFadeDownLen = 0;
double outerFadeUpLen = 0;
mParent->mDuckAmountDbBox->GetValue().ToDouble(&duckAmountDb);
mParent->mInnerFadeDownLenBox->GetValue().ToDouble(&innerFadeDownLen);
mParent->mInnerFadeUpLenBox->GetValue().ToDouble(&innerFadeUpLen);
mParent->mOuterFadeDownLenBox->GetValue().ToDouble(&outerFadeDownLen);
mParent->mOuterFadeUpLenBox->GetValue().ToDouble(&outerFadeUpLen);
mEffect->mDuckAmountDbBox->GetValue().ToDouble(&duckAmountDb);
mEffect->mInnerFadeDownLenBox->GetValue().ToDouble(&innerFadeDownLen);
mEffect->mInnerFadeUpLenBox->GetValue().ToDouble(&innerFadeUpLen);
mEffect->mOuterFadeDownLenBox->GetValue().ToDouble(&outerFadeDownLen);
mEffect->mOuterFadeUpLenBox->GetValue().ToDouble(&outerFadeUpLen);
if (innerFadeDownLen < MIN_FADE || innerFadeDownLen > MAX_FADE ||
innerFadeUpLen < MIN_FADE || innerFadeUpLen > MAX_FADE ||
outerFadeDownLen < MIN_FADE || outerFadeDownLen > MAX_FADE ||
outerFadeUpLen < MIN_FADE || outerFadeUpLen > MAX_FADE ||
duckAmountDb < MIN_DUCK_AMOUNT || duckAmountDb > MAX_DUCK_AMOUNT)
if (innerFadeDownLen < MIN_InnerFadeDownLen || innerFadeDownLen > MAX_InnerFadeDownLen ||
innerFadeUpLen < MIN_InnerFadeUpLen || innerFadeUpLen > MAX_InnerFadeUpLen ||
outerFadeDownLen < MIN_OuterFadeDownLen || outerFadeDownLen > MAX_OuterFadeDownLen ||
outerFadeUpLen < MIN_OuterFadeUpLen || outerFadeUpLen > MAX_OuterFadeUpLen ||
duckAmountDb < MIN_DuckAmountDb || duckAmountDb > MAX_DuckAmountDb)
{
// values are out of range, no preview available
wxString message = wxString::Format(_("Preview not available"));
@ -839,14 +802,14 @@ void EffectAutoDuckPanel::OnPaint(wxPaintEvent& WXUNUSED(event))
}
void EffectAutoDuckPanel::OnMouseCaptureChanged(
wxMouseCaptureChangedEvent& WXUNUSED(event))
wxMouseCaptureChangedEvent & WXUNUSED(evt))
{
SetCursor(wxNullCursor);
mCurrentControlPoint = none;
}
void EffectAutoDuckPanel::OnMouseCaptureLost(
wxMouseCaptureLostEvent& WXUNUSED(event))
wxMouseCaptureLostEvent & WXUNUSED(evt))
{
mCurrentControlPoint = none;
@ -857,7 +820,7 @@ void EffectAutoDuckPanel::OnMouseCaptureLost(
}
EffectAutoDuckPanel::EControlPoint
EffectAutoDuckPanel::GetNearestControlPoint(const wxPoint& pt)
EffectAutoDuckPanel::GetNearestControlPoint(const wxPoint & pt)
{
int dist[AUTO_DUCK_PANEL_NUM_CONTROL_POINTS];
int i;
@ -876,7 +839,7 @@ EffectAutoDuckPanel::EControlPoint
return none;
}
void EffectAutoDuckPanel::OnLeftDown(wxMouseEvent &evt)
void EffectAutoDuckPanel::OnLeftDown(wxMouseEvent & evt)
{
EControlPoint nearest = GetNearestControlPoint(evt.GetPosition());
@ -895,7 +858,7 @@ void EffectAutoDuckPanel::OnLeftDown(wxMouseEvent &evt)
}
}
void EffectAutoDuckPanel::OnLeftUp(wxMouseEvent& WXUNUSED(event))
void EffectAutoDuckPanel::OnLeftUp(wxMouseEvent & WXUNUSED(evt))
{
if (mCurrentControlPoint != none)
{
@ -904,7 +867,7 @@ void EffectAutoDuckPanel::OnLeftUp(wxMouseEvent& WXUNUSED(event))
}
}
void EffectAutoDuckPanel::OnMotion(wxMouseEvent &evt)
void EffectAutoDuckPanel::OnMotion(wxMouseEvent & evt)
{
switch (GetNearestControlPoint(evt.GetPosition()))
{
@ -945,54 +908,28 @@ void EffectAutoDuckPanel::OnMotion(wxMouseEvent &evt)
{
case outerFadeDown:
newValue = ((double)(FADE_DOWN_START - evt.GetX())) / FADE_SCALE;
if (newValue < MIN_FADE)
newValue = MIN_FADE;
if (newValue > MAX_FADE)
newValue = MAX_FADE;
mParent->mOuterFadeDownLenBox->SetValue(
Internat::ToDisplayString(newValue));
mEffect->mOuterFadeDownLen = TrapDouble(newValue, MIN_OuterFadeDownLen, MAX_OuterFadeDownLen);
break;
case outerFadeUp:
newValue = ((double)(evt.GetX() - FADE_UP_START)) / FADE_SCALE;
if (newValue < MIN_FADE)
newValue = MIN_FADE;
if (newValue > MAX_FADE)
newValue = MAX_FADE;
mParent->mOuterFadeUpLenBox->SetValue(
Internat::ToDisplayString(newValue));
mEffect->mOuterFadeUpLen = TrapDouble(newValue, MIN_OuterFadeUpLen, MAX_OuterFadeUpLen);
break;
case innerFadeDown:
newValue = ((double)(evt.GetX() - FADE_DOWN_START)) / FADE_SCALE;
if (newValue < MIN_FADE)
newValue = MIN_FADE;
if (newValue > MAX_FADE)
newValue = MAX_FADE;
mParent->mInnerFadeDownLenBox->SetValue(
Internat::ToDisplayString(newValue));
mEffect->mInnerFadeDownLen = TrapDouble(newValue, MIN_InnerFadeDownLen, MAX_InnerFadeDownLen);
break;
case innerFadeUp:
newValue = ((double)(FADE_UP_START - evt.GetX())) / FADE_SCALE;
if (newValue < MIN_FADE)
newValue = MIN_FADE;
if (newValue > MAX_FADE)
newValue = MAX_FADE;
mParent->mInnerFadeUpLenBox->SetValue(
Internat::ToDisplayString(newValue));
mEffect->mInnerFadeUpLen = TrapDouble(newValue, MIN_InnerFadeUpLen, MAX_InnerFadeUpLen);
break;
case duckAmount:
newValue = ((double)(DUCK_AMOUNT_START - evt.GetY())) /
DUCK_AMOUNT_SCALE;
if (newValue < MIN_DUCK_AMOUNT)
newValue = MIN_DUCK_AMOUNT;
if (newValue > MAX_DUCK_AMOUNT)
newValue = MAX_DUCK_AMOUNT;
mParent->mDuckAmountDbBox->SetValue(
Internat::ToDisplayString(newValue));
newValue = ((double)(DUCK_AMOUNT_START - evt.GetY())) / DUCK_AMOUNT_SCALE;
mEffect->mDuckAmountDb = TrapDouble(newValue, MIN_DuckAmountDb, MAX_DuckAmountDb);
break;
case none:
wxASSERT(false); // should not happen
}
mEffect->TransferDataToWindow();
Refresh(false);
}
}

View File

@ -11,47 +11,91 @@
#ifndef __AUDACITY_EFFECT_AUTODUCK__
#define __AUDACITY_EFFECT_AUTODUCK__
#include <wx/dialog.h>
#include <wx/bitmap.h>
#include <wx/event.h>
#include <wx/gdicmn.h>
#include <wx/panel.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include <wx/window.h>
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
#include "Effect.h"
class EffectAutoDuck;
class EffectAutoDuckPanel;
class EffectAutoDuckDialog: public wxDialog
{
public:
EffectAutoDuckDialog(EffectAutoDuck* effect, wxWindow* parent);
private:
friend class EffectAutoDuckPanel;
void OnOk(wxCommandEvent& evt);
void OnCancel(wxCommandEvent& evt);
void OnValueChanged(wxCommandEvent& evt);
EffectAutoDuck* mEffect;
wxTextCtrl* mDuckAmountDbBox;
wxTextCtrl* mInnerFadeDownLenBox;
wxTextCtrl* mInnerFadeUpLenBox;
wxTextCtrl* mOuterFadeDownLenBox;
wxTextCtrl* mOuterFadeUpLenBox;
wxTextCtrl* mThresholdDbBox;
wxTextCtrl* mMaximumPauseBox;
EffectAutoDuckPanel* mPanel;
DECLARE_EVENT_TABLE()
};
#define AUTO_DUCK_PANEL_NUM_CONTROL_POINTS 5
class EffectAutoDuckPanel: public wxPanel
#define AUTODUCK_PLUGIN_SYMBOL wxTRANSLATE("Auto Duck")
class EffectAutoDuck : public Effect
{
public:
EffectAutoDuckPanel(EffectAutoDuckDialog* parent, wxWindowID id);
EffectAutoDuck();
virtual ~EffectAutoDuck();
// IdentInterface implementation
virtual wxString GetSymbol();
virtual wxString GetDescription();
// EffectIdentInterface implementation
virtual EffectType GetType();
// EffectClientInterface implementation
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
// Effect implementation
virtual bool Startup();
virtual bool Init();
virtual void End();
virtual bool Process();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
private:
// EffectAutoDuck implementation
bool ApplyDuckFade(int trackNumber, WaveTrack *t, double t0, double t1);
void OnValueChanged(wxCommandEvent & evt);
private:
double mDuckAmountDb;
double mInnerFadeDownLen;
double mInnerFadeUpLen;
double mOuterFadeDownLen;
double mOuterFadeUpLen;
double mThresholdDb;
double mMaximumPause;
WaveTrack *mControlTrack;
wxTextCtrl *mDuckAmountDbBox;
wxTextCtrl *mInnerFadeDownLenBox;
wxTextCtrl *mInnerFadeUpLenBox;
wxTextCtrl *mOuterFadeDownLenBox;
wxTextCtrl *mOuterFadeUpLenBox;
wxTextCtrl *mThresholdDbBox;
wxTextCtrl *mMaximumPauseBox;
EffectAutoDuckPanel *mPanel;
DECLARE_EVENT_TABLE();
friend class EffectAutoDuckPanel;
};
class EffectAutoDuckPanel : public wxPanel
{
public:
EffectAutoDuckPanel(wxWindow *parent, EffectAutoDuck *effect);
virtual ~EffectAutoDuckPanel();
private:
@ -69,76 +113,27 @@ private:
virtual bool AcceptsFocus() const {return false;}
#endif
void OnPaint(wxPaintEvent& evt);
void OnMouseCaptureChanged(wxMouseCaptureChangedEvent &evt);
void OnMouseCaptureLost(wxMouseCaptureLostEvent &evt);
void OnLeftDown(wxMouseEvent &evt);
void OnLeftUp(wxMouseEvent &evt);
void OnMotion(wxMouseEvent &evt);
void OnPaint(wxPaintEvent & evt);
void OnMouseCaptureChanged(wxMouseCaptureChangedEvent & evt);
void OnMouseCaptureLost(wxMouseCaptureLostEvent & evt);
void OnLeftDown(wxMouseEvent & evt);
void OnLeftUp(wxMouseEvent & evt);
void OnMotion(wxMouseEvent & evt);
void ResetControlPoints();
EControlPoint GetNearestControlPoint(const wxPoint& pt);
EControlPoint GetNearestControlPoint(const wxPoint & pt);
EffectAutoDuckDialog* mParent;
wxBitmap* mBackgroundBitmap;
private:
wxWindow *mParent;
EffectAutoDuck *mEffect;
wxBitmap *mBackgroundBitmap;
EControlPoint mCurrentControlPoint;
wxPoint mControlPoints[AUTO_DUCK_PANEL_NUM_CONTROL_POINTS];
wxPoint mMoveStartControlPoints[AUTO_DUCK_PANEL_NUM_CONTROL_POINTS];
wxPoint mMouseDownPoint;
bool mControlPointMoveActivated;
DECLARE_EVENT_TABLE()
};
class EffectAutoDuck: public Effect
{
friend class EffectAutoDuckDialog;
public:
EffectAutoDuck();
virtual wxString GetEffectName()
{
return wxString(wxTRANSLATE("Auto Duck..."));
}
virtual std::set<wxString> GetEffectCategories()
{
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#DynamicsPlugin"));
return result;
}
virtual wxString GetEffectIdentifier()
{
return wxString(wxT("AutoDuck"));
}
virtual wxString GetEffectAction()
{
return wxString(_("Processing Auto Duck..."));
}
virtual bool PromptUser();
virtual bool TransferParameters(Shuttle & shuttle);
virtual bool Init();
virtual void End();
virtual bool CheckWhetherSkipEffect();
virtual bool Process();
private:
bool ApplyDuckFade(int trackNumber, WaveTrack* t, double t0, double t1);
double mDuckAmountDb;
double mInnerFadeDownLen;
double mInnerFadeUpLen;
double mOuterFadeDownLen;
double mOuterFadeUpLen;
double mThresholdDb;
double mMaximumPause;
WaveTrack* mControlTrack;
DECLARE_EVENT_TABLE();
};
#endif

View File

@ -10,113 +10,225 @@
******************************************************************//**
\class EffectBassTreble
\brief A TwoPassSimpleMono, high shelf and low shelf filters.
\brief A high shelf and low shelf filter.
The first pass applies the equalization and calculates the
peak value. The second pass, if enabled, normalizes to the
level set by the level control.
*//****************************************************************//**
\class BassTrebleDialog
\brief Dialog for EffectBassTreble
*//*******************************************************************/
#include "../Audacity.h"
#include <math.h>
#include "BassTreble.h"
#include "../WaveTrack.h"
#include "../Prefs.h"
#include <wx/button.h>
#include <wx/valtext.h>
#include <wx/checkbox.h>
#include <wx/slider.h>
#include <wx/intl.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/textctrl.h>
#include <wx/utils.h>
#include "../Prefs.h"
#include "../WaveTrack.h"
#include "../widgets/valnum.h"
#include "BassTreble.h"
enum
{
ID_Bass = 10000,
ID_Treble,
ID_Level,
ID_Normalize,
};
// Define keys, defaults, minimums, and maximums for the effect parameters
//
// Name Type Key Def Min Max Scale
Param( Bass, double, wxTRANSLATE("Bass"), 0.0, -15.0, 15.0, 1 );
Param( Treble, double, wxTRANSLATE("Treble"), 0.0, -15.0, 15.0, 1 );
Param( Level, double, wxTRANSLATE("Level"), -1.0, -30.0, 0.0, 1 );
Param( Normalize, bool, wxTRANSLATE("Normalize"), true, false, true, 1 );
// Sliders are integer, so range is x 10
// to allow 1 decimal place resolution
static const int kSliderScale = 10;
// Used to communicate the type of the filter.
static const int bassType = 0; //Low Shelf
static const int trebleType = 1; // High Shelf
enum kShelfType
{
kBass,
kTreble
};
BEGIN_EVENT_TABLE(EffectBassTreble, wxEvtHandler)
EVT_SLIDER(ID_Bass, EffectBassTreble::OnBassSlider)
EVT_SLIDER(ID_Treble, EffectBassTreble::OnTrebleSlider)
EVT_SLIDER(ID_Level, EffectBassTreble::OnLevelSlider)
EVT_TEXT(ID_Bass, EffectBassTreble::OnBassText)
EVT_TEXT(ID_Treble, EffectBassTreble::OnTrebleText)
EVT_TEXT(ID_Level, EffectBassTreble::OnLevelText)
EVT_CHECKBOX(ID_Normalize, EffectBassTreble::OnNormalize)
END_EVENT_TABLE()
EffectBassTreble::EffectBassTreble()
{
dB_bass = DEF_Bass;
dB_treble = DEF_Treble;
dB_level = DEF_Level;
mbNormalize = DEF_Normalize;
}
bool EffectBassTreble::Init()
EffectBassTreble::~EffectBassTreble()
{
// restore saved preferences
int readBool;
gPrefs->Read(wxT("/Effects/BassTreble/Bass"), &dB_bass, 0.0);
gPrefs->Read(wxT("/Effects/BassTreble/Treble"), &dB_treble, 0.0);
gPrefs->Read(wxT("/Effects/BassTreble/Level"), &dB_level, -1.0);
gPrefs->Read(wxT("/Effects/BassTreble/Normalize"), &readBool, 1 );
}
// Validate data
dB_level = (dB_level > 0)? 0 : dB_level;
mbNormalize = (readBool != 0);
// IdentInterface implementation
wxString EffectBassTreble::GetSymbol()
{
return BASSTREBLE_PLUGIN_SYMBOL;
}
wxString EffectBassTreble::GetDescription()
{
return wxTRANSLATE("Increases or decreases the lower frequencies and higher frequencies of your audio independently");
}
// EffectIdentInterface implementation
EffectType EffectBassTreble::GetType()
{
return EffectTypeProcess;
}
// EffectClientInterface implementation
int EffectBassTreble::GetAudioInCount()
{
return 1;
}
int EffectBassTreble::GetAudioOutCount()
{
return 1;
}
bool EffectBassTreble::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames WXUNUSED(chanMap))
{
if (GetPass() == 1)
{
const float slope = 0.4f; // same slope for both filters
const double hzBass = 250.0f;
const double hzTreble = 4000.0f;
//(re)initialise filter parameters
xn1Bass=xn2Bass=yn1Bass=yn2Bass=0;
xn1Treble=xn2Treble=yn1Treble=yn2Treble=0;
// Compute coefficents of the low shelf biquand IIR filter
Coefficents(hzBass, slope, dB_bass, kBass,
a0Bass, a1Bass, a2Bass,
b0Bass, b1Bass, b2Bass);
// Compute coefficents of the high shelf biquand IIR filter
Coefficents(hzTreble, slope, dB_treble, kTreble,
a0Treble, a1Treble, a2Treble,
b0Treble, b1Treble, b2Treble);
}
return true;
}
wxString EffectBassTreble::GetEffectDescription() {
// Note: This is useful only after values have been set.
wxString strResult =
wxString::Format(_("Applied effect: %s bass = %.1f dB, treble = %.1f dB"),
this->GetEffectName().c_str(),
dB_bass, dB_treble);
(mbNormalize) ?
strResult += wxString::Format(_(", level enabled at = %.1f dB"), dB_level) :
strResult += wxString::Format(_(", level disabled"));
sampleCount EffectBassTreble::ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen)
{
float *ibuf = inBlock[0];
float *obuf = outBlock[0];
return strResult;
if (GetPass() == 1)
{
for (sampleCount i = 0; i < blockLen; i++)
{
obuf[i] = DoFilter(ibuf[i]) / mPreGain;
}
}
else
{
float gain = (pow(10.0, dB_level / 20.0f)) / mMax;
for (sampleCount i = 0; i < blockLen; i++)
{
// Normalize to specified level
obuf[i] = ibuf[i] * (mPreGain * gain);
}
}
return blockLen;
}
bool EffectBassTreble::PromptUser()
bool EffectBassTreble::GetAutomationParameters(EffectAutomationParameters & parms)
{
BassTrebleDialog dlog(this, mParent);
dlog.mBass = dB_bass;
dlog.mTreble = dB_treble;
dlog.mLevel = dB_level;
dlog.mbNormalize = mbNormalize;
dlog.TransferDataToWindow();
dlog.CentreOnParent();
dlog.ShowModal();
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
dB_bass = dlog.mBass;
dB_treble = dlog.mTreble;
dB_level = dlog.mLevel;
mbNormalize = dlog.mbNormalize;
gPrefs->Write(wxT("/Effects/BassTreble/Bass"), dB_bass);
gPrefs->Write(wxT("/Effects/BassTreble/Treble"), dB_treble);
gPrefs->Write(wxT("/Effects/BassTreble/Level"), dB_level);
gPrefs->Write(wxT("/Effects/BassTreble/Normalize"), mbNormalize);
gPrefs->Flush();
parms.Write(KEY_Bass, dB_bass);
parms.Write(KEY_Treble, dB_treble);
parms.Write(KEY_Level, dB_level);
parms.Write(KEY_Normalize, mbNormalize);
return true;
}
bool EffectBassTreble::TransferParameters(Shuttle & shuttle)
bool EffectBassTreble::SetAutomationParameters(EffectAutomationParameters & parms)
{
shuttle.TransferDouble(wxT("Bass"),dB_bass,0.0);
shuttle.TransferDouble(wxT("Treble"),dB_treble,0.0);
shuttle.TransferDouble(wxT("Level"),dB_level,0.0);
shuttle.TransferBool( wxT("Normalize"), mbNormalize, true );
ReadAndVerifyDouble(Bass);
ReadAndVerifyDouble(Treble);
ReadAndVerifyDouble(Level);
ReadAndVerifyBool(Normalize);
dB_bass = Bass;
dB_treble = Treble;
dB_level = Level;
mbNormalize = Normalize;
return true;
}
// Effect implementation
bool EffectBassTreble::Startup()
{
wxString base = wxT("/Effects/BassTreble/");
// Migrate settings from 2.1.0 or before
// Already migrated, so bail
if (gPrefs->Exists(base + wxT("Migrated")))
{
return true;
}
// Load the old "current" settings
if (gPrefs->Exists(base))
{
int readBool;
gPrefs->Read(base + wxT("Bass"), &dB_bass, 0.0);
gPrefs->Read(base + wxT("Treble"), &dB_treble, 0.0);
gPrefs->Read(base + wxT("Level"), &dB_level, -1.0);
gPrefs->Read(base + wxT("Normalize"), &readBool, 1 );
// Validate data
dB_level = (dB_level > 0) ? 0 : dB_level;
mbNormalize = (readBool != 0);
SaveUserPreset(GetCurrentSettingsGroup());
// Do not migrate again
gPrefs->Write(base + wxT("Migrated"), true);
gPrefs->Flush();
}
return true;
}
bool EffectBassTreble::InitPass1()
{
mMax=0.0;
mMax = 0.0;
// Integer format tracks require headroom to avoid clipping
// when saved between passes (bug 619)
@ -124,57 +236,139 @@ bool EffectBassTreble::InitPass1()
if (mbNormalize) // don't need to calculate this if only doing one pass.
{
// Up to (gain + 6dB) headroom required for treble boost (experimental).
mPreGain = (dB_treble > 0)? (dB_treble + 6.0) : 0.0;
mPreGain = (dB_treble > 0) ? (dB_treble + 6.0) : 0.0;
if (dB_bass >= 0)
{
mPreGain = (mPreGain > dB_bass)? mPreGain : dB_bass;
} else {
// Up to 6 dB headroom reaquired for bass cut (experimental)
mPreGain = (mPreGain > 6.0)? mPreGain : 6.0;
mPreGain = (mPreGain > dB_bass) ? mPreGain : dB_bass;
}
mPreGain = (exp (log(10.0) * mPreGain / 20)); // to linear
} else {
else
{
// Up to 6 dB headroom reaquired for bass cut (experimental)
mPreGain = (mPreGain > 6.0) ? mPreGain : 6.0;
}
mPreGain = (exp(log(10.0) * mPreGain / 20)); // to linear
}
else
{
mPreGain = 1.0; // Unity gain
}
if (!mbNormalize)
DisableSecondPass();
return true;
}
bool EffectBassTreble::NewTrackPass1()
bool EffectBassTreble::InitPass2()
{
const float slope = 0.4f; // same slope for both filters
const double hzBass = 250.0f;
const double hzTreble = 4000.0f;
return mbNormalize && mMax != 0;
}
//(re)initialise filter parameters
xn1Bass=xn2Bass=yn1Bass=yn2Bass=0;
xn1Treble=xn2Treble=yn1Treble=yn2Treble=0;
void EffectBassTreble::PopulateOrExchange(ShuttleGui & S)
{
S.StartVerticalLay(0);
{
S.StartStatic(wxT(""));
{
S.StartMultiColumn(3, wxEXPAND);
S.SetStretchyCol(2);
{
#ifdef __WXGTK__
// BoxSizer is to make first mnemonic work, on Linux.
wxPanel* cPanel = new wxPanel(S.GetParent(), wxID_ANY);
wxBoxSizer* cSizer = new wxBoxSizer(wxVERTICAL);
cPanel->SetSizer(cSizer);
#endif
// Compute coefficents of the low shelf biquand IIR filter
Coefficents(hzBass, slope, dB_bass, bassType,
a0Bass, a1Bass, a2Bass,
b0Bass, b1Bass, b2Bass);
// Bass control
FloatingPointValidator<double> vldBass(1, &dB_bass);
vldBass.SetRange(MIN_Bass, MAX_Bass);
mBassT = S.Id(ID_Bass).AddTextBox(_("&Bass (dB):"), wxT(""), 10);
mBassT->SetName(_("Bass (dB):"));
mBassT->SetValidator(vldBass);
// Compute coefficents of the high shelf biquand IIR filter
Coefficents(hzTreble, slope, dB_treble, trebleType,
a0Treble, a1Treble, a2Treble,
b0Treble, b1Treble, b2Treble);
S.SetStyle(wxSL_HORIZONTAL);
mBassS = S.Id(ID_Bass).AddSlider(wxT(""), 0, MAX_Bass * kSliderScale, MIN_Bass * kSliderScale);
mBassS->SetName(_("Bass"));
mBassS->SetPageSize(30);
// Treble control
FloatingPointValidator<double> vldTreble(1, &dB_treble);
vldTreble.SetRange(MIN_Treble, MAX_Treble);
mTrebleT = S.Id(ID_Treble).AddTextBox(_("&Treble (dB):"), wxT(""), 10);
mTrebleT->SetValidator(vldTreble);
S.SetStyle(wxSL_HORIZONTAL);
mTrebleS = S.Id(ID_Treble).AddSlider(wxT(""), 0, MAX_Treble * kSliderScale, MIN_Treble * kSliderScale);
mTrebleS->SetName(_("Treble"));
mTrebleS->SetPageSize(30);
// Level control
FloatingPointValidator<double> vldLevel(1, &dB_level);
vldLevel.SetRange(MIN_Level, MAX_Level);
mLevelT = S.Id(ID_Level).AddTextBox(_("&Level (dB):"), wxT(""), 10);
mLevelT->SetValidator(vldLevel);
S.SetStyle(wxSL_HORIZONTAL);
mLevelS = S.Id(ID_Level).AddSlider(wxT(""), 0, MAX_Level * kSliderScale, MIN_Level * kSliderScale);
mLevelS->SetName(_("Level"));
mLevelS->SetPageSize(30);
}
S.EndMultiColumn();
}
S.EndStatic();
// Normalize checkbox
S.StartHorizontalLay(wxLEFT, true);
{
mNormalizeCheckBox = S.Id(ID_Normalize).AddCheckBox(_("&Enable level control"),
DEF_Normalize ? wxT("true") : wxT("false"));
mWarning = S.AddVariableText(wxT(""), false, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
}
S.EndHorizontalLay();
}
S.EndVerticalLay();
return;
}
bool EffectBassTreble::TransferDataToWindow()
{
if (!mUIParent->TransferDataToWindow())
{
return false;
}
mBassS->SetValue((int) dB_bass * kSliderScale + 0.5);
mTrebleS->SetValue((int) dB_treble * kSliderScale + 0.5);
mLevelS->SetValue((int) dB_level * kSliderScale + 0.5);
mNormalizeCheckBox->SetValue(mbNormalize);
UpdateUI();
return true;
}
bool EffectBassTreble::TransferDataFromWindow()
{
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
mbNormalize = mNormalizeCheckBox->GetValue();
return true;
}
// EffectBassTreble implementation
void EffectBassTreble::Coefficents(double hz, float slope, double gain, int type,
float& a0, float& a1, float& a2,
float& b0, float& b1, float& b2)
{
double w = 2 * M_PI * hz / mCurRate;
double w = 2 * M_PI * hz / mSampleRate;
double a = exp(log(10.0) * gain / 40);
double b = sqrt((a * a + 1) / slope - (pow((a - 1), 2)));
if (type == bassType)
if (type == kBass)
{
b0 = a * ((a + 1) - (a - 1) * cos(w) + b * sin(w));
b1 = 2 * a * ((a - 1) - (a + 1) * cos(w));
@ -183,7 +377,7 @@ void EffectBassTreble::Coefficents(double hz, float slope, double gain, int type
a1 = -2 * ((a - 1) + (a + 1) * cos(w));
a2 = (a + 1) + (a - 1) * cos(w) - b * sin(w);
}
else //assumed trebleType
else //assumed kTreble
{
b0 = a * ((a + 1) + (a - 1) * cos(w) + b * sin(w));
b1 = -2 * a * ((a - 1) + (a + 1) * cos(w));
@ -194,32 +388,6 @@ void EffectBassTreble::Coefficents(double hz, float slope, double gain, int type
}
}
bool EffectBassTreble::InitPass2()
{
return mbNormalize;
}
// Process the input
bool EffectBassTreble::ProcessPass1(float *buffer, sampleCount len)
{
for (sampleCount i = 0; i < len; i++)
buffer[i] = (DoFilter(buffer[i]) / mPreGain);
return true;
}
bool EffectBassTreble::ProcessPass2(float *buffer, sampleCount len)
{
if (mMax != 0)
{
float gain = (pow(10.0, dB_level/20.0f))/mMax;
for (int i = 0; i < len; i++)
// Normalize to specified level
buffer[i] *= (mPreGain * gain);
}
return true;
}
float EffectBassTreble::DoFilter(float in)
{
// Bass filter
@ -245,266 +413,84 @@ float EffectBassTreble::DoFilter(float in)
return out;
}
//----------------------------------------------------------------------------
// BassTrebleDialog
//----------------------------------------------------------------------------
// Declare window functions
#define ID_BASS_TEXT 10001
#define ID_BASS_SLIDER 10002
#define ID_TREBLE_TEXT 10003
#define ID_TREBLE_SLIDER 10004
#define ID_LEVEL_TEXT 10005
#define ID_LEVEL_SLIDER 10006
#define ID_NORMALIZE 10007
// Declare ranges
// Sliders are integer, so range is x 10
// to allow 1 decimal place resolution
#define BASS_MIN -150 // Corresponds to -15 db
#define BASS_MAX 150 // Corresponds to +15 dB
#define TREBLE_MIN -150 // Corresponds to -15 dB
#define TREBLE_MAX 150 // Corresponds to +15 dB
#define LEVEL_MIN -300 // Corresponds to -30 dN
#define LEVEL_MAX 0 // Corresponds to 0 dB
#define DB_MAX 100 // Maximum allowed dB boost
BEGIN_EVENT_TABLE(BassTrebleDialog, EffectDialog)
EVT_SLIDER(ID_BASS_SLIDER, BassTrebleDialog::OnBassSlider)
EVT_SLIDER(ID_TREBLE_SLIDER, BassTrebleDialog::OnTrebleSlider)
EVT_SLIDER(ID_LEVEL_SLIDER, BassTrebleDialog::OnLevelSlider)
EVT_TEXT(ID_BASS_TEXT, BassTrebleDialog::OnBassText)
EVT_TEXT(ID_TREBLE_TEXT, BassTrebleDialog::OnTrebleText)
EVT_TEXT(ID_LEVEL_TEXT, BassTrebleDialog::OnLevelText)
EVT_CHECKBOX(ID_NORMALIZE, BassTrebleDialog::OnNormalize)
EVT_BUTTON(ID_EFFECT_PREVIEW, BassTrebleDialog::OnPreview)
END_EVENT_TABLE()
BassTrebleDialog::BassTrebleDialog(EffectBassTreble *effect,
wxWindow * parent):
EffectDialog(parent, _("Bass and Treble"), PROCESS_EFFECT),
mEffect(effect)
{
Init();
}
void BassTrebleDialog::PopulateOrExchange(ShuttleGui & S)
{
S.StartStatic(wxT(""));
{
S.StartMultiColumn(3, wxEXPAND);
S.SetStretchyCol(2);
{
#ifdef __WXGTK__
// BoxSizer is to make first mnemonic work, on Linux.
wxPanel* cPanel = new wxPanel( this, wxID_ANY );
wxBoxSizer* cSizer = new wxBoxSizer(wxVERTICAL);
cPanel->SetSizer(cSizer);
#endif
wxTextValidator vld(wxFILTER_NUMERIC);
// Bass control
mBassT = S.Id(ID_BASS_TEXT).AddTextBox(_("&Bass (dB):"), wxT(""), 10);
mBassT->SetName(_("Bass (dB):"));
mBassT->SetValidator(vld);
S.SetStyle(wxSL_HORIZONTAL);
mBassS = S.Id(ID_BASS_SLIDER).AddSlider(wxT(""), 0, BASS_MAX, BASS_MIN);
mBassS->SetName(_("Bass"));
mBassS->SetRange(BASS_MIN, BASS_MAX);
mBassS->SetPageSize(30);
// Treble control
mTrebleT = S.Id(ID_TREBLE_TEXT).AddTextBox(_("&Treble (dB):"), wxT(""), 10);
mTrebleT->SetValidator(vld);
S.SetStyle(wxSL_HORIZONTAL);
mTrebleS = S.Id(ID_TREBLE_SLIDER).AddSlider(wxT(""), 0, TREBLE_MAX, TREBLE_MIN);
mTrebleS->SetName(_("Treble"));
mTrebleS->SetRange(TREBLE_MIN, TREBLE_MAX);
mTrebleS->SetPageSize(30);
// Level control
mLevelT = S.Id(ID_LEVEL_TEXT).AddTextBox(_("&Level (dB):"), wxT(""), 10);
mLevelT->SetValidator(vld);
S.SetStyle(wxSL_HORIZONTAL);
mLevelS = S.Id(ID_LEVEL_SLIDER).AddSlider(wxT(""), 0, LEVEL_MAX, LEVEL_MIN);
mLevelS->SetName(_("Level"));
mLevelS->SetRange(LEVEL_MIN, LEVEL_MAX);
mLevelS->SetPageSize(30);
}
S.EndMultiColumn();
}
S.EndStatic();
// Normalize checkbox
S.StartTwoColumn();
{
S.AddSpace(5,0);
mNormalizeCheckBox = S.Id(ID_NORMALIZE).AddCheckBox(_("&Enable level control"),
mbNormalize ? wxT("true") : wxT("false"));
S.AddSpace(5, 0);
mWarning = S.AddVariableText( wxT(""), false);
}
S.EndTwoColumn();
}
bool BassTrebleDialog::TransferDataToWindow()
{
mBassS->SetValue((double)mBass);
mTrebleS->SetValue((double)mTreble);
mLevelS->SetValue((double)mLevel);
mBassT->SetValue(wxString::Format(wxT("%.1f"), (float)mBass));
mTrebleT->SetValue(wxString::Format(wxT("%.1f"), (float)mTreble));
mLevelT->SetValue(wxString::Format(wxT("%.1f"), (float)mLevel));
mNormalizeCheckBox->SetValue(mbNormalize);
UpdateUI();
TransferDataFromWindow();
return true;
}
bool BassTrebleDialog::TransferDataFromWindow()
{
mBassT->GetValue().ToDouble(&mBass);
mTrebleT->GetValue().ToDouble(&mTreble);
mLevelT->GetValue().ToDouble(&mLevel);
mbNormalize = mNormalizeCheckBox->GetValue();
// Ensure that max values can never exceed design limits
// See bug 683.
mBass = wxMin(DB_MAX, mBass);
mTreble = wxMin(DB_MAX, mTreble);
mLevel = wxMin(0, mLevel);
return true;
}
void BassTrebleDialog::OnNormalize(wxCommandEvent& WXUNUSED(evt))
{
UpdateUI();
}
void BassTrebleDialog::UpdateUI()
void EffectBassTreble::UpdateUI()
{
double bass, treble, level;
mBassT->GetValue().ToDouble(&bass);
mTrebleT->GetValue().ToDouble(&treble);
mLevelT->GetValue().ToDouble(&level);
bool enable = mNormalizeCheckBox->GetValue();
bool okEnabled = true;
bool preveiwEnabled = true;
wxString warning = wxT("");
double v0, v1, v2;
wxString val0 = mBassT->GetValue();
val0.ToDouble(&v0);
wxString val1 = mTrebleT->GetValue();
val1.ToDouble(&v1);
wxString val2 = mLevelT->GetValue();
val2.ToDouble(&v2);
// Disallow level control if disabled
mLevelT->Enable(enable);
mLevelS->Enable(enable);
wxButton *ok = (wxButton *) FindWindow(wxID_OK);
wxButton *preview = (wxButton *) FindWindow(ID_EFFECT_PREVIEW);
if (v0==0 && v1==0 && !enable) {
// Disallow OK if nothing to do (but allow preview)
okEnabled = false;
warning = (_("Warning: No change to apply."));
if (bass == 0 && treble == 0 && !enable)
{
// Disallow Apply if nothing to do
EnableApply(false);
mWarning->SetLabel(_(" No change to apply."));
}
if (v0 > DB_MAX) {
okEnabled = false;
preveiwEnabled = false;
warning = (_("Error: Maximum Bass = 100 dB."));
else
{
if (level > 0 && enable)
{
// Disallow Apply if level enabled and > 0
EnableApply(false);
mWarning->SetLabel(_(": Maximum 0 dB."));
}
else
{
// Apply enabled
EnableApply(true);
mWarning->SetLabel(wxT(""));
}
}
if (v1 > DB_MAX) {
okEnabled = false;
preveiwEnabled = false;
warning = (_("Error: Maximum Treble = 100 dB."));
}
if ((v2 > 0) && enable) {
// Disallow OK and Preview if level enabled and > 0
okEnabled = false;
preveiwEnabled = false;
warning = (_("Error: Maximum Level = 0 dB."));
}
mWarning->SetLabel(warning);
ok->Enable(okEnabled);
preview->Enable(preveiwEnabled);
}
// handler implementations for BassTrebleDialog
void BassTrebleDialog::OnBassText(wxCommandEvent & WXUNUSED(event))
void EffectBassTreble::OnBassText(wxCommandEvent & WXUNUSED(evt))
{
double val;
mBassT->GetValue().ToDouble(&val);
int newval = floor(val / 0.1 + 0.5);
mBassS->SetValue(TrapDouble(newval, BASS_MIN, BASS_MAX));
mBassT->GetValidator()->TransferFromWindow();
mBassS->SetValue((int) floor(dB_bass * kSliderScale + 0.5));
UpdateUI();
}
void BassTrebleDialog::OnTrebleText(wxCommandEvent & WXUNUSED(event))
void EffectBassTreble::OnTrebleText(wxCommandEvent & WXUNUSED(evt))
{
double val;
mTrebleT->GetValue().ToDouble(&val);
int newval = floor(val / 0.1 + 0.5);
mTrebleS->SetValue(TrapDouble(newval, TREBLE_MIN, TREBLE_MAX));
mTrebleT->GetValidator()->TransferFromWindow();
mTrebleS->SetValue((int) floor(dB_treble * kSliderScale + 0.5));
UpdateUI();
}
void BassTrebleDialog::OnLevelText(wxCommandEvent & WXUNUSED(event))
void EffectBassTreble::OnLevelText(wxCommandEvent & WXUNUSED(evt))
{
double val;
mLevelT->GetValue().ToDouble(&val);
int newval = floor(val / 0.1 + 0.5);
mLevelS->SetValue(TrapDouble(newval, LEVEL_MIN, LEVEL_MAX));
mLevelT->GetValidator()->TransferFromWindow();
mLevelS->SetValue((int) floor(dB_level * kSliderScale + 0.5));
UpdateUI();
}
void BassTrebleDialog::OnBassSlider(wxCommandEvent & WXUNUSED(event))
void EffectBassTreble::OnBassSlider(wxCommandEvent & evt)
{
mBassT->SetValue(wxString::Format(wxT("%.1f"), mBassS->GetValue() * 0.1));
dB_bass = (double) evt.GetInt() / kSliderScale;
mBassT->GetValidator()->TransferToWindow();
UpdateUI();
}
void BassTrebleDialog::OnTrebleSlider(wxCommandEvent & WXUNUSED(event))
void EffectBassTreble::OnTrebleSlider(wxCommandEvent & evt)
{
mTrebleT->SetValue(wxString::Format(wxT("%.1f"), mTrebleS->GetValue() * 0.1));
dB_treble = (double) evt.GetInt() / kSliderScale;
mTrebleT->GetValidator()->TransferToWindow();
UpdateUI();
}
void BassTrebleDialog::OnLevelSlider(wxCommandEvent & WXUNUSED(event))
void EffectBassTreble::OnLevelSlider(wxCommandEvent & evt)
{
mLevelT->SetValue(wxString::Format(wxT("%.1f"), mLevelS->GetValue() * 0.1));
dB_level = (double) evt.GetInt() / kSliderScale;
mLevelT->GetValidator()->TransferToWindow();
UpdateUI();
}
void BassTrebleDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
void EffectBassTreble::OnNormalize(wxCommandEvent& WXUNUSED(evt))
{
TransferDataFromWindow();
// Save & restore parameters around Preview, because we didn't do OK.
double oldBass = mEffect->dB_bass;
double oldTreble = mEffect->dB_treble;
double oldLevel = mEffect->dB_level;
bool oldUseGain = mEffect->mbNormalize;
mEffect->dB_bass = mBass;
mEffect->dB_treble = mTreble;
mEffect->dB_level = mLevel;
mEffect->mbNormalize = mbNormalize;
mEffect->Preview();
mEffect->dB_bass = oldBass;
mEffect->dB_treble = oldTreble;
mEffect->dB_level = oldLevel;
mEffect->mbNormalize = oldUseGain;
UpdateUI();
}

View File

@ -12,56 +12,70 @@
#ifndef __AUDACITY_EFFECT_BASS_TREBLE__
#define __AUDACITY_EFFECT_BASS_TREBLE__
#include "TwoPassSimpleMono.h"
#include <wx/checkbox.h>
#include <wx/event.h>
#include <wx/slider.h>
#include <wx/stattext.h>
#include <wx/string.h>
#include <wx/textctrl.h>
class wxSizer;
class wxTextCtrl;
class WaveTrack;
#include "../ShuttleGui.h"
class EffectBassTreble: public EffectTwoPassSimpleMono {
#include "Effect.h"
#define BASSTREBLE_PLUGIN_SYMBOL wxTRANSLATE("Bass and Treble")
class EffectBassTreble : public Effect
{
public:
EffectBassTreble();
virtual ~EffectBassTreble() {};
virtual ~EffectBassTreble();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Bass and Treble..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#EQPlugin"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Bass and Treble"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Adjusting Bass and Treble"));
}
virtual EffectType GetType();
// Useful only after PromptUser values have been set.
virtual wxString GetEffectDescription();
// EffectClientInterface implementation
protected:
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual bool Init();
virtual int GetAudioInCount();
virtual int GetAudioOutCount();
virtual bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap = NULL);
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen);
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
virtual bool ProcessPass1(float *buffer, sampleCount len);
virtual bool ProcessPass2(float *buffer, sampleCount len);
// Effect Implementation
virtual bool Startup();
virtual bool InitPass1();
virtual bool InitPass2();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
private:
// EffectBassTreble implementation
void Coefficents(double hz, float slope, double gain, int type,
float& a0, float& a1, float& a2, float& b0, float& b1, float& b2);
float DoFilter(float in);
void UpdateUI();
void OnBassText(wxCommandEvent & evt);
void OnTrebleText(wxCommandEvent & evt);
void OnLevelText(wxCommandEvent & evt);
void OnBassSlider(wxCommandEvent & evt);
void OnTrebleSlider(wxCommandEvent & evt);
void OnLevelSlider(wxCommandEvent & evt);
void OnNormalize(wxCommandEvent & evt);
private:
virtual bool NewTrackPass1();
virtual bool InitPass1();
virtual bool InitPass2();
float DoFilter(float in);
float xn1Bass, xn2Bass, yn1Bass, yn2Bass,
wBass, swBass, cwBass, aBass, bBass,
a0Bass, a1Bass, a2Bass, b0Bass, b1Bass, b2Bass;
@ -75,36 +89,6 @@ private:
bool mbNormalize;
double mPreGain;
friend class BassTrebleDialog;
};
//----------------------------------------------------------------------------
// BassTrebleDialog
//----------------------------------------------------------------------------
class BassTrebleDialog:public EffectDialog {
public:
BassTrebleDialog(EffectBassTreble *effect, wxWindow * parent);
virtual ~BassTrebleDialog() {};
// method declarations for BassTrebleDialog
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
private:
// handler declarations for BassTrebleDialog
void OnBassText(wxCommandEvent & event);
void OnTrebleText(wxCommandEvent & event);
void OnLevelText(wxCommandEvent & event);
void OnBassSlider(wxCommandEvent & event);
void OnTrebleSlider(wxCommandEvent & event);
void OnLevelSlider(wxCommandEvent & event);
void OnNormalize(wxCommandEvent& evt);
void UpdateUI();
void OnPreview(wxCommandEvent & event);
void set_properties();
private:
wxSlider *mBassS;
wxSlider *mTrebleS;
wxSlider *mLevelS;
@ -112,17 +96,9 @@ private:
wxTextCtrl *mTrebleT;
wxTextCtrl *mLevelT;
wxCheckBox *mNormalizeCheckBox;
wxStaticText* mWarning;
wxStaticText *mWarning;
public:
EffectBassTreble *mEffect;
double mBass;
double mTreble;
double mLevel;
bool mbNormalize;
DECLARE_EVENT_TABLE()
DECLARE_EVENT_TABLE();
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -20,78 +20,55 @@ the pitch without changing the tempo.
#ifndef __AUDACITY_EFFECT_CHANGEPITCH__
#define __AUDACITY_EFFECT_CHANGEPITCH__
#include "SoundTouchEffect.h"
#include <wx/dialog.h>
#include <wx/intl.h>
#include <wx/choice.h>
#include <wx/event.h>
#include <wx/slider.h>
#include <wx/spinctrl.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include "../ShuttleGui.h"
#include "SoundTouchEffect.h"
#define CHANGEPITCH_PLUGIN_SYMBOL wxTRANSLATE("Change Pitch")
class EffectChangePitch : public EffectSoundTouch
{
public:
public:
EffectChangePitch();
virtual ~EffectChangePitch();
virtual wxString GetEffectName() { return wxString(wxTRANSLATE("Change Pitch...")); }
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#PitchPlugin"));
result.insert(wxT("http://audacityteam.org/namespace#PitchAndTempo"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Change Pitch"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Changing Pitch"));
}
virtual EffectType GetType();
// Useful only after PromptUser values have been set.
virtual wxString GetEffectDescription();
// EffectClientInterface implementation
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
// Effect implementation
virtual bool Init();
virtual bool Process();
virtual bool CheckWhetherSkipEffect();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
private:
// EffectChangePitch implementation
// Deduce m_FromFrequency from the samples at the beginning of
// the selection. Then set some other params accordingly.
virtual void DeduceFrequencies();
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual bool CheckWhetherSkipEffect() { return (m_dPercentChange == 0.0); }
virtual bool Process();
private:
double m_dSemitonesChange; // how many semitones to change pitch
double m_dStartFrequency; // starting frequency of first 0.2s of selection
double m_dPercentChange; // percent change to apply to frequency
friend class ChangePitchDialog;
};
//----------------------------------------------------------------------------
// ChangePitchDialog
//----------------------------------------------------------------------------
class wxChoice;
class wxRadioButton;
class wxString;
class wxTextCtrl;
class ChangePitchDialog : public EffectDialog
{
public:
ChangePitchDialog(EffectChangePitch * effect, wxWindow * parent,
double dSemitonesChange, double dStartFrequency);
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
private:
// calculations
void Calc_ToPitch(); // Update m_nToPitch from new m_dSemitonesChange.
void Calc_ToOctave();
@ -102,20 +79,18 @@ class ChangePitchDialog : public EffectDialog
void Calc_PercentChange(); // Update m_dPercentChange based on new m_dSemitonesChange.
// handlers
void OnChoice_FromPitch(wxCommandEvent & event);
void OnSpin_FromOctave(wxCommandEvent & event);
void OnChoice_ToPitch(wxCommandEvent & event);
void OnSpin_ToOctave(wxCommandEvent & event);
void OnChoice_FromPitch(wxCommandEvent & evt);
void OnSpin_FromOctave(wxCommandEvent & evt);
void OnChoice_ToPitch(wxCommandEvent & evt);
void OnSpin_ToOctave(wxCommandEvent & evt);
void OnText_SemitonesChange(wxCommandEvent & event);
void OnText_SemitonesChange(wxCommandEvent & evt);
void OnText_FromFrequency(wxCommandEvent & event);
void OnText_ToFrequency(wxCommandEvent & event);
void OnText_FromFrequency(wxCommandEvent & evt);
void OnText_ToFrequency(wxCommandEvent & evt);
void OnText_PercentChange(wxCommandEvent & event);
void OnSlider_PercentChange(wxCommandEvent & event);
void OnPreview( wxCommandEvent &event );
void OnText_PercentChange(wxCommandEvent & evt);
void OnSlider_PercentChange(wxCommandEvent & evt);
// helper fns for controls
void Update_Choice_FromPitch();
@ -131,8 +106,21 @@ class ChangePitchDialog : public EffectDialog
void Update_Text_PercentChange(); // Update control per current m_dPercentChange.
void Update_Slider_PercentChange(); // Update control per current m_dPercentChange.
private:
EffectChangePitch * mEffect;
private:
// effect parameters
int m_nFromPitch; // per PitchIndex()
int m_nFromOctave; // per PitchOctave()
int m_nToPitch; // per PitchIndex()
int m_nToOctave; // per PitchOctave()
double m_FromFrequency; // starting frequency of selection
double m_ToFrequency; // target frequency of selection
double m_dSemitonesChange; // how many semitones to change pitch
double m_dStartFrequency; // starting frequency of first 0.2s of selection
double m_dPercentChange; // percent change to apply to pitch
// Slider is (-100, 200], but textCtrls can set higher.
bool m_bLoopDetect; // Used to avoid loops in initialization and in event handling.
// controls
@ -147,26 +135,9 @@ class ChangePitchDialog : public EffectDialog
wxTextCtrl * m_pTextCtrl_PercentChange;
wxSlider * m_pSlider_PercentChange;
public:
// effect parameters
int m_nFromPitch; // per PitchIndex()
int m_nFromOctave; // per PitchOctave()
int m_nToPitch; // per PitchIndex()
int m_nToOctave; // per PitchOctave()
double m_dSemitonesChange; // how many semitones to change pitch
double m_FromFrequency; // starting frequency of selection
double m_ToFrequency; // target frequency of selection
double m_dPercentChange; // percent change to apply to pitch
// Slider is (-100, 200], but textCtrls can set higher.
private:
DECLARE_EVENT_TABLE()
DECLARE_EVENT_TABLE();
};
#endif // __AUDACITY_EFFECT_CHANGEPITCH__
#endif // USE_SOUNDTOUCH

View File

@ -11,64 +11,139 @@
\class EffectChangeSpeed
\brief An Effect that affects both pitch & speed.
*//****************************************************************//**
\class ChangeSpeedDialog
\brief Dialog used with EffectChangeSpeed
*//*******************************************************************/
#include "../Audacity.h"
#include <math.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/valtext.h>
#include <wx/intl.h>
#include "../Audacity.h"
#include "../LabelTrack.h"
#include "../Envelope.h"
#include "../LabelTrack.h"
#include "../Prefs.h"
#include "../Project.h"
#include "../Resample.h"
#include "../ShuttleGui.h"
#include "../widgets/valnum.h"
#include "ChangeSpeed.h"
#include "TimeWarper.h"
enum
{
ID_PercentChange = 10000,
ID_Multiplier,
ID_FromVinyl,
ID_ToVinyl,
ID_ToLength
};
// the standard vinyl rpm choices
// If the percent change is not one of these ratios, the choice control gets "n/a".
enum {
enum kVinyl
{
kVinyl_33AndAThird = 0,
kVinyl_45,
kVinyl_78,
kVinyl_NA
kVinyl_NA,
kNumVinyl
};
static const wxChar *kVinylStrings[kNumVinyl] =
{
wxT("33 1/3"),
wxT("45"),
wxT("78"),
/* i18n-hint: n/a is an English abbreviation meaning "not applicable". */
wxTRANSLATE("n/a"),
};
// Soundtouch is not reasonable below -99% or above 3000%.
// Define keys, defaults, minimums, and maximums for the effect parameters
//
// Name Type Key Def Min Max Scale
Param( Percentage, double, wxTRANSLATE("Percentage"), 0.0, -99.0, 4900.0, 1 );
// We warp the slider to go up to 400%, but user can enter higher values
static const double kSliderMax = 100.0; // warped above zero to actually go up to 400%
static const double kSliderWarp = 1.30105; // warp power takes max from 100 to 400.
//
// EffectChangeSpeed
//
BEGIN_EVENT_TABLE(EffectChangeSpeed, wxEvtHandler)
EVT_TEXT(ID_PercentChange, EffectChangeSpeed::OnText_PercentChange)
EVT_TEXT(ID_Multiplier, EffectChangeSpeed::OnText_Multiplier)
EVT_SLIDER(ID_PercentChange, EffectChangeSpeed::OnSlider_PercentChange)
EVT_CHOICE(ID_FromVinyl, EffectChangeSpeed::OnChoice_Vinyl)
EVT_CHOICE(ID_ToVinyl, EffectChangeSpeed::OnChoice_Vinyl)
EVT_TEXT(ID_ToLength, EffectChangeSpeed::OnTimeCtrl_ToLength)
EVT_COMMAND(ID_ToLength, EVT_TIMETEXTCTRL_UPDATED, EffectChangeSpeed::OnTimeCtrlUpdate)
END_EVENT_TABLE()
EffectChangeSpeed::EffectChangeSpeed()
{
// Retrieve last used control values
gPrefs->Read(wxT("/Effects/ChangeSpeed/PercentChange"), &m_PercentChange, 0);
// default format "4" is the same as the Selection toolbar: "hh:mm:ss + milliseconds";
gPrefs->Read(wxT("/Effects/ChangeSpeed/TimeFormat"), &mTimeCtrlFormat, 4);
// effect parameters
m_PercentChange = DEF_Percentage;
gPrefs->Read(wxT("/Effects/ChangeSpeed/VinylChoice"), &mFromVinyl, 0);
if (mFromVinyl == kVinyl_NA) {
mFromVinyl = kVinyl_33AndAThird;
}
mFromVinyl = kVinyl_33AndAThird;
mToVinyl = kVinyl_33AndAThird;
mFromLength = 0.0;
mToLength = 0.0;
mFormat = _("hh:mm:ss + milliseconds");
mbLoopDetect = false;
}
wxString EffectChangeSpeed::GetEffectDescription() {
// Note: This is useful only after change amount has been set.
return wxString::Format(_("Applied effect: %s %.3f%%"),
this->GetEffectName().c_str(),
m_PercentChange);
EffectChangeSpeed::~EffectChangeSpeed()
{
}
// IdentInterface implementation
wxString EffectChangeSpeed::GetSymbol()
{
return CHANGESPEED_PLUGIN_SYMBOL;
}
wxString EffectChangeSpeed::GetDescription()
{
return wxTRANSLATE("Change the speed of a track, also changing its pitch");
}
// EffectIdentInterface implementation
EffectType EffectChangeSpeed::GetType()
{
return EffectTypeProcess;
}
// EffectClientInterface implementation
bool EffectChangeSpeed::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.Write(KEY_Percentage, m_PercentChange);
return true;
}
bool EffectChangeSpeed::SetAutomationParameters(EffectAutomationParameters & parms)
{
ReadAndVerifyDouble(Percentage);
m_PercentChange = Percentage;
return true;
}
// Effect implementation
bool EffectChangeSpeed::CheckWhetherSkipEffect()
{
return (m_PercentChange == 0.0);
}
double EffectChangeSpeed::CalcPreviewInputLength(double previewLength)
@ -76,30 +151,43 @@ double EffectChangeSpeed::CalcPreviewInputLength(double previewLength)
return previewLength * (100.0 + m_PercentChange) / 100.0;
}
bool EffectChangeSpeed::PromptUser()
bool EffectChangeSpeed::Startup()
{
ChangeSpeedDialog dlog(this, mParent);
dlog.m_PercentChange = m_PercentChange;
dlog.mFromVinyl = mFromVinyl;
dlog.mFromLength = mFromLength;
dlog.mTimeCtrlFormat = mTimeCtrlFormat;
// Don't need to call TransferDataToWindow, although other
// Audacity dialogs (from which I derived this one) do it, because
// ShowModal calls stuff that eventually calls wxWindowBase::OnInitDialog,
// which calls dlog.TransferDataToWindow();
dlog.CentreOnParent();
dlog.ShowModal();
wxString base = wxT("/Effects/ChangeSpeed/");
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
// Migrate settings from 2.1.0 or before
m_PercentChange = dlog.m_PercentChange;
mFromVinyl = dlog.mFromVinyl;
mTimeCtrlFormat = dlog.mTimeCtrlFormat;
// Already migrated, so bail
if (gPrefs->Exists(base + wxT("Migrated")))
{
return true;
}
// Load the old "current" settings
if (gPrefs->Exists(base))
{
// Retrieve last used control values
gPrefs->Read(base + wxT("PercentChange"), &m_PercentChange, 0);
// default format "4" is the same as the Selection toolbar: "hh:mm:ss + milliseconds";
gPrefs->Read(base + wxT("TimeFormat"), &mFormat, _("hh:mm:ss + milliseconds"));
gPrefs->Read(base + wxT("VinylChoice"), &mFromVinyl, 0);
if (mFromVinyl == kVinyl_NA)
{
mFromVinyl = kVinyl_33AndAThird;
}
SetPrivateConfig(GetCurrentSettingsGroup(), wxT("TimeFormat"), mFormat);
SetPrivateConfig(GetCurrentSettingsGroup(), wxT("VinylChoice"), mFromVinyl);
SaveUserPreset(GetCurrentSettingsGroup());
// Do not migrate again
gPrefs->Write(base + wxT("Migrated"), true);
gPrefs->Flush();
}
gPrefs->Write(wxT("/Effects/ChangeSpeed/PercentChange"), m_PercentChange);
gPrefs->Write(wxT("/Effects/ChangeSpeed/TimeFormat"), mTimeCtrlFormat);
gPrefs->Flush();
return true;
}
@ -111,25 +199,6 @@ bool EffectChangeSpeed::Init()
return true;
}
// Labels are time-scaled linearly inside the affected region, and labels after
// the region are shifted along according to how the region size changed.
bool EffectChangeSpeed::ProcessLabelTrack(Track *t)
{
SetTimeWarper(new RegionTimeWarper(mT0, mT1,
new LinearTimeWarper(mT0, mT0,
mT1, mT0 + (mT1-mT0)*mFactor)));
LabelTrack *lt = (LabelTrack*)t;
if (lt == NULL) return false;
lt->WarpLabels(*GetTimeWarper());
return true;
}
bool EffectChangeSpeed::TransferParameters( Shuttle & shuttle )
{
shuttle.TransferDouble(wxT("Percentage"),m_PercentChange,0.0);
return true;
}
bool EffectChangeSpeed::Process()
{
// Similar to EffectSoundTouch::Process()
@ -137,7 +206,7 @@ bool EffectChangeSpeed::Process()
// Iterate over each track.
// Track::All is needed because this effect needs to introduce
// silence in the sync-lock group tracks to keep sync
this->CopyInputTracks(Track::All); // Set up mOutputTracks.
CopyInputTracks(Track::All); // Set up mOutputTracks.
bool bGoodResult = true;
TrackListIterator iter(mOutputTracks);
@ -204,6 +273,185 @@ bool EffectChangeSpeed::Process()
return bGoodResult;
}
void EffectChangeSpeed::PopulateOrExchange(ShuttleGui & S)
{
S.SetBorder(5);
S.StartVerticalLay(0);
{
S.AddSpace(0, 5);
S.AddTitle(_("Change Speed, affecting both Tempo and Pitch"));
S.AddSpace(0, 10);
// Speed multiplier and percent change controls.
S.StartMultiColumn(4, wxCENTER);
{
FloatingPointValidator<double> vldMultiplier(3, &mMultiplier, NUM_VAL_NO_TRAILING_ZEROES);
vldMultiplier.SetRange(MIN_Percentage / 100.0, MAX_Percentage / 100.0);
mpTextCtrl_Multiplier =
S.Id(ID_Multiplier).AddTextBox(_("Speed Multiplier:"), wxT(""), 12);
mpTextCtrl_Multiplier->SetValidator(vldMultiplier);
FloatingPointValidator<double> vldPercentage(3, &m_PercentChange, NUM_VAL_NO_TRAILING_ZEROES);
vldPercentage.SetRange(MIN_Percentage, MAX_Percentage);
mpTextCtrl_PercentChange =
S.Id(ID_PercentChange).AddTextBox(_("Percent Change:"), wxT(""), 12);
mpTextCtrl_PercentChange->SetValidator(vldPercentage);
}
S.EndMultiColumn();
// Percent change slider.
S.StartHorizontalLay(wxEXPAND);
{
S.SetStyle(wxSL_HORIZONTAL);
mpSlider_PercentChange =
S.Id(ID_PercentChange).AddSlider(wxT(""), 0, (int)kSliderMax, (int)MIN_Percentage);
mpSlider_PercentChange->SetName(_("Percent Change"));
}
S.EndHorizontalLay();
// Vinyl rpm controls.
S.StartMultiColumn(5, wxCENTER);
{
/* i18n-hint: "rpm" is an English abbreviation meaning "revolutions per minute". */
S.AddUnits(_("Standard Vinyl rpm:"));
wxASSERT(kNumVinyl == WXSIZEOF(kVinylStrings));
wxArrayString vinylChoices;
for (int i = 0; i < kNumVinyl; i++)
{
if (i == kVinyl_NA)
{
vinylChoices.Add(wxGetTranslation(kVinylStrings[i]));
}
else
{
vinylChoices.Add(kVinylStrings[i]);
}
}
mpChoice_FromVinyl =
S.Id(ID_FromVinyl).AddChoice(_("from"), wxT(""), &vinylChoices);
mpChoice_FromVinyl->SetName(_("From rpm"));
mpChoice_FromVinyl->SetSizeHints(100, -1);
mpChoice_ToVinyl =
S.Id(ID_ToVinyl).AddChoice(_("to"), wxT(""), &vinylChoices);
mpChoice_ToVinyl->SetName(_("To rpm"));
mpChoice_ToVinyl->SetSizeHints(100, -1);
}
S.EndMultiColumn();
// From/To time controls.
S.StartStatic(_("Selection Length"), 0);
{
S.StartMultiColumn(2, wxCENTER);
{
S.AddPrompt(_("Current Length:"));
mpFromLengthCtrl = new
NumericTextCtrl(NumericConverter::TIME,
S.GetParent(),
wxID_ANY,
mFormat,
mFromLength,
mProjectRate);
mpFromLengthCtrl->SetName(_("from"));
mpFromLengthCtrl->SetToolTip(_("Current length of selection."));
mpFromLengthCtrl->SetReadOnly(true);
mpFromLengthCtrl->EnableMenu(false);
S.AddWindow(mpFromLengthCtrl, wxALIGN_LEFT);
S.AddPrompt(_("New Length:"));
mpToLengthCtrl = new
NumericTextCtrl(NumericConverter::TIME,
S.GetParent(),
ID_ToLength,
mFormat,
mToLength,
mProjectRate);
mpToLengthCtrl->SetName(_("to"));
mpToLengthCtrl->EnableMenu();
S.AddWindow(mpToLengthCtrl, wxALIGN_LEFT);
}
S.EndMultiColumn();
}
S.EndStatic();
}
S.EndVerticalLay();
}
bool EffectChangeSpeed::TransferDataToWindow()
{
mbLoopDetect = true;
if (!mUIParent->TransferDataToWindow())
{
return false;
}
GetPrivateConfig(GetCurrentSettingsGroup(), wxT("TimeFormat"), mFormat, mFormat);
GetPrivateConfig(GetCurrentSettingsGroup(), wxT("VinylChoice"), mFromVinyl, mFromVinyl);
if (mFromVinyl == kVinyl_NA)
{
mFromVinyl = kVinyl_33AndAThird;
}
Update_Text_PercentChange();
Update_Text_Multiplier();
Update_Slider_PercentChange();
Update_TimeCtrl_ToLength();
// Set from/to Vinyl controls - mFromVinyl must be set first.
mpChoice_FromVinyl->SetSelection(mFromVinyl);
// Then update to get correct mToVinyl.
Update_Vinyl();
// Then update ToVinyl control.
mpChoice_ToVinyl->SetSelection(mToVinyl);
// Set From Length control.
// Set the format first so we can get sample accuracy.
mpFromLengthCtrl->SetFormatName(mFormat);
mpFromLengthCtrl->SetValue(mFromLength);
mbLoopDetect = false;
return true;
}
bool EffectChangeSpeed::TransferDataFromWindow()
{
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
SetPrivateConfig(GetCurrentSettingsGroup(), wxT("TimeFormat"), mFormat);
SetPrivateConfig(GetCurrentSettingsGroup(), wxT("VinylChoice"), mFromVinyl);
return true;
}
// EffectChangeSpeed implementation
// Labels are time-scaled linearly inside the affected region, and labels after
// the region are shifted along according to how the region size changed.
bool EffectChangeSpeed::ProcessLabelTrack(Track *t)
{
SetTimeWarper(new RegionTimeWarper(mT0, mT1,
new LinearTimeWarper(mT0, mT0,
mT1, mT0 + (mT1-mT0)*mFactor)));
LabelTrack *lt = (LabelTrack*)t;
if (lt == NULL) return false;
lt->WarpLabels(*GetTimeWarper());
return true;
}
// ProcessOne() takes a track, transforms it to bunch of buffer-blocks,
// and calls libsamplerate code on these blocks.
bool EffectChangeSpeed::ProcessOne(WaveTrack * track,
@ -304,237 +552,42 @@ bool EffectChangeSpeed::ProcessOne(WaveTrack * track,
return bResult;
}
// handler implementations for EffectChangeSpeed
//
// ChangeSpeedDialog
//
// -99 for PERCENTCHANGE_MIN because -100% is nonsensical.
#define PERCENTCHANGE_MIN -99
#define PERCENTCHANGE_MAX 100 // warped above zero to actually go up to 400%
#define PERCENTCHANGE_MAX_TEXT 4900 // maximum allowed by text entry (= 50 times)
#define PERCENTCHANGE_SLIDER_WARP 1.30105 // warp power takes max from 100 to 400.
enum {
ID_TEXT_PERCENTCHANGE = 10001,
ID_TEXT_MULTIPLIER,
ID_SLIDER_PERCENTCHANGE,
ID_CHOICE_FROMVINYL,
ID_CHOICE_TOVINYL,
ID_TIMECTRL_TOLENGTH
};
// event table for ChangeSpeedDialog
BEGIN_EVENT_TABLE(ChangeSpeedDialog, EffectDialog)
EVT_TEXT(ID_TEXT_PERCENTCHANGE, ChangeSpeedDialog::OnText_PercentChange)
EVT_TEXT(ID_TEXT_MULTIPLIER, ChangeSpeedDialog::OnText_Multiplier)
EVT_SLIDER(ID_SLIDER_PERCENTCHANGE, ChangeSpeedDialog::OnSlider_PercentChange)
EVT_CHOICE(ID_CHOICE_FROMVINYL, ChangeSpeedDialog::OnChoice_Vinyl)
EVT_CHOICE(ID_CHOICE_TOVINYL, ChangeSpeedDialog::OnChoice_Vinyl)
EVT_TEXT(ID_TIMECTRL_TOLENGTH, ChangeSpeedDialog::OnTimeCtrl_ToLength)
EVT_COMMAND(ID_TIMECTRL_TOLENGTH, EVT_TIMETEXTCTRL_UPDATED, ChangeSpeedDialog::OnTimeCtrlUpdate)
EVT_BUTTON(ID_EFFECT_PREVIEW, ChangeSpeedDialog::OnPreview)
END_EVENT_TABLE()
ChangeSpeedDialog::ChangeSpeedDialog(EffectChangeSpeed *effect, wxWindow *parent)
: EffectDialog(parent,
/* i18n-hint: Audacity's change speed effect changes the speed and pitch.*/
_("Change Speed"),
PROCESS_EFFECT),
mEffect(effect)
{
mbLoopDetect = false;
// effect parameters
m_PercentChange = 0.0;
mFromVinyl = kVinyl_33AndAThird;
mToVinyl = kVinyl_33AndAThird;
mFromLength = 0.0;
mToLength = 0.0;
mFormat = wxT("");
mTimeCtrlFormat = 0;
Init();
}
void ChangeSpeedDialog::PopulateOrExchange(ShuttleGui & S)
{
S.SetBorder(5);
S.AddSpace(0, 5);
S.AddTitle(_("Change Speed, affecting both Tempo and Pitch"));
S.AddSpace(0, 10);
// Speed multiplier and percent change controls.
S.StartMultiColumn(4, wxLEFT);
{
wxTextValidator validator(wxFILTER_NUMERIC);
mpTextCtrl_Multiplier =
S.Id(ID_TEXT_MULTIPLIER).AddTextBox(_("Speed Multiplier:"), wxT(""), 12);
mpTextCtrl_Multiplier->SetValidator(validator);
mpTextCtrl_PercentChange =
S.Id(ID_TEXT_PERCENTCHANGE).AddTextBox(_("Percent Change:"), wxT(""), 12);
mpTextCtrl_PercentChange->SetValidator(validator);
}
S.EndMultiColumn();
// Percent change slider.
S.StartHorizontalLay(wxEXPAND);
{
S.SetStyle(wxSL_HORIZONTAL);
mpSlider_PercentChange =
S.Id(ID_SLIDER_PERCENTCHANGE).AddSlider(wxT(""), 0, (int)PERCENTCHANGE_MAX, (int)PERCENTCHANGE_MIN);
mpSlider_PercentChange->SetName(_("Percent Change"));
}
S.EndHorizontalLay();
// Vinyl rpm controls.
S.StartMultiColumn(5, wxCENTER);
{
/* i18n-hint: "rpm" is an English abbreviation meaning "revolutions per minute". */
S.AddUnits(_("Standard Vinyl rpm:"));
wxArrayString rpmStrings;
rpmStrings.Add(wxT("33 1/3"));
rpmStrings.Add(wxT("45"));
rpmStrings.Add(wxT("78"));
/* i18n-hint: n/a is an English abbreviation meaning "not applicable". */
rpmStrings.Add(_("n/a"));
mpChoice_FromVinyl =
S.Id(ID_CHOICE_FROMVINYL).AddChoice(_("from"), wxT(""), &rpmStrings);
mpChoice_FromVinyl->SetName(_("From rpm"));
mpChoice_FromVinyl->SetSizeHints(100, -1);
mpChoice_ToVinyl =
S.Id(ID_CHOICE_TOVINYL).AddChoice(_("to"), wxT(""), &rpmStrings);
mpChoice_ToVinyl->SetName(_("To rpm"));
mpChoice_ToVinyl->SetSizeHints(100, -1);
}
S.EndMultiColumn();
// From/To time controls.
S.StartStatic(_("Selection Length"), 0);
{
S.StartMultiColumn(2, wxLEFT);
{
S.AddPrompt(_("Current Length") + wxString(wxT(":")));
mpFromLengthCtrl = new
NumericTextCtrl(NumericConverter::TIME, this,
wxID_ANY,
mFormat,
mFromLength,
mEffect->mProjectRate);
mpFromLengthCtrl->SetName(_("from"));
S.AddWindow(mpFromLengthCtrl, wxALIGN_LEFT);
#if wxUSE_TOOLTIPS
wxString tip(_("Current length of selection."));
mpFromLengthCtrl->SetToolTip(tip);
#endif
mpFromLengthCtrl->SetReadOnly(true);
mpFromLengthCtrl->EnableMenu(false);
S.AddPrompt(_("New Length") + wxString(wxT(":")));
mpToLengthCtrl = new
NumericTextCtrl(NumericConverter::TIME, this,
ID_TIMECTRL_TOLENGTH,
mFormat,
mToLength,
mEffect->mProjectRate);
mpToLengthCtrl->SetName(_("to"));
S.AddWindow(mpToLengthCtrl, wxALIGN_LEFT);
mpToLengthCtrl->EnableMenu();
}
S.EndMultiColumn();
}
S.EndStatic();
}
bool ChangeSpeedDialog::TransferDataToWindow()
{
mbLoopDetect = true;
this->Update_Text_PercentChange();
this->Update_Text_Multiplier();
this->Update_Slider_PercentChange();
this->Update_TimeCtrl_ToLength();
// Set from/to Vinyl controls - mFromVinyl must be set first.
mpChoice_FromVinyl->SetSelection(mFromVinyl);
// Then update to get correct mToVinyl.
this->Update_Vinyl();
// Then update ToVinyl control.
mpChoice_ToVinyl->SetSelection(mToVinyl);
// Set From Length control.
// Set the format first so we can get sample accuracy.
mpFromLengthCtrl->SetFormatName(mFormat);
mpFromLengthCtrl->SetValue(mFromLength);
mbLoopDetect = false;
return true;
}
bool ChangeSpeedDialog::Validate()
{
TransferDataFromWindow();
m_PercentChange = TrapDouble(m_PercentChange, PERCENTCHANGE_MIN, PERCENTCHANGE_MAX_TEXT);
return true;
}
// handler implementations for ChangeSpeedDialog
void ChangeSpeedDialog::OnText_PercentChange(wxCommandEvent & WXUNUSED(event))
void EffectChangeSpeed::OnText_PercentChange(wxCommandEvent & WXUNUSED(evt))
{
if (mbLoopDetect)
return;
double newValue = 0;
wxString str = mpTextCtrl_PercentChange->GetValue();
str.ToDouble(&newValue);
m_PercentChange = newValue;
this->UpdateUI();
mpTextCtrl_PercentChange->GetValidator()->TransferFromWindow();
UpdateUI();
mbLoopDetect = true;
this->Update_Text_Multiplier();
this->Update_Slider_PercentChange();
this->Update_Vinyl();
this->Update_TimeCtrl_ToLength();
Update_Text_Multiplier();
Update_Slider_PercentChange();
Update_Vinyl();
Update_TimeCtrl_ToLength();
mbLoopDetect = false;
}
void ChangeSpeedDialog::OnText_Multiplier(wxCommandEvent & WXUNUSED(event))
void EffectChangeSpeed::OnText_Multiplier(wxCommandEvent & WXUNUSED(evt))
{
if (mbLoopDetect)
return;
double newValue = 0;
wxString str = mpTextCtrl_Multiplier->GetValue();
str.ToDouble(&newValue);
m_PercentChange = 100 * (newValue - 1);
this->UpdateUI();
mpTextCtrl_Multiplier->GetValidator()->TransferFromWindow();
m_PercentChange = 100 * (mMultiplier - 1);
UpdateUI();
mbLoopDetect = true;
this->Update_Text_PercentChange();
this->Update_Slider_PercentChange();
this->Update_Vinyl();
this->Update_TimeCtrl_ToLength();
Update_Text_PercentChange();
Update_Slider_PercentChange();
Update_Vinyl();
Update_TimeCtrl_ToLength();
mbLoopDetect = false;
}
void ChangeSpeedDialog::OnSlider_PercentChange(wxCommandEvent & WXUNUSED(event))
void EffectChangeSpeed::OnSlider_PercentChange(wxCommandEvent & WXUNUSED(evt))
{
if (mbLoopDetect)
return;
@ -542,18 +595,18 @@ void ChangeSpeedDialog::OnSlider_PercentChange(wxCommandEvent & WXUNUSED(event))
m_PercentChange = (double)(mpSlider_PercentChange->GetValue());
// Warp positive values to actually go up faster & further than negatives.
if (m_PercentChange > 0.0)
m_PercentChange = pow(m_PercentChange, PERCENTCHANGE_SLIDER_WARP);
this->UpdateUI();
m_PercentChange = pow(m_PercentChange, kSliderWarp);
UpdateUI();
mbLoopDetect = true;
this->Update_Text_PercentChange();
this->Update_Text_Multiplier();
this->Update_Vinyl();
this->Update_TimeCtrl_ToLength();
Update_Text_PercentChange();
Update_Text_Multiplier();
Update_Vinyl();
Update_TimeCtrl_ToLength();
mbLoopDetect = false;
}
void ChangeSpeedDialog::OnChoice_Vinyl(wxCommandEvent & WXUNUSED(event))
void EffectChangeSpeed::OnChoice_Vinyl(wxCommandEvent & WXUNUSED(evt))
{
// Treat mpChoice_FromVinyl and mpChoice_ToVinyl as one control since we need
// both to calculate Percent Change.
@ -561,8 +614,7 @@ void ChangeSpeedDialog::OnChoice_Vinyl(wxCommandEvent & WXUNUSED(event))
mToVinyl = mpChoice_ToVinyl->GetSelection();
// Use this as the 'preferred' choice.
if (mFromVinyl != kVinyl_NA) {
gPrefs->Write(wxT("/Effects/ChangeSpeed/VinylChoice"), mFromVinyl);
gPrefs->Flush();
SetPrivateConfig(GetCurrentSettingsGroup(), wxT("VinylChoice"), mFromVinyl);
}
// If mFromVinyl & mToVinyl are set, then there's a new percent change.
@ -583,94 +635,74 @@ void ChangeSpeedDialog::OnChoice_Vinyl(wxCommandEvent & WXUNUSED(event))
case kVinyl_78: toRPM = 78; break;
}
m_PercentChange = ((toRPM * 100.0) / fromRPM) - 100.0;
this->UpdateUI();
UpdateUI();
mbLoopDetect = true;
this->Update_Text_PercentChange();
this->Update_Text_Multiplier();
this->Update_Slider_PercentChange();
this->Update_TimeCtrl_ToLength();
Update_Text_PercentChange();
Update_Text_Multiplier();
Update_Slider_PercentChange();
Update_TimeCtrl_ToLength();
}
mbLoopDetect = false;
}
void ChangeSpeedDialog::OnTimeCtrl_ToLength(wxCommandEvent & WXUNUSED(event))
void EffectChangeSpeed::OnTimeCtrl_ToLength(wxCommandEvent & WXUNUSED(evt))
{
if (mbLoopDetect)
return;
mToLength = mpToLengthCtrl->GetValue();
m_PercentChange = ((mFromLength * 100.0) / mToLength) - 100.0;
this->UpdateUI();
mToLength = mpToLengthCtrl->GetValue();
m_PercentChange = ((mFromLength * 100.0) / mToLength) - 100.0;
UpdateUI();
mbLoopDetect = true;
mbLoopDetect = true;
this->Update_Text_PercentChange();
this->Update_Text_Multiplier();
this->Update_Slider_PercentChange();
this->Update_Vinyl();
Update_Text_PercentChange();
Update_Text_Multiplier();
Update_Slider_PercentChange();
Update_Vinyl();
mbLoopDetect = false;
mbLoopDetect = false;
}
void ChangeSpeedDialog::OnTimeCtrlUpdate(wxCommandEvent &evt)
void EffectChangeSpeed::OnTimeCtrlUpdate(wxCommandEvent & evt)
{
mTimeCtrlFormat = evt.GetInt();
mFormat = evt.GetString();
mFormat = mpToLengthCtrl->GetBuiltinName(mTimeCtrlFormat);
mpFromLengthCtrl->SetFormatName(mFormat);
// Update From/To Length controls (precision has changed).
mpToLengthCtrl->SetValue(mToLength);
mpFromLengthCtrl->SetValue(mFromLength);
}
void ChangeSpeedDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
{
TransferDataFromWindow();
// Save & restore parameters around Preview, because we didn't do OK.
double oldPercentChange = mEffect->m_PercentChange;
// bug 773 allows effects to bypass greyed out OK button,
// but validate() should now catch that.
wxASSERT((m_PercentChange >= PERCENTCHANGE_MIN) && (m_PercentChange <= PERCENTCHANGE_MAX_TEXT));
mEffect->m_PercentChange = m_PercentChange;
mEffect->Preview();
mEffect->m_PercentChange = oldPercentChange;
}
// helper functions
void ChangeSpeedDialog::Update_Text_PercentChange()
void EffectChangeSpeed::Update_Text_PercentChange()
// Update Text Percent control from percent change.
{
wxString str;
str.Printf(wxT("%.3f"), m_PercentChange);
mpTextCtrl_PercentChange->SetValue(str);
mpTextCtrl_PercentChange->GetValidator()->TransferToWindow();
}
void ChangeSpeedDialog::Update_Text_Multiplier()
void EffectChangeSpeed::Update_Text_Multiplier()
// Update Multiplier control from percent change.
{
wxString str;
str.Printf(wxT("%.3f"), 1 + (m_PercentChange) / 100.0);
mpTextCtrl_Multiplier->SetValue(str);
mMultiplier = 1 + (m_PercentChange) / 100.0;
mpTextCtrl_Multiplier->GetValidator()->TransferToWindow();
}
void ChangeSpeedDialog::Update_Slider_PercentChange()
void EffectChangeSpeed::Update_Slider_PercentChange()
// Update Slider Percent control from percent change.
{
double unwarped = m_PercentChange;
if (unwarped > 0.0)
// Un-warp values above zero to actually go up to PERCENTCHANGE_MAX.
unwarped = pow(m_PercentChange, (1.0 / PERCENTCHANGE_SLIDER_WARP));
// Un-warp values above zero to actually go up to kSliderMax.
unwarped = pow(m_PercentChange, (1.0 / kSliderWarp));
// Add 0.5 to unwarped so trunc -> round.
mpSlider_PercentChange->SetValue((int)(unwarped + 0.5));
}
void ChangeSpeedDialog::Update_Vinyl()
void EffectChangeSpeed::Update_Vinyl()
// Update Vinyl controls from percent change.
{
// Match Vinyl rpm when within 0.01% of a standard ratio.
@ -684,7 +716,7 @@ void ChangeSpeedDialog::Update_Vinyl()
mpChoice_ToVinyl->SetSelection(mpChoice_FromVinyl->GetSelection());
} else {
// Use the last saved option.
gPrefs->Read(wxT("/Effects/ChangeSpeed/VinylChoice"), &mFromVinyl, 0);
GetPrivateConfig(GetCurrentSettingsGroup(), wxT("VinylChoice"), mFromVinyl, 0);
mpChoice_FromVinyl->SetSelection(mFromVinyl);
mpChoice_ToVinyl->SetSelection(mFromVinyl);
}
@ -721,13 +753,12 @@ void ChangeSpeedDialog::Update_Vinyl()
mToVinyl = mpChoice_ToVinyl->GetSelection();
}
void ChangeSpeedDialog::Update_TimeCtrl_ToLength()
void EffectChangeSpeed::Update_TimeCtrl_ToLength()
// Update ToLength control from percent change.
{
mToLength = (mFromLength * 100.0) / (100.0 + m_PercentChange);
// Set the format first so we can get sample accuracy.
mFormat = mpToLengthCtrl->GetBuiltinName(mTimeCtrlFormat);
mpToLengthCtrl->SetFormatName(mFormat);
// Negative times do not make sense.
// 359999 = 99h:59m:59s which is a little less disturbing than overflow characters
@ -736,11 +767,8 @@ void ChangeSpeedDialog::Update_TimeCtrl_ToLength()
mpToLengthCtrl->SetValue(mToLength);
}
void ChangeSpeedDialog::UpdateUI()
void EffectChangeSpeed::UpdateUI()
// Disable OK and Preview if not in sensible range.
{
bool enabled = (m_PercentChange < PERCENTCHANGE_MIN ||
m_PercentChange > PERCENTCHANGE_MAX_TEXT)? false : true;
FindWindow(wxID_OK)->Enable(enabled);
FindWindow(ID_EFFECT_PREVIEW)->Enable(enabled);
EnableApply(m_PercentChange >= MIN_Percentage && m_PercentChange <= MAX_Percentage);
}

View File

@ -13,58 +13,75 @@
#ifndef __AUDACITY_EFFECT_CHANGESPEED__
#define __AUDACITY_EFFECT_CHANGESPEED__
#include "Effect.h"
#include "../Resample.h"
#include <wx/choice.h>
#include <wx/dialog.h>
#include <wx/intl.h>
#include <wx/event.h>
#include <wx/slider.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include "../ShuttleGui.h"
#include "../Track.h"
#include "../WaveTrack.h"
#include "../widgets/NumericTextCtrl.h"
#include "Effect.h"
#define CHANGESPEED_PLUGIN_SYMBOL wxTRANSLATE("Change Speed")
class EffectChangeSpeed : public Effect
{
public:
public:
EffectChangeSpeed();
virtual ~EffectChangeSpeed();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Change Speed..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://audacityteam.org/namespace#PitchAndTempo"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Change Speed"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Changing Speed"));
}
virtual EffectType GetType();
// Useful only after PromptUser values have been set.
virtual wxString GetEffectDescription();
// EffectClientInterface implementation
double CalcPreviewInputLength(double previewLength);
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
protected:
// Effect implementation
virtual bool CheckWhetherSkipEffect();
virtual double CalcPreviewInputLength(double previewLength);
virtual bool Startup();
virtual bool Init();
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual bool CheckWhetherSkipEffect() { return (m_PercentChange == 0.0); }
virtual bool Process();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataFromWindow();
virtual bool TransferDataToWindow();
private:
bool ProcessOne(WaveTrack * t, sampleCount start, sampleCount end);
private:
// EffectChangeSpeed implementation
bool ProcessOne(WaveTrack *t, sampleCount start, sampleCount end);
bool ProcessLabelTrack(Track *t);
private:
// handlers
void OnText_PercentChange(wxCommandEvent & evt);
void OnText_Multiplier(wxCommandEvent & evt);
void OnSlider_PercentChange(wxCommandEvent & evt);
void OnChoice_Vinyl(wxCommandEvent & evt);
void OnTimeCtrl_ToLength(wxCommandEvent & evt);
void OnTimeCtrlUpdate(wxCommandEvent & evt);
// helper functions
void Update_Text_PercentChange(); // Update control per current m_PercentChange.
void Update_Text_Multiplier(); // Update control per current m_PercentChange.
void Update_Slider_PercentChange(); // Update control per current m_PercentChange.
void Update_Vinyl(); // Update Vinyl controls for new percent change.
void Update_TimeCtrl_ToLength(); // Update target length controls for new percent change.
void UpdateUI(); // Enable / disable OK / preview.
private:
// track related
int mCurTrackNum;
double mMaxNewLength;
@ -79,42 +96,8 @@ class EffectChangeSpeed : public Effect
double mFactor; // scale factor calculated from percent change
double mFromLength; // current selection length
int mTimeCtrlFormat; // time control format index number
double mMultiplier;
friend class ChangeSpeedDialog;
};
class ChangeSpeedDialog : public EffectDialog
{
public:
ChangeSpeedDialog(EffectChangeSpeed * effect,
wxWindow * parent);
void PopulateOrExchange(ShuttleGui& S);
bool TransferDataToWindow();
bool Validate();
private:
// handlers
void OnText_PercentChange(wxCommandEvent & event);
void OnText_Multiplier(wxCommandEvent & event);
void OnSlider_PercentChange(wxCommandEvent & event);
void OnChoice_Vinyl(wxCommandEvent & event);
void OnTimeCtrl_ToLength(wxCommandEvent & event);
void OnTimeCtrlUpdate(wxCommandEvent & event);
void OnPreview(wxCommandEvent &event);
// helper functions
void Update_Text_PercentChange(); // Update control per current m_PercentChange.
void Update_Text_Multiplier(); // Update control per current m_PercentChange.
void Update_Slider_PercentChange(); // Update control per current m_PercentChange.
void Update_Vinyl(); // Update Vinyl controls for new percent change.
void Update_TimeCtrl_ToLength(); // Update target length controls for new percent change.
void UpdateUI(); // Enable / disable OK / preview.
private:
EffectChangeSpeed * mEffect;
bool mbLoopDetect;
// controls
@ -132,18 +115,7 @@ class ChangeSpeedDialog : public EffectDialog
double mToLength; // target length of selection
wxString mFormat; // time control format
public:
// effect parameters
double m_PercentChange; // percent change to apply to tempo
// -100% is meaningless, but sky's the upper limit.
// Slider is (-100, 200], but textCtrls can set higher.
int mFromVinyl; // from standard vinyl speed (rpm)
double mFromLength; // current selection length
int mTimeCtrlFormat; // time control format index
private:
DECLARE_EVENT_TABLE()
DECLARE_EVENT_TABLE();
};
#endif // __AUDACITY_EFFECT_CHANGESPEED__

View File

@ -13,54 +13,121 @@
\brief An EffectSoundTouch provides speeding up or
slowing down tempo without changing pitch.
*//****************************************************************//**
\class ChangeTempoDialog
\brief Dialog used with EffectChangeTempo
*//*******************************************************************/
#include "../Audacity.h" // for USE_SOUNDTOUCH
#if USE_SOUNDTOUCH
#include "ChangeTempo.h"
#include "../ShuttleGui.h"
#include "TimeWarper.h"
#include <math.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/valtext.h>
#include <wx/intl.h>
#include "../ShuttleGui.h"
#include "../widgets/valnum.h"
#include "TimeWarper.h"
#include "ChangeTempo.h"
enum
{
ID_PercentChange = 10000,
ID_FromBPM,
ID_ToBPM,
ID_FromLength,
ID_ToLength
};
// Soundtouch is not reasonable below -99% or above 3000%.
// Define keys, defaults, minimums, and maximums for the effect parameters
//
// Name Type Key Def Min Max Scale
Param( Percentage, double, wxTRANSLATE("Percentage"), 0.0, -99.0, 3000.0, 1 );
// We warp the slider to go up to 400%, but user can enter higher values.
static const double kSliderMax = 100.0; // warped above zero to actually go up to 400%
static const double kSliderWarp = 1.30105; // warp power takes max from 100 to 400.
//
// EffectChangeTempo
//
BEGIN_EVENT_TABLE(EffectChangeTempo, wxEvtHandler)
EVT_TEXT(ID_PercentChange, EffectChangeTempo::OnText_PercentChange)
EVT_SLIDER(ID_PercentChange, EffectChangeTempo::OnSlider_PercentChange)
EVT_TEXT(ID_FromBPM, EffectChangeTempo::OnText_FromBPM)
EVT_TEXT(ID_ToBPM, EffectChangeTempo::OnText_ToBPM)
EVT_TEXT(ID_ToLength, EffectChangeTempo::OnText_ToLength)
END_EVENT_TABLE()
EffectChangeTempo::EffectChangeTempo()
{
m_PercentChange = 0.0;
m_PercentChange = DEF_Percentage;
m_FromBPM = 0.0; // indicates not yet set
m_ToBPM = 0.0; // indicates not yet set
m_FromLength = 0.0;
m_ToLength = 0.0;
m_bLoopDetect = false;
}
EffectChangeTempo::~EffectChangeTempo()
{
}
// IdentInterface implementation
wxString EffectChangeTempo::GetSymbol()
{
return CHANGETEMPO_PLUGIN_SYMBOL;
}
wxString EffectChangeTempo::GetDescription()
{
return wxTRANSLATE("Change the tempo of a selection without changing its pitch");
}
// EffectIdentInterface implementation
EffectType EffectChangeTempo::GetType()
{
return EffectTypeProcess;
}
bool EffectChangeTempo::SupportsAutomation()
{
return true;
}
// EffectClientInterface implementation
bool EffectChangeTempo::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.Write(KEY_Percentage, m_PercentChange);
return true;
}
bool EffectChangeTempo::SetAutomationParameters(EffectAutomationParameters & parms)
{
ReadAndVerifyDouble(Percentage);
m_PercentChange = Percentage;
return true;
}
// Effect implementation
double EffectChangeTempo::CalcPreviewInputLength(double previewLength)
{
return previewLength * (100.0 + m_PercentChange) / 100.0;
}
wxString EffectChangeTempo::GetEffectDescription() {
// Note: This is useful only after change amount has been set.
return wxString::Format(_("Applied effect: %s %.1f%%"),
this->GetEffectName().c_str(),
m_PercentChange);
bool EffectChangeTempo::CheckWhetherSkipEffect()
{
return (m_PercentChange == 0.0);
}
bool EffectChangeTempo::Init()
@ -75,37 +142,6 @@ bool EffectChangeTempo::Init()
return true;
}
bool EffectChangeTempo::PromptUser()
{
ChangeTempoDialog dlog(this, mParent);
dlog.m_PercentChange = m_PercentChange;
dlog.m_FromBPM = m_FromBPM;
dlog.m_ToBPM = m_ToBPM;
dlog.m_FromLength = m_FromLength;
dlog.m_ToLength = m_ToLength;
// Don't need to call TransferDataToWindow, although other
// Audacity dialogs (from which I derived this one) do it, because
// ShowModal calls stuff that eventually calls wxWindowBase::OnInitDialog,
// which calls dlog.TransferDataToWindow();
dlog.CentreOnParent();
dlog.ShowModal();
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
m_PercentChange = dlog.m_PercentChange;
m_FromBPM = dlog.m_FromBPM;
m_ToBPM = dlog.m_ToBPM;
m_ToLength = dlog.m_ToLength;
return true;
}
bool EffectChangeTempo::TransferParameters( Shuttle & shuttle )
{
shuttle.TransferDouble(wxT("Percentage"),m_PercentChange,0.0);
return true;
}
bool EffectChangeTempo::Process()
{
mSoundTouch = new SoundTouch();
@ -113,384 +149,233 @@ bool EffectChangeTempo::Process()
double mT1Dashed = mT0 + (mT1 - mT0)/(m_PercentChange/100.0 + 1.0);
SetTimeWarper(new RegionTimeWarper(mT0, mT1,
new LinearTimeWarper(mT0, mT0, mT1, mT1Dashed )));
bool success = this->EffectSoundTouch::Process();
bool success = EffectSoundTouch::Process();
if( success )
mT1 = mT0 + (mT1 - mT0)/(m_PercentChange/100 + 1.);
return success;
}
//----------------------------------------------------------------------------
// ChangeTempoDialog
//----------------------------------------------------------------------------
#define PERCENTCHANGE_MIN -99
#define PERCENTCHANGE_MAX 100 // warped above zero to actually go up to 400%
#define PERCENTCHANGE_SLIDER_WARP 1.30105 // warp power takes max from 100 to 400.
#define ID_TEXT_PERCENTCHANGE 10001
#define ID_SLIDER_PERCENTCHANGE 10002
#define ID_TEXT_FROMBPM 10003
#define ID_TEXT_TOBPM 10004
#define ID_TEXT_FROMLENGTH 10005
#define ID_TEXT_TOLENGTH 10006
// event table for ChangeTempoDialog
BEGIN_EVENT_TABLE(ChangeTempoDialog, EffectDialog)
EVT_TEXT(ID_TEXT_PERCENTCHANGE, ChangeTempoDialog::OnText_PercentChange)
EVT_SLIDER(ID_SLIDER_PERCENTCHANGE, ChangeTempoDialog::OnSlider_PercentChange)
EVT_TEXT(ID_TEXT_FROMBPM, ChangeTempoDialog::OnText_FromBPM)
EVT_TEXT(ID_TEXT_TOBPM, ChangeTempoDialog::OnText_ToBPM)
EVT_TEXT(ID_TEXT_TOLENGTH, ChangeTempoDialog::OnText_ToLength)
EVT_BUTTON(ID_EFFECT_PREVIEW, ChangeTempoDialog::OnPreview)
END_EVENT_TABLE()
ChangeTempoDialog::ChangeTempoDialog(EffectChangeTempo *effect, wxWindow *parent)
: EffectDialog(parent, _("Change Tempo"), PROCESS_EFFECT),
mEffect(effect)
void EffectChangeTempo::PopulateOrExchange(ShuttleGui & S)
{
m_bLoopDetect = false;
// NULL out these control members because there are some cases where the
// event table handlers get called during this method, and those handlers that
// can cause trouble check for NULL.
m_pTextCtrl_PercentChange = NULL;
m_pSlider_PercentChange = NULL;
m_pTextCtrl_FromBPM = NULL;
m_pTextCtrl_ToBPM = NULL;
m_pTextCtrl_FromLength = NULL;
m_pTextCtrl_ToLength = NULL;
// effect parameters
m_PercentChange = 0.0;
m_FromBPM = 0.0; // indicates not yet set
m_ToBPM = 0.0; // indicates not yet set
m_FromLength = 0.0;
m_ToLength = 0.0;
Init();
}
void ChangeTempoDialog::PopulateOrExchange(ShuttleGui & S)
{
wxTextValidator nullvld(wxFILTER_INCLUDE_CHAR_LIST);
wxTextValidator numvld(wxFILTER_NUMERIC);
S.AddSpace(0, 5);
S.AddTitle(_("Change Tempo without Changing Pitch"));
S.SetBorder(5);
//
S.StartMultiColumn(2, wxCENTER);
S.StartVerticalLay(0);
{
m_pTextCtrl_PercentChange = S.Id(ID_TEXT_PERCENTCHANGE)
.AddTextBox(_("Percent Change:"), wxT(""), 12);
m_pTextCtrl_PercentChange->SetValidator(numvld);
}
S.EndMultiColumn();
//
S.StartHorizontalLay(wxEXPAND);
{
S.SetStyle(wxSL_HORIZONTAL);
m_pSlider_PercentChange = S.Id(ID_SLIDER_PERCENTCHANGE)
.AddSlider(wxT(""), 0, (int)PERCENTCHANGE_MAX, (int)PERCENTCHANGE_MIN);
m_pSlider_PercentChange->SetName(_("Percent Change"));
}
S.EndHorizontalLay();
//
S.StartMultiColumn(5, wxCENTER);
{
//
S.AddUnits(_("Beats per minute:"));
m_pTextCtrl_FromBPM = S.Id(ID_TEXT_FROMBPM)
.AddTextBox(_("from"), wxT(""), 12);
m_pTextCtrl_FromBPM->SetName(_("From beats per minute"));
m_pTextCtrl_FromBPM->SetValidator(numvld);
m_pTextCtrl_ToBPM = S.Id(ID_TEXT_TOBPM)
.AddTextBox(_("to"), wxT(""), 12);
m_pTextCtrl_ToBPM->SetName(_("To beats per minute"));
m_pTextCtrl_ToBPM->SetValidator(numvld);
S.AddSpace(0, 5);
S.AddTitle(_("Change Tempo without Changing Pitch"));
S.SetBorder(5);
//
S.AddUnits(_("Length (seconds):"));
S.StartMultiColumn(2, wxCENTER);
{
FloatingPointValidator<double> vldPercentage(3, &m_PercentChange, NUM_VAL_NO_TRAILING_ZEROES);
vldPercentage.SetRange(MIN_Percentage, MAX_Percentage);
m_pTextCtrl_PercentChange = S.Id(ID_PercentChange)
.AddTextBox(_("Percent Change:"), wxT(""), 12);
m_pTextCtrl_PercentChange->SetValidator(vldPercentage);
}
S.EndMultiColumn();
m_pTextCtrl_FromLength = S.Id(ID_TEXT_FROMLENGTH)
.AddTextBox(_("from"), wxT(""), 12);
m_pTextCtrl_FromLength->SetName(_("From length in seconds"));
m_pTextCtrl_FromLength->SetValidator(nullvld);
//
S.StartHorizontalLay(wxEXPAND);
{
S.SetStyle(wxSL_HORIZONTAL);
m_pSlider_PercentChange = S.Id(ID_PercentChange)
.AddSlider(wxT(""), 0, (int)kSliderMax, (int)MIN_Percentage);
m_pSlider_PercentChange->SetName(_("Percent Change"));
}
S.EndHorizontalLay();
m_pTextCtrl_ToLength = S.Id(ID_TEXT_TOLENGTH)
.AddTextBox(_("to"), wxT(""), 12);
m_pTextCtrl_ToLength->SetName(_("To length in seconds"));
m_pTextCtrl_ToLength->SetValidator(numvld);
//
S.StartMultiColumn(5, wxCENTER);
{
//
S.AddUnits(_("Beats per minute:"));
FloatingPointValidator<double> vldFromBPM(3, &m_FromBPM, NUM_VAL_NO_TRAILING_ZEROES | NUM_VAL_ZERO_AS_BLANK);
m_pTextCtrl_FromBPM = S.Id(ID_FromBPM)
.AddTextBox(_("from"), wxT(""), 12);
m_pTextCtrl_FromBPM->SetName(_("From beats per minute"));
m_pTextCtrl_FromBPM->SetValidator(vldFromBPM);
FloatingPointValidator<double> vldToBPM(3, &m_ToBPM, NUM_VAL_NO_TRAILING_ZEROES | NUM_VAL_ZERO_AS_BLANK);
m_pTextCtrl_ToBPM = S.Id(ID_ToBPM)
.AddTextBox(_("to"), wxT(""), 12);
m_pTextCtrl_ToBPM->SetName(_("To beats per minute"));
m_pTextCtrl_ToBPM->SetValidator(vldToBPM);
//
S.AddUnits(_("Length (seconds):"));
FloatingPointValidator<double> vldFromLength(3, &m_FromLength, NUM_VAL_NO_TRAILING_ZEROES);
m_pTextCtrl_FromLength = S.Id(ID_FromLength)
.AddTextBox(_("from"), wxT(""), 12);
m_pTextCtrl_FromLength->SetName(_("From length in seconds"));
m_pTextCtrl_FromLength->SetValidator(vldFromLength);
m_pTextCtrl_FromLength->Enable(false); // Disable because the value comes from the user selection.
FloatingPointValidator<double> vldToLength(3, &m_ToLength, NUM_VAL_NO_TRAILING_ZEROES);
vldToLength.SetRange((m_FromLength * 100.0) / (100.0 + MAX_Percentage),
(m_FromLength * 100.0) / (100.0 + MIN_Percentage));
m_pTextCtrl_ToLength = S.Id(ID_ToLength)
.AddTextBox(_("to"), wxT(""), 12);
m_pTextCtrl_ToLength->SetName(_("To length in seconds"));
m_pTextCtrl_ToLength->SetValidator(vldToLength);
}
S.EndMultiColumn();
}
S.EndMultiColumn();
S.EndVerticalLay();
return;
}
bool ChangeTempoDialog::TransferDataToWindow()
bool EffectChangeTempo::TransferDataToWindow()
{
m_bLoopDetect = true;
if (!mUIParent->TransferDataToWindow())
{
return false;
}
// percent change controls
this->Update_Text_PercentChange();
this->Update_Slider_PercentChange();
// from/to BPM controls
wxString str;
if (m_pTextCtrl_FromBPM) {
if (m_FromBPM != 0.0)
str.Printf(wxT("%.3f"), m_FromBPM);
else
str = wxT("");
m_pTextCtrl_FromBPM->SetValue(str);
}
if (m_pTextCtrl_ToBPM) {
if (m_ToBPM != 0.0)
str.Printf(wxT("%.3f"), m_ToBPM);
else
str = wxT("");
m_pTextCtrl_ToBPM->SetValue(str);
}
// from/to Length controls
if (m_pTextCtrl_FromLength) {
str.Printf(wxT("%.2f"), m_FromLength);
m_pTextCtrl_FromLength->SetValue(str);
m_pTextCtrl_FromLength->Enable(false); // Disable because the value comes from the user selection.
}
if (m_pTextCtrl_ToLength) {
str.Printf(wxT("%.2f"), m_ToLength);
m_pTextCtrl_ToLength->SetValue(str);
}
Update_Slider_PercentChange();
m_bLoopDetect = false;
return true;
}
bool ChangeTempoDialog::TransferDataFromWindow()
bool EffectChangeTempo::TransferDataFromWindow()
{
wxString str;
// percent change controls
if (m_pTextCtrl_PercentChange) {
str = m_pTextCtrl_PercentChange->GetValue();
double newValue = 0;
str.ToDouble(&newValue);
m_PercentChange = newValue;
}
// Ignore Slider_PercentChange because TextCtrl_PercentChange
// always tracks it & is more precise (decimal points).
// from/to BPM controls
double newValue;
if (m_pTextCtrl_FromBPM) {
str = m_pTextCtrl_FromBPM->GetValue();
str.ToDouble(&newValue);
m_FromBPM = newValue;
}
if (m_pTextCtrl_ToBPM) {
str = m_pTextCtrl_ToBPM->GetValue();
str.ToDouble(&newValue);
m_ToBPM = newValue;
}
// from/to Length controls
// Don't do m_pTextCtrl_ToLength. It's disabled.
if (m_pTextCtrl_ToLength) {
str = m_pTextCtrl_ToLength->GetValue();
str.ToDouble(&newValue);
m_ToLength = newValue;
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
return true;
}
// handler implementations for ChangeTempoDialog
// handler implementations for EffectChangeTempo
void ChangeTempoDialog::OnText_PercentChange(wxCommandEvent & WXUNUSED(event))
void EffectChangeTempo::OnText_PercentChange(wxCommandEvent & WXUNUSED(evt))
{
if (m_bLoopDetect)
return;
if (m_pTextCtrl_PercentChange) {
wxString str = m_pTextCtrl_PercentChange->GetValue();
double newValue = 0;
str.ToDouble(&newValue);
m_PercentChange = newValue;
m_pTextCtrl_PercentChange->GetValidator()->TransferFromWindow();
m_bLoopDetect = true;
this->Update_Slider_PercentChange();
this->Update_Text_ToBPM();
this->Update_Text_ToLength();
m_bLoopDetect = false;
FindWindow(wxID_OK)->Enable(m_PercentChange > -100.0);
}
m_bLoopDetect = true;
Update_Slider_PercentChange();
Update_Text_ToBPM();
Update_Text_ToLength();
m_bLoopDetect = false;
}
void ChangeTempoDialog::OnSlider_PercentChange(wxCommandEvent & WXUNUSED(event))
void EffectChangeTempo::OnSlider_PercentChange(wxCommandEvent & WXUNUSED(evt))
{
if (m_bLoopDetect)
return;
if (m_pSlider_PercentChange) {
m_PercentChange = (double)(m_pSlider_PercentChange->GetValue());
// Warp positive values to actually go up faster & further than negatives.
if (m_PercentChange > 0.0)
m_PercentChange = pow(m_PercentChange, PERCENTCHANGE_SLIDER_WARP);
m_PercentChange = (double)(m_pSlider_PercentChange->GetValue());
// Warp positive values to actually go up faster & further than negatives.
if (m_PercentChange > 0.0)
m_PercentChange = pow(m_PercentChange, kSliderWarp);
m_bLoopDetect = true;
this->Update_Text_PercentChange();
this->Update_Text_ToBPM();
this->Update_Text_ToLength();
m_bLoopDetect = false;
}
m_bLoopDetect = true;
Update_Text_PercentChange();
Update_Text_ToBPM();
Update_Text_ToLength();
m_bLoopDetect = false;
}
void ChangeTempoDialog::OnText_FromBPM(wxCommandEvent & WXUNUSED(event))
void EffectChangeTempo::OnText_FromBPM(wxCommandEvent & WXUNUSED(evt))
{
if (m_bLoopDetect)
return;
if (m_pTextCtrl_FromBPM) {
wxString str = m_pTextCtrl_FromBPM->GetValue();
double newValue;
str.ToDouble(&newValue);
m_FromBPM = newValue;
m_pTextCtrl_FromBPM->GetValidator()->TransferFromWindow();
m_bLoopDetect = true;
m_bLoopDetect = true;
this->Update_Text_ToBPM();
Update_Text_ToBPM();
m_bLoopDetect = false;
}
m_bLoopDetect = false;
}
void ChangeTempoDialog::OnText_ToBPM(wxCommandEvent & WXUNUSED(event))
void EffectChangeTempo::OnText_ToBPM(wxCommandEvent & WXUNUSED(evt))
{
if (m_bLoopDetect)
return;
if (m_pTextCtrl_ToBPM) {
wxString str = m_pTextCtrl_ToBPM->GetValue();
double newValue;
str.ToDouble(&newValue);
m_ToBPM = newValue;
m_pTextCtrl_ToBPM->GetValidator()->TransferFromWindow();
m_bLoopDetect = true;
m_bLoopDetect = true;
// If FromBPM has already been set, then there's a new percent change.
if (m_FromBPM != 0.0) {
m_PercentChange = ((m_ToBPM * 100.0) / m_FromBPM) - 100.0;
this->Update_Text_PercentChange();
this->Update_Slider_PercentChange();
this->Update_Text_ToLength();
}
m_bLoopDetect = false;
}
}
void ChangeTempoDialog::OnText_ToLength(wxCommandEvent & WXUNUSED(event))
{
if (m_bLoopDetect)
return;
if (m_pTextCtrl_ToLength) {
wxString str = m_pTextCtrl_ToLength->GetValue();
double newValue = 0;
str.ToDouble(&newValue);
m_ToLength = newValue;
m_PercentChange = ((m_FromLength * 100.0) / m_ToLength) - 100.0;
m_bLoopDetect = true;
this->Update_Text_PercentChange();
this->Update_Slider_PercentChange();
this->Update_Text_ToBPM();
m_bLoopDetect = false;
}
}
void ChangeTempoDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
{
TransferDataFromWindow();
// Save & restore parameters around Preview, because we didn't do OK.
double oldPercentChange = mEffect->m_PercentChange;
if( m_PercentChange < -99.0)
// If FromBPM has already been set, then there's a new percent change.
if (m_FromBPM != 0.0 && m_ToBPM != 0.0)
{
m_PercentChange = -99.0;
this->Update_Text_PercentChange();
m_PercentChange = ((m_ToBPM * 100.0) / m_FromBPM) - 100.0;
Update_Text_PercentChange();
Update_Slider_PercentChange();
Update_Text_ToLength();
}
mEffect->m_PercentChange = m_PercentChange;
mEffect->Preview();
mEffect->m_PercentChange = oldPercentChange;
m_bLoopDetect = false;
}
void EffectChangeTempo::OnText_ToLength(wxCommandEvent & WXUNUSED(evt))
{
if (m_bLoopDetect)
return;
m_pTextCtrl_ToLength->GetValidator()->TransferFromWindow();
if (m_ToLength != 0.0)
{
m_PercentChange = ((m_FromLength * 100.0) / m_ToLength) - 100.0;
}
m_bLoopDetect = true;
Update_Text_PercentChange();
Update_Slider_PercentChange();
Update_Text_ToBPM();
m_bLoopDetect = false;
}
// helper fns
void ChangeTempoDialog::Update_Text_PercentChange()
void EffectChangeTempo::Update_Text_PercentChange()
{
if (m_pTextCtrl_PercentChange) {
wxString str;
str.Printf(wxT("%.3f"), m_PercentChange);
m_pTextCtrl_PercentChange->SetValue(str);
FindWindow(wxID_OK)->Enable(m_PercentChange > -100.0);
}
m_pTextCtrl_PercentChange->GetValidator()->TransferToWindow();
}
void ChangeTempoDialog::Update_Slider_PercentChange()
void EffectChangeTempo::Update_Slider_PercentChange()
{
if (m_pSlider_PercentChange) {
double unwarped = m_PercentChange;
if (unwarped > 0.0)
// Un-warp values above zero to actually go up to PERCENTCHANGE_MAX.
unwarped = pow(m_PercentChange, (1.0 / PERCENTCHANGE_SLIDER_WARP));
double unwarped = m_PercentChange;
if (unwarped > 0.0)
// Un-warp values above zero to actually go up to kSliderMax.
unwarped = pow(m_PercentChange, (1.0 / kSliderWarp));
// Add 0.5 to unwarped so trunc -> round.
m_pSlider_PercentChange->SetValue((int)(unwarped + 0.5));
}
// Add 0.5 to unwarped so trunc -> round.
m_pSlider_PercentChange->SetValue((int)(unwarped + 0.5));
}
void ChangeTempoDialog::Update_Text_ToBPM()
void EffectChangeTempo::Update_Text_ToBPM()
// Use m_FromBPM & m_PercentChange to set new m_ToBPM & control.
{
// Update ToBPM iff FromBPM has been set.
if (m_FromBPM == 0.0)
return;
m_ToBPM = (((m_FromBPM * (100.0 + m_PercentChange)) / 100.0));
if (m_pTextCtrl_ToBPM) {
wxString str;
str.Printf(wxT("%.3f"), m_ToBPM);
m_pTextCtrl_ToBPM->SetValue(str);
}
m_pTextCtrl_ToBPM->GetValidator()->TransferToWindow();
}
void ChangeTempoDialog::Update_Text_ToLength()
void EffectChangeTempo::Update_Text_ToLength()
// Use m_FromLength & m_PercentChange to set new m_ToLength & control.
{
m_ToLength = (m_FromLength * 100.0) / (100.0 + m_PercentChange);
if (m_pTextCtrl_ToLength) {
wxString str;
str.Printf(wxT("%.2f"), m_ToLength);
m_pTextCtrl_ToLength->SetValue(str);
}
m_pTextCtrl_ToLength->GetValidator()->TransferToWindow();
}
#endif // USE_SOUNDTOUCH
#endif // USE_SOUNDTOUCH

View File

@ -16,85 +16,57 @@
#ifndef __AUDACITY_EFFECT_CHANGETEMPO__
#define __AUDACITY_EFFECT_CHANGETEMPO__
#include <wx/event.h>
#include <wx/slider.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include "../ShuttleGui.h"
#include "SoundTouchEffect.h"
#include <wx/intl.h>
#include <wx/dialog.h>
#include <wx/slider.h>
#define CHANGETEMPO_PLUGIN_SYMBOL wxTRANSLATE("Change Tempo")
class wxString;
class wxTextCtrl;
class EffectChangeTempo : public EffectSoundTouch {
public:
class EffectChangeTempo : public EffectSoundTouch
{
public:
EffectChangeTempo();
virtual ~EffectChangeTempo();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Change Tempo..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://audacityteam.org/namespace#PitchAndTempo"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Change Tempo"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Changing Tempo"));
}
virtual EffectType GetType();
virtual bool SupportsAutomation();
// Useful only after PromptUser values have been set.
virtual wxString GetEffectDescription();
// EffectClientInterface implementation
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
// Effect implementation
virtual bool Init();
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual bool CheckWhetherSkipEffect() { return (m_PercentChange == 0.0); }
virtual bool CheckWhetherSkipEffect();
virtual bool Process();
virtual double CalcPreviewInputLength(double previewLength);
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
double CalcPreviewInputLength(double previewLength);
private:
// EffectChangeTempo implementation
private:
double m_PercentChange; // percent change to apply to tempo
// -100% is meaningless, but sky's the upper limit
double m_FromBPM; // user-set beats-per-minute. Zero means not yet set.
double m_ToBPM; // Zero value means not yet set.
double m_FromLength; // starting length of selection
double m_ToLength; // target length of selection
friend class ChangeTempoDialog;
};
//----------------------------------------------------------------------------
// ChangeTempoDialog
//----------------------------------------------------------------------------
class ChangeTempoDialog:public EffectDialog {
public:
ChangeTempoDialog(EffectChangeTempo * effect,
wxWindow * parent);
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
private:
// handlers
void OnText_PercentChange(wxCommandEvent & event);
void OnSlider_PercentChange(wxCommandEvent & event);
void OnText_FromBPM(wxCommandEvent & event);
void OnText_ToBPM(wxCommandEvent & event);
void OnText_ToLength(wxCommandEvent & event);
void OnPreview( wxCommandEvent &event );
void OnText_PercentChange(wxCommandEvent & evt);
void OnSlider_PercentChange(wxCommandEvent & evt);
void OnText_FromBPM(wxCommandEvent & evt);
void OnText_ToBPM(wxCommandEvent & evt);
void OnText_ToLength(wxCommandEvent & evt);
// helper fns
void Update_Text_PercentChange(); // Update control per current m_PercentChange.
@ -102,8 +74,14 @@ class ChangeTempoDialog:public EffectDialog {
void Update_Text_ToBPM(); // Use m_FromBPM & m_PercentChange to set new m_ToBPM & control.
void Update_Text_ToLength(); // Use m_FromLength & m_PercentChange to set new m_ToLength & control.
private:
EffectChangeTempo * mEffect;
private:
double m_PercentChange; // percent change to apply to tempo
// -100% is meaningless, but sky's the upper limit
double m_FromBPM; // user-set beats-per-minute. Zero means not yet set.
double m_ToBPM; // Zero value means not yet set.
double m_FromLength; // starting length of selection
double m_ToLength; // target length of selection
bool m_bLoopDetect;
// controls
@ -114,21 +92,9 @@ class ChangeTempoDialog:public EffectDialog {
wxTextCtrl * m_pTextCtrl_FromLength;
wxTextCtrl * m_pTextCtrl_ToLength;
public:
// effect parameters
double m_PercentChange; // percent change to apply to tempo
// -100% is meaningless, but sky's the upper limit.
// Slider is (-100, 200], but textCtrls can set higher.
double m_FromBPM; // user-set beats-per-minute. Zero means not yet set.
double m_ToBPM; // Zero value means not yet set.
double m_FromLength; // starting length of selection
double m_ToLength; // target length of selection
private:
DECLARE_EVENT_TABLE()
DECLARE_EVENT_TABLE();
};
#endif // __AUDACITY_EFFECT_CHANGETEMPO__
#endif // USE_SOUNDTOUCH

View File

@ -22,101 +22,133 @@
This file is intended to become part of Audacity. You may modify
and/or distribute it under the same terms as Audacity itself.
*//****************************************************************//**
\class ClickRemovalDialog
\brief Dialog used with EffectClickRemoval
*//*******************************************************************/
#include "../Audacity.h"
#include <math.h>
#if defined(__WXMSW__) && !defined(__CYGWIN__)
#include <float.h>
#define finite(x) _finite(x)
#endif
#include <wx/msgdlg.h>
#include <wx/textdlg.h>
#include <wx/brush.h>
#include <wx/image.h>
#include <wx/dcmemory.h>
#include <wx/statbox.h>
#include <wx/intl.h>
#include <wx/msgdlg.h>
#include <wx/valgen.h>
#include "../Prefs.h"
#include "../widgets/valnum.h"
#include "ClickRemoval.h"
#include "../ShuttleGui.h"
#include "../Envelope.h"
// #include "../FFT.h"
#include "../WaveTrack.h"
#include "../Prefs.h"
#define MIN_THRESHOLD 0
#define MAX_THRESHOLD 900
#define MIN_CLICK_WIDTH 0
#define MAX_CLICK_WIDTH 40
enum
{
ID_Thresh = 10000,
ID_Width
};
// Define keys, defaults, minimums, and maximums for the effect parameters
//
// Name Type Key Def Min Max Scale
Param( Threshold, int, wxTRANSLATE("Threshold"), 200, 0, 900, 1 );
Param( Width, int, wxTRANSLATE("Width"), 20, 0, 40, 1 );
BEGIN_EVENT_TABLE(EffectClickRemoval, wxEvtHandler)
EVT_SLIDER(ID_Thresh, EffectClickRemoval::OnThreshSlider)
EVT_SLIDER(ID_Width, EffectClickRemoval::OnWidthSlider)
EVT_TEXT(ID_Thresh, EffectClickRemoval::OnThreshText)
EVT_TEXT(ID_Width, EffectClickRemoval::OnWidthText)
END_EVENT_TABLE()
EffectClickRemoval::EffectClickRemoval()
{
mThresholdLevel = DEF_Threshold;
mClickWidth = DEF_Width;
windowSize = 8192;
sep = 2049;
Init();
}
EffectClickRemoval::~EffectClickRemoval()
{
}
bool EffectClickRemoval::Init()
// IdentInterface implementation
wxString EffectClickRemoval::GetSymbol()
{
mThresholdLevel = gPrefs->Read(wxT("/Effects/ClickRemoval/ClickThresholdLevel"), 200);
if ((mThresholdLevel < MIN_THRESHOLD) || (mThresholdLevel > MAX_THRESHOLD)) { // corrupted Prefs?
mThresholdLevel = 0; //Off-skip
gPrefs->Write(wxT("/Effects/ClickRemoval/ClickThresholdLevel"), mThresholdLevel);
}
mClickWidth = gPrefs->Read(wxT("/Effects/ClickRemoval/ClickWidth"), 20);
if ((mClickWidth < MIN_CLICK_WIDTH) || (mClickWidth > MAX_CLICK_WIDTH)) { // corrupted Prefs?
mClickWidth = 0; //Off-skip
gPrefs->Write(wxT("/Effects/ClickRemoval/ClickWidth"), mClickWidth);
}
return gPrefs->Flush();
return CLICKREMOVAL_PLUGIN_SYMBOL;
}
wxString EffectClickRemoval::GetDescription()
{
return wxTRANSLATE("Click Removal is designed to remove clicks on audio tracks");
}
// EffectIdentInterface implementation
EffectType EffectClickRemoval::GetType()
{
return EffectTypeProcess;
}
// EffectClientInterface implementation
bool EffectClickRemoval::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.Write(KEY_Threshold, mThresholdLevel);
parms.Write(KEY_Width, mClickWidth);
return true;
}
bool EffectClickRemoval::SetAutomationParameters(EffectAutomationParameters & parms)
{
ReadAndVerifyInt(Threshold);
ReadAndVerifyInt(Width);
mThresholdLevel = Threshold;
mClickWidth = Width;
return true;
}
// Effect implementation
bool EffectClickRemoval::CheckWhetherSkipEffect()
{
return ((mClickWidth == 0) || (mThresholdLevel == 0));
}
bool EffectClickRemoval::PromptUser()
bool EffectClickRemoval::Startup()
{
ClickRemovalDialog dlog(this, mParent);
dlog.mThresh = mThresholdLevel;
dlog.mWidth = mClickWidth;
wxString base = wxT("/Effects/ClickRemoval/");
dlog.TransferDataToWindow();
dlog.CentreOnParent();
dlog.ShowModal();
// Migrate settings from 2.1.0 or before
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
// Already migrated, so bail
if (gPrefs->Exists(base + wxT("Migrated")))
{
return true;
}
mThresholdLevel = dlog.mThresh;
mClickWidth = dlog.mWidth;
// Load the old "current" settings
if (gPrefs->Exists(base))
{
mThresholdLevel = gPrefs->Read(base + wxT("ClickThresholdLevel"), 200);
if ((mThresholdLevel < MIN_Threshold) || (mThresholdLevel > MAX_Threshold))
{ // corrupted Prefs?
mThresholdLevel = 0; //Off-skip
}
mClickWidth = gPrefs->Read(base + wxT("ClickWidth"), 20);
if ((mClickWidth < MIN_Width) || (mClickWidth > MAX_Width))
{ // corrupted Prefs?
mClickWidth = 0; //Off-skip
}
gPrefs->Write(wxT("/Effects/ClickRemoval/ClickThresholdLevel"), mThresholdLevel);
gPrefs->Write(wxT("/Effects/ClickRemoval/ClickWidth"), mClickWidth);
SaveUserPreset(GetCurrentSettingsGroup());
return gPrefs->Flush();
}
// Do not migrate again
gPrefs->Write(base + wxT("Migrated"), true);
gPrefs->Flush();
}
bool EffectClickRemoval::TransferParameters( Shuttle & shuttle )
{
shuttle.TransferInt(wxT("Threshold"),mThresholdLevel,0);
shuttle.TransferInt(wxT("Width"),mClickWidth,0);
return true;
}
@ -153,7 +185,7 @@ bool EffectClickRemoval::Process()
if (bGoodResult && !mbDidSomething) // Processing successful, but ineffective.
wxMessageBox(
wxString::Format(_("Algorithm not effective on this audio. Nothing changed.")),
this->GetEffectName(),
GetName(),
wxOK | wxICON_ERROR);
this->ReplaceProcessedTracks(bGoodResult && mbDidSomething);
@ -166,7 +198,7 @@ bool EffectClickRemoval::ProcessOne(int count, WaveTrack * track, sampleCount st
{
wxMessageBox(
wxString::Format(_("Selection must be larger than %d samples."), windowSize/2),
this->GetEffectName(),
GetName(),
wxOK | wxICON_ERROR);
return false;
}
@ -294,49 +326,8 @@ bool EffectClickRemoval::RemoveClicks(sampleCount len, float *buffer)
return bResult;
}
// WDR: class implementations
//----------------------------------------------------------------------------
// ClickRemovalDialog
//----------------------------------------------------------------------------
const static wxChar *numbers[] =
void EffectClickRemoval::PopulateOrExchange(ShuttleGui & S)
{
wxT("0"), wxT("1"), wxT("2"), wxT("3"), wxT("4"),
wxT("5"), wxT("6"), wxT("7"), wxT("8"), wxT("9")
};
// Declare window functions
#define ID_THRESH_TEXT 10001
#define ID_THRESH_SLIDER 10002
#define ID_WIDTH_TEXT 10003
#define ID_WIDTH_SLIDER 10004
// Declare ranges
BEGIN_EVENT_TABLE(ClickRemovalDialog, EffectDialog)
EVT_SLIDER(ID_THRESH_SLIDER, ClickRemovalDialog::OnThreshSlider)
EVT_SLIDER(ID_WIDTH_SLIDER, ClickRemovalDialog::OnWidthSlider)
EVT_TEXT(ID_THRESH_TEXT, ClickRemovalDialog::OnThreshText)
EVT_TEXT(ID_WIDTH_TEXT, ClickRemovalDialog::OnWidthText)
EVT_BUTTON(ID_EFFECT_PREVIEW, ClickRemovalDialog::OnPreview)
END_EVENT_TABLE()
ClickRemovalDialog::ClickRemovalDialog(EffectClickRemoval *effect,
wxWindow *parent)
: EffectDialog(parent, _("Click Removal"), PROCESS_EFFECT),
mEffect(effect)
{
Init();
}
void ClickRemovalDialog::PopulateOrExchange(ShuttleGui & S)
{
wxTextValidator vld(wxFILTER_INCLUDE_CHAR_LIST);
vld.SetIncludes(wxArrayString(10, numbers));
S.AddSpace(0, 5);
S.SetBorder(10);
@ -344,115 +335,84 @@ void ClickRemovalDialog::PopulateOrExchange(ShuttleGui & S)
S.SetStretchyCol(2);
{
// Threshold
mThreshT = S.Id(ID_THRESH_TEXT).AddTextBox(_("Threshold (lower is more sensitive):"),
wxT(""),
10);
mThreshT->SetValidator(vld);
IntegerValidator<int> vldThresh(&mThresholdLevel);
vldThresh.SetRange(MIN_Threshold, MAX_Threshold);
mThreshT = S.Id(ID_Thresh).AddTextBox(_("Threshold (lower is more sensitive):"),
wxT(""),
10);
mThreshT->SetValidator(vldThresh);
S.SetStyle(wxSL_HORIZONTAL);
mThreshS = S.Id(ID_THRESH_SLIDER).AddSlider(wxT(""),
0,
MAX_THRESHOLD);
mThreshS = S.Id(ID_Thresh).AddSlider(wxT(""), mThresholdLevel, MAX_Threshold, MIN_Threshold);
mThreshS->SetName(_("Threshold"));
mThreshS->SetRange(MIN_THRESHOLD, MAX_THRESHOLD);
mThreshS->SetValidator(wxGenericValidator(&mThresholdLevel));
#if defined(__WXGTK__)
// Force a minimum size since wxGTK allows it to go to zero
mThreshS->SetMinSize(wxSize(100, -1));
#endif
// Click width
mWidthT = S.Id(ID_WIDTH_TEXT).AddTextBox(_("Max Spike Width (higher is more sensitive):"),
wxT(""),
10);
mWidthT->SetValidator(vld);
IntegerValidator<int> vldWidth(&mClickWidth);
vldWidth.SetRange(MIN_Width, MAX_Width);
mWidthT = S.Id(ID_Width).AddTextBox(_("Max Spike Width (higher is more sensitive):"),
wxT(""),
10);
mWidthT->SetValidator(vldWidth);
S.SetStyle(wxSL_HORIZONTAL);
mWidthS = S.Id(ID_WIDTH_SLIDER).AddSlider(wxT(""),
0,
MAX_CLICK_WIDTH);
mWidthS = S.Id(ID_Width).AddSlider(wxT(""), mClickWidth, MAX_Width, MIN_Width);
mWidthS->SetName(_("Max Spike Width"));
mWidthS->SetRange(MIN_CLICK_WIDTH, MAX_CLICK_WIDTH);
mWidthS->SetValidator(wxGenericValidator(&mClickWidth));
#if defined(__WXGTK__)
// Force a minimum size since wxGTK allows it to go to zero
mWidthS->SetMinSize(wxSize(100, -1));
#endif
}
S.EndMultiColumn();
return;
}
bool ClickRemovalDialog::TransferDataToWindow()
bool EffectClickRemoval::TransferDataToWindow()
{
mWidthS->SetValue(mWidth);
mThreshS->SetValue(mThresh);
mWidthT->SetValue(wxString::Format(wxT("%d"), mWidth));
mThreshT->SetValue(wxString::Format(wxT("%d"), mThresh));
if (!mUIParent->TransferDataToWindow())
{
return false;
}
return true;
}
bool ClickRemovalDialog::TransferDataFromWindow()
bool EffectClickRemoval::TransferDataFromWindow()
{
mWidth = TrapLong(mWidthS->GetValue(), MIN_CLICK_WIDTH, MAX_CLICK_WIDTH);
mThresh = TrapLong(mThreshS->GetValue(), MIN_THRESHOLD, MAX_THRESHOLD);
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
return true;
}
// WDR: handler implementations for ClickRemovalDialog
void ClickRemovalDialog::OnWidthText(wxCommandEvent & WXUNUSED(event))
void EffectClickRemoval::OnWidthText(wxCommandEvent & WXUNUSED(evt))
{
long val;
mWidthT->GetValue().ToLong(&val);
mWidthS->SetValue(TrapLong(val, MIN_CLICK_WIDTH, MAX_CLICK_WIDTH));
mWidthT->GetValidator()->TransferFromWindow();
mWidthS->GetValidator()->TransferToWindow();
}
void ClickRemovalDialog::OnThreshText(wxCommandEvent & WXUNUSED(event))
void EffectClickRemoval::OnThreshText(wxCommandEvent & WXUNUSED(evt))
{
long val;
mThreshT->GetValue().ToLong(&val);
mThreshS->SetValue(TrapLong(val, MIN_THRESHOLD, MAX_THRESHOLD));
mThreshT->GetValidator()->TransferFromWindow();
mThreshS->GetValidator()->TransferToWindow();
}
void ClickRemovalDialog::OnWidthSlider(wxCommandEvent & WXUNUSED(event))
void EffectClickRemoval::OnWidthSlider(wxCommandEvent & WXUNUSED(evt))
{
mWidthT->SetValue(wxString::Format(wxT("%d"), mWidthS->GetValue()));
mWidthS->GetValidator()->TransferFromWindow();
mWidthT->GetValidator()->TransferToWindow();
}
void ClickRemovalDialog::OnThreshSlider(wxCommandEvent & WXUNUSED(event))
void EffectClickRemoval::OnThreshSlider(wxCommandEvent & WXUNUSED(evt))
{
mThreshT->SetValue(wxString::Format(wxT("%d"), mThreshS->GetValue()));
mThreshS->GetValidator()->TransferFromWindow();
mThreshT->GetValidator()->TransferToWindow();
}
void ClickRemovalDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
{
TransferDataFromWindow();
mEffect->mThresholdLevel = mThresh;
mEffect->mClickWidth = mWidth;
mEffect->Preview();
}
// WDR: handler implementations for NoiseRemovalDialog
/*
void ClickRemovalDialog::OnPreview(wxCommandEvent &event)
{
// Save & restore parameters around Preview, because we didn't do OK.
int oldLevel = mEffect->mThresholdLevel;
int oldWidth = mEffect->mClickWidth;
int oldSep = mEffect->sep;
mEffect->mThresholdLevel = m_pSlider->GetValue();
mEffect->mClickWidth = m_pSlider_width->GetValue();
// mEffect->sep = m_pSlider_sep->GetValue();
mEffect->Preview();
mEffect->sep = oldSep;
mEffect->mClickWidth = oldWidth;
mEffect->mThresholdLevel = oldLevel;
}
*/

View File

@ -16,54 +16,47 @@
#ifndef __AUDACITY_EFFECT_CLICK_REMOVAL__
#define __AUDACITY_EFFECT_CLICK_REMOVAL__
#include <wx/bitmap.h>
#include <wx/button.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/event.h>
#include <wx/slider.h>
#include <wx/stattext.h>
#include <wx/intl.h>
#include <wx/string.h>
#include <wx/textctrl.h>
class wxString;
#include "../Envelope.h"
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
#include "Effect.h"
class Envelope;
class WaveTrack;
class EffectClickRemoval: public Effect {
#define CLICKREMOVAL_PLUGIN_SYMBOL wxTRANSLATE("Click Removal")
class EffectClickRemoval : public Effect
{
public:
EffectClickRemoval();
virtual ~EffectClickRemoval();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Click Removal..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://audacityteam.org/namespace#NoiseRemoval"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Click Removal"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Removing clicks and pops..."));
}
virtual EffectType GetType();
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
// EffectClientInterface implementation
virtual bool Init();
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
// Effect implementation
virtual bool CheckWhetherSkipEffect();
virtual bool Startup();
virtual bool Process();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
private:
bool ProcessOne(int count, WaveTrack * track,
@ -71,54 +64,26 @@ private:
bool RemoveClicks(sampleCount len, float *buffer);
void OnWidthText(wxCommandEvent & evt);
void OnThreshText(wxCommandEvent & evt);
void OnWidthSlider(wxCommandEvent & evt);
void OnThreshSlider(wxCommandEvent & evt);
private:
Envelope *mEnvelope;
bool mbDidSomething; // This effect usually does nothing on real-world data.
int windowSize;
int mThresholdLevel;
int mClickWidth;
int sep;
int windowSize;
int mThresholdLevel;
int mClickWidth;
int sep;
friend class ClickRemovalDialog;
};
// WDR: class declarations
//----------------------------------------------------------------------------
// BassWidthDialog
//----------------------------------------------------------------------------
class ClickRemovalDialog:public EffectDialog {
public:
// constructors and destructors
ClickRemovalDialog(EffectClickRemoval *effect, wxWindow *parent);
// WDR: method declarations for BassWidthDialog
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
private:
// WDR: handler declarations for BassWidthDialog
void OnWidthText(wxCommandEvent & event);
void OnThreshText(wxCommandEvent & event);
void OnWidthSlider(wxCommandEvent & event);
void OnThreshSlider(wxCommandEvent & event);
void OnPreview(wxCommandEvent & event);
private:
wxSlider *mWidthS;
wxSlider *mThreshS;
wxTextCtrl *mWidthT;
wxTextCtrl *mThreshT;
DECLARE_EVENT_TABLE()
public:
EffectClickRemoval *mEffect;
int mThresh;
int mWidth;
DECLARE_EVENT_TABLE();
};
#endif

View File

@ -19,67 +19,74 @@
*//****************************************************************//**
\class CompressorDialog
\brief Dialog used with EffectCompressor.
*//****************************************************************//**
\class CompressorPanel
\brief Panel used within the CompressorDialog for EffectCompressor.
\brief Panel used within the EffectCompressor for EffectCompressor.
*//*******************************************************************/
#include "../Audacity.h" // for rint from configwin.h
#include "../Audacity.h"
#include <math.h>
#include <wx/msgdlg.h>
#include <wx/textdlg.h>
#include <wx/brush.h>
#include <wx/image.h>
#include <wx/dcmemory.h>
#include <wx/intl.h>
#include <wx/msgdlg.h>
#include "../AColor.h"
#include "../Prefs.h"
#include "../float_cast.h"
#include "../widgets/Ruler.h"
#include "Compressor.h"
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
#include "../widgets/Ruler.h"
#include "../AColor.h"
#include "../Shuttle.h"
#include "../Prefs.h"
enum
{
ID_Threshold = 10000,
ID_NoiseFloor,
ID_Ratio,
ID_Attack,
ID_Decay
};
// Define keys, defaults, minimums, and maximums for the effect parameters
//
// Name Type Key Def Min Max Scale
Param( Threshold, double, wxTRANSLATE("Threshold"), -12.0, -60.0, -1.0, 1 );
Param( NoiseFloor, double, wxTRANSLATE("NoiseFloor"), -40.0, -80.0, -20.0, 5 );
Param( Ratio, double, wxTRANSLATE("Ratio"), 2.0, 1.5, 10.0, 2 );
Param( AttackTime, double, wxTRANSLATE("AttackTime"), 0.2, 0.1, 5.0, 100 );
Param( ReleaseTime, double, wxTRANSLATE("ReleaseTime"), 1.0, 1.0, 30.0, 10 );
Param( Normalize, bool, wxTRANSLATE("Normalize"), true, false, true, 1 );
Param( UsePeak, bool, wxTRANSLATE("UsePeak"), false, false, true, 1 );
//----------------------------------------------------------------------------
// EffectCompressor
//----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(EffectCompressor, wxEvtHandler)
EVT_SLIDER(wxID_ANY, EffectCompressor::OnSlider)
END_EVENT_TABLE()
EffectCompressor::EffectCompressor()
{
mNormalize = true;
mUsePeak = false;
mThresholdDB = DEF_Threshold;
mNoiseFloorDB = DEF_NoiseFloor;
mAttackTime = DEF_AttackTime; // seconds
mDecayTime = DEF_ReleaseTime; // seconds
mRatio = DEF_Ratio; // positive number > 1.0
mNormalize = DEF_Normalize;
mUsePeak = DEF_UsePeak;
mThreshold = 0.25;
mAttackTime = 0.2; // seconds
mDecayTime = 1.0; // seconds
mRatio = 2.0; // positive number > 1.0
mCompression = 0.5;
mThresholdDB = -12.0;
mNoiseFloorDB = -40.0;
mNoiseFloor = 0.01;
mCompression = 0.5;
mCircle = NULL;
mFollow1 = NULL;
mFollow2 = NULL;
mFollowLen = 0;
}
bool EffectCompressor::Init()
{
// Restore the saved preferences
gPrefs->Read(wxT("/Effects/Compressor/ThresholdDB"), &mThresholdDB, -12.0f );
gPrefs->Read(wxT("/Effects/Compressor/NoiseFloorDB"), &mNoiseFloorDB, -40.0f );
gPrefs->Read(wxT("/Effects/Compressor/Ratio"), &mRatio, 2.0f );
gPrefs->Read(wxT("/Effects/Compressor/AttackTime"), &mAttackTime, 0.2f );
gPrefs->Read(wxT("/Effects/Compressor/DecayTime"), &mDecayTime, 1.0f );
gPrefs->Read(wxT("/Effects/Compressor/Normalize"), &mNormalize, true );
gPrefs->Read(wxT("/Effects/Compressor/UsePeak"), &mUsePeak, false );
return true;
}
EffectCompressor::~EffectCompressor()
{
if (mCircle) {
@ -96,56 +103,226 @@ EffectCompressor::~EffectCompressor()
}
}
bool EffectCompressor::TransferParameters( Shuttle & shuttle )
// IdentInterface implementation
wxString EffectCompressor::GetSymbol()
{
shuttle.TransferDouble( wxT("Threshold"), mThresholdDB, -12.0f );
shuttle.TransferDouble( wxT("NoiseFloor"), mNoiseFloorDB, -40.0f );
shuttle.TransferDouble( wxT("Ratio"), mRatio, 2.0f );
shuttle.TransferDouble( wxT("AttackTime"), mAttackTime, 0.2f );
shuttle.TransferDouble( wxT("ReleaseTime"), mDecayTime, 1.0f );
shuttle.TransferBool( wxT("Normalize"), mNormalize, true );
shuttle.TransferBool( wxT("UsePeak"), mUsePeak, false );
return COMPRESSOR_PLUGIN_SYMBOL;
}
wxString EffectCompressor::GetDescription()
{
return wxTRANSLATE("Compresses the dynamic range of audio");
}
// EffectIdentInterface implementation
EffectType EffectCompressor::GetType()
{
return EffectTypeProcess;
}
// EffectClientInterface implementation
bool EffectCompressor::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.Write(KEY_Threshold, mThresholdDB);
parms.Write(KEY_NoiseFloor, mNoiseFloorDB);
parms.Write(KEY_Ratio, mRatio);
parms.Write(KEY_AttackTime, mAttackTime);
parms.Write(KEY_ReleaseTime, mDecayTime);
parms.Write(KEY_Normalize, mNormalize);
parms.Write(KEY_UsePeak, mUsePeak);
return true;
}
bool EffectCompressor::PromptUser()
bool EffectCompressor::SetAutomationParameters(EffectAutomationParameters & parms)
{
CompressorDialog dlog(this, mParent);
dlog.threshold = mThresholdDB;
dlog.noisefloor = mNoiseFloorDB;
dlog.ratio = mRatio;
dlog.attack = mAttackTime;
dlog.decay = mDecayTime;
dlog.useGain = mNormalize;
dlog.usePeak = mUsePeak;
dlog.TransferDataToWindow();
ReadAndVerifyDouble(Threshold);
ReadAndVerifyDouble(NoiseFloor);
ReadAndVerifyDouble(Ratio);
ReadAndVerifyDouble(AttackTime);
ReadAndVerifyDouble(ReleaseTime);
ReadAndVerifyBool(Normalize);
ReadAndVerifyBool(UsePeak);
dlog.CentreOnParent();
dlog.ShowModal();
mThresholdDB = Threshold;
mNoiseFloorDB = NoiseFloor;
mRatio = Ratio;
mAttackTime = AttackTime;
mDecayTime = ReleaseTime;
mNormalize = Normalize;
mUsePeak = UsePeak;
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
mThresholdDB = dlog.threshold;
mNoiseFloorDB = dlog.noisefloor;
mRatio = dlog.ratio;
mAttackTime = dlog.attack;
mDecayTime = dlog.decay;
mNormalize = dlog.useGain;
mUsePeak = dlog.usePeak;
// Retain the settings
gPrefs->Write(wxT("/Effects/Compressor/ThresholdDB"), mThresholdDB);
gPrefs->Write(wxT("/Effects/Compressor/NoiseFloorDB"), mNoiseFloorDB);
gPrefs->Write(wxT("/Effects/Compressor/Ratio"), mRatio);
gPrefs->Write(wxT("/Effects/Compressor/AttackTime"), mAttackTime);
gPrefs->Write(wxT("/Effects/Compressor/DecayTime"), mDecayTime);
gPrefs->Write(wxT("/Effects/Compressor/Normalize"), mNormalize);
gPrefs->Write(wxT("/Effects/Compressor/UsePeak"), mUsePeak);
return gPrefs->Flush();
return true;
}
// Effect Implemenration
bool EffectCompressor::Startup()
{
wxString base = wxT("/Effects/Compressor/");
// Migrate settings from 2.1.0 or before
// Already migrated, so bail
if (gPrefs->Exists(base + wxT("Migrated")))
{
return true;
}
// Load the old "current" settings
if (gPrefs->Exists(base))
{
gPrefs->Read(base + wxT("ThresholdDB"), &mThresholdDB, -12.0f );
gPrefs->Read(base + wxT("NoiseFloorDB"), &mNoiseFloorDB, -40.0f );
gPrefs->Read(base + wxT("Ratio"), &mRatio, 2.0f );
gPrefs->Read(base + wxT("AttackTime"), &mAttackTime, 0.2f );
gPrefs->Read(base + wxT("DecayTime"), &mDecayTime, 1.0f );
gPrefs->Read(base + wxT("Normalize"), &mNormalize, true );
gPrefs->Read(base + wxT("UsePeak"), &mUsePeak, false );
SaveUserPreset(GetCurrentSettingsGroup());
// Do not migrate again
gPrefs->Write(base + wxT("Migrated"), true);
gPrefs->Flush();
}
return true;
}
void EffectCompressor::PopulateOrExchange(ShuttleGui & S)
{
S.SetBorder(5);
S.StartHorizontalLay(wxEXPAND, true);
{
S.SetBorder(10);
mPanel = new EffectCompressorPanel(S.GetParent(),
mThresholdDB,
mNoiseFloorDB,
mRatio);
mPanel->SetMinSize(wxSize(400, 200));
S.Prop(true).AddWindow(mPanel, wxEXPAND | wxALL);
S.SetBorder(5);
}
S.EndHorizontalLay();
S.StartStatic(wxT(""));
{
S.StartMultiColumn(3, wxEXPAND | wxALIGN_CENTER_VERTICAL);
{
S.SetStretchyCol(1);
mThresholdLabel = S.AddVariableText(_("Threshold:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mThresholdSlider = S.Id(ID_Threshold).AddSlider(wxT(""),
DEF_Threshold * SCL_Threshold,
MAX_Threshold * SCL_Threshold,
MIN_Threshold * SCL_Threshold);
mThresholdSlider->SetName(_("Threshold"));
mThresholdText = S.AddVariableText(wxT("XXX dB"), true,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
mNoiseFloorLabel = S.AddVariableText(_("Noise Floor:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mNoiseFloorSlider = S.Id(ID_NoiseFloor).AddSlider(wxT(""),
DEF_NoiseFloor / SCL_NoiseFloor,
MAX_NoiseFloor / SCL_NoiseFloor,
MIN_NoiseFloor / SCL_NoiseFloor);
mNoiseFloorSlider->SetName(_("Noise Floor"));
mNoiseFloorText = S.AddVariableText(wxT("XXX dB"), true,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
mRatioLabel = S.AddVariableText(_("Ratio:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mRatioSlider = S.Id(ID_Ratio).AddSlider(wxT(""),
DEF_Ratio * SCL_Ratio,
MAX_Ratio * SCL_Ratio,
MIN_Ratio * SCL_Ratio);
mRatioSlider->SetName(_("Ratio"));
mRatioText = S.AddVariableText(wxT("XXXX:1"), true,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
/* i18n-hint: Particularly in percussion, sounds can be regarded as having
* an 'attack' phase where the sound builds up and a 'decay' where the
* sound dies away. So this means 'onset duration'. */
mAttackLabel = S.AddVariableText(_("Attack Time:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mAttackSlider = S.Id(ID_Attack).AddSlider(wxT(""),
DEF_AttackTime * SCL_AttackTime,
MAX_AttackTime * SCL_AttackTime,
MIN_AttackTime * SCL_AttackTime);
mAttackSlider->SetName(_("Attack Time"));
mAttackText = S.AddVariableText(wxT("XXXX secs"), true,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
mDecayLabel = S.AddVariableText(_("Release Time:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mDecaySlider = S.Id(ID_Decay).AddSlider(wxT(""),
DEF_ReleaseTime * SCL_ReleaseTime,
MAX_ReleaseTime * SCL_ReleaseTime,
MIN_ReleaseTime * SCL_ReleaseTime);
mDecaySlider->SetName(_("Release Time"));
mDecayText = S.AddVariableText(wxT("XXXX secs"), true,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
}
S.EndMultiColumn();
}
S.EndStatic();
S.StartHorizontalLay(wxCENTER, false);
{
/* i18n-hint: Make-up, i.e. correct for any reduction, rather than fabricate it.*/
mGainCheckBox = S.AddCheckBox(_("Make-up gain for 0 dB after compressing"),
DEF_Normalize ? wxT("true") : wxT("false"));
mPeakCheckBox = S.AddCheckBox(_("Compress based on Peaks"),
DEF_UsePeak ? wxT("true") : wxT("false"));
}
S.EndHorizontalLay();
}
bool EffectCompressor::TransferDataToWindow()
{
mThresholdSlider->SetValue(lrint(mThresholdDB));
mNoiseFloorSlider->SetValue(lrint(mNoiseFloorDB / SCL_NoiseFloor));
mRatioSlider->SetValue(lrint(mRatio * SCL_Ratio));
mAttackSlider->SetValue(lrint(mAttackTime * SCL_AttackTime));
mDecaySlider->SetValue(lrint(mDecayTime * SCL_ReleaseTime));
mGainCheckBox->SetValue(mNormalize);
mPeakCheckBox->SetValue(mUsePeak);
UpdateUI();
return true;
}
bool EffectCompressor::TransferDataFromWindow()
{
if (!mUIParent->Validate())
{
return false;
}
mThresholdDB = (double) mThresholdSlider->GetValue();
mNoiseFloorDB = (double) mNoiseFloorSlider->GetValue() * SCL_NoiseFloor;
mRatio = (double) mRatioSlider->GetValue() / SCL_Ratio;
mAttackTime = (double) mAttackSlider->GetValue() / 100.0; //SCL_AttackTime;
mDecayTime = (double) mDecaySlider->GetValue() / SCL_ReleaseTime;
mNormalize = mGainCheckBox->GetValue();
mUsePeak = mPeakCheckBox->GetValue();
return true;
}
// EffectTwoPassSimpleMono implementation
bool EffectCompressor::NewTrackPass1()
{
mThreshold = pow(10.0, mThresholdDB/20); // factor of 20 because it's power
@ -175,6 +352,7 @@ bool EffectCompressor::NewTrackPass1()
return true;
}
bool EffectCompressor::InitPass1()
{
mMax=0.0;
@ -209,11 +387,12 @@ bool EffectCompressor::InitPass1()
return true;
}
bool EffectCompressor::InitPass2()
{
// Actually, this should not even be called, because we call
// DisableSecondPass() before, if mNormalize is false.
return mNormalize;
// Actually, this should not even be called, because we call
// DisableSecondPass() before, if mNormalize is false.
return mNormalize;
}
// Process the input with 2 buffers available at a time
@ -432,25 +611,74 @@ float EffectCompressor::DoCompression(float value, double env)
return out;
}
void EffectCompressor::OnSlider(wxCommandEvent & WXUNUSED(evt))
{
TransferDataFromWindow();
UpdateUI();
}
void EffectCompressor::UpdateUI()
{
mThresholdLabel->SetName(wxString::Format(_("Threshold %d dB"), (int) mThresholdDB));
/* i18n-hint: usually leave this as is as dB doesn't get translated*/
mThresholdText->SetLabel(wxString::Format(_("%3d dB"), (int) mThresholdDB));
mThresholdText->SetName(mThresholdText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
mNoiseFloorLabel->SetName(wxString::Format(_("Noise Floor %d dB"), (int) mNoiseFloorDB));
mNoiseFloorText->SetLabel(wxString::Format(_("%3d dB"), (int) mNoiseFloorDB));
mNoiseFloorText->SetName(mNoiseFloorText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
if (mRatioSlider->GetValue() % 2 == 0) {
mRatioLabel->SetName(wxString::Format(_("Ratio %.0f to 1"), mRatio));
/* i18n-hint: Unless your language has a different convention for ratios,
* like 8:1, leave as is.*/
mRatioText->SetLabel(wxString::Format(_("%.0f:1"), mRatio));
}
else {
mRatioLabel->SetName(wxString::Format(_("Ratio %.1f to 1"), mRatio));
/* i18n-hint: Unless your language has a different convention for ratios,
* like 8:1, leave as is.*/
mRatioText->SetLabel(wxString::Format(_("%.1f:1"), mRatio));
}
mRatioText->SetName(mRatioText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
mAttackLabel->SetName(wxString::Format(_("Attack Time %.2f secs"), mAttackTime));
mAttackText->SetLabel(wxString::Format(_("%.2f secs"), mAttackTime));
mAttackText->SetName(mAttackText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
mDecayLabel->SetName(wxString::Format(_("Release Time %.1f secs"), mDecayTime));
mDecayText->SetLabel(wxString::Format(_("%.1f secs"), mDecayTime));
mDecayText->SetName(mDecayText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
mPanel->Refresh(false);
return;
}
//----------------------------------------------------------------------------
// CompressorPanel
// EffectCompressorPanel
//----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(CompressorPanel, wxPanel)
EVT_PAINT(CompressorPanel::OnPaint)
BEGIN_EVENT_TABLE(EffectCompressorPanel, wxPanel)
EVT_PAINT(EffectCompressorPanel::OnPaint)
EVT_SIZE(EffectCompressorPanel::OnSize)
END_EVENT_TABLE()
CompressorPanel::CompressorPanel( wxWindow *parent, wxWindowID id,
const wxPoint& pos,
const wxSize& size):
wxPanel(parent, id, pos, size)
EffectCompressorPanel::EffectCompressorPanel(wxWindow *parent,
double & threshold,
double & noiseFloor,
double & ratio)
: wxPanel(parent),
threshold(threshold),
noiseFloor(noiseFloor),
ratio(ratio)
{
mBitmap = NULL;
mWidth = 0;
mHeight = 0;
}
void CompressorPanel::OnPaint(wxPaintEvent & WXUNUSED(event))
void EffectCompressorPanel::OnPaint(wxPaintEvent & WXUNUSED(evt))
{
wxPaintDC dc(this);
@ -525,11 +753,11 @@ void CompressorPanel::OnPaint(wxPaintEvent & WXUNUSED(event))
mEnvRect = border;
mEnvRect.Deflate( 2, 2 );
int kneeX = (int)rint((rangeDB+threshold)*mEnvRect.width/rangeDB);
int kneeY = (int)rint((rangeDB+threshold/ratio)*mEnvRect.height/rangeDB);
int kneeX = lrint((rangeDB+threshold)*mEnvRect.width/rangeDB);
int kneeY = lrint((rangeDB+threshold/ratio)*mEnvRect.height/rangeDB);
int finalY = mEnvRect.height;
int startY = (int)rint((threshold*(1.0/ratio-1.0))*mEnvRect.height/rangeDB);
int startY = lrint((threshold*(1.0/ratio-1.0))*mEnvRect.height/rangeDB);
// Yellow line for threshold
/* memDC.SetPen(wxPen(wxColour(220, 220, 0), 1, wxSOLID));
@ -569,226 +797,7 @@ void CompressorPanel::OnPaint(wxPaintEvent & WXUNUSED(event))
&memDC, 0, 0, wxCOPY, FALSE);
}
//----------------------------------------------------------------------------
// CompressorDialog
//----------------------------------------------------------------------------
enum {
ThresholdID = 7100,
NoiseFloorID,
RatioID,
AttackID,
DecayID
};
BEGIN_EVENT_TABLE(CompressorDialog, EffectDialog)
EVT_SIZE( CompressorDialog::OnSize )
EVT_BUTTON( ID_EFFECT_PREVIEW, CompressorDialog::OnPreview )
EVT_SLIDER( ThresholdID, CompressorDialog::OnSlider )
EVT_SLIDER( NoiseFloorID, CompressorDialog::OnSlider )
EVT_SLIDER( RatioID, CompressorDialog::OnSlider )
EVT_SLIDER( AttackID, CompressorDialog::OnSlider )
EVT_SLIDER( DecayID, CompressorDialog::OnSlider )
END_EVENT_TABLE()
CompressorDialog::CompressorDialog(EffectCompressor *effect, wxWindow *parent)
: EffectDialog(parent, _("Dynamic Range Compressor"), PROCESS_EFFECT,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
mEffect(effect)
void EffectCompressorPanel::OnSize(wxSizeEvent & WXUNUSED(evt))
{
Init();
SetSizeHints(500, 400);
SetSize(500, 500);
}
void CompressorDialog::PopulateOrExchange(ShuttleGui & S)
{
S.SetBorder(5);
S.StartHorizontalLay(wxEXPAND, true);
{
S.SetBorder(10);
mPanel = new CompressorPanel(S.GetParent(), wxID_ANY);
mPanel->threshold = threshold;
mPanel->noisefloor = noisefloor;
mPanel->ratio = ratio;
S.Prop(true).AddWindow(mPanel, wxEXPAND | wxALL);
S.SetBorder(5);
}
S.EndHorizontalLay();
S.StartStatic(wxT(""));
{
S.StartMultiColumn(3, wxEXPAND | wxALIGN_CENTER_VERTICAL);
{
S.SetStretchyCol(1);
mThresholdLabel = S.AddVariableText(_("Threshold:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mThresholdSlider = S.Id(ThresholdID).AddSlider(wxT(""), -12, -1, -60);
mThresholdSlider->SetName(_("Threshold"));
mThresholdText = S.AddVariableText(wxT("XXX dB"), true,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
mNoiseFloorLabel = S.AddVariableText(_("Noise Floor:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mNoiseFloorSlider = S.Id(NoiseFloorID).AddSlider(wxT(""), -8, -4, -16);
mNoiseFloorSlider->SetName(_("Noise Floor"));
mNoiseFloorText = S.AddVariableText(wxT("XXX dB"), true,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
mRatioLabel = S.AddVariableText(_("Ratio:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mRatioSlider = S.Id(RatioID).AddSlider(wxT(""), 4, 20, 3);
mRatioSlider->SetName(_("Ratio"));
mRatioText = S.AddVariableText(wxT("XXXX:1"), true,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
/* i18n-hint: Particularly in percussion, sounds can be regarded as having
* an 'attack' phase where the sound builds up and a 'decay' where the
* sound dies away. So this means 'onset duration'. */
mAttackLabel = S.AddVariableText(_("Attack Time:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mAttackSlider = S.Id(AttackID).AddSlider(wxT(""), 2, 500, 1);
mAttackSlider->SetName(_("Attack Time"));
mAttackText = S.AddVariableText(wxT("XXXX secs"), true,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
mDecayLabel = S.AddVariableText(_("Release Time:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mDecaySlider = S.Id(DecayID).AddSlider(wxT(""), 10, 300, 1);
mDecaySlider->SetName(_("Release Time"));
mDecayText = S.AddVariableText(wxT("XXXX secs"), true,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
}
S.EndMultiColumn();
}
S.EndStatic();
S.StartHorizontalLay(wxCENTER, false);
{
/* i18n-hint: Make-up, i.e. correct for any reduction, rather than fabricate it.*/
mGainCheckBox = S.AddCheckBox(_("Make-up gain for 0 dB after compressing"),
wxT("true"));
mPeakCheckBox = S.AddCheckBox(_("Compress based on Peaks"),
wxT("false"));
}
S.EndHorizontalLay();
}
bool CompressorDialog::TransferDataToWindow()
{
mPanel->threshold = threshold;
mPanel->noisefloor = noisefloor;
mPanel->ratio = ratio;
mThresholdSlider->SetValue((int)rint(threshold));
mNoiseFloorSlider->SetValue((int)rint(noisefloor/5));
mRatioSlider->SetValue((int)rint(ratio*2));
mAttackSlider->SetValue((int)rint(attack*100));
mDecaySlider->SetValue((int)rint(decay*10));
mGainCheckBox->SetValue(useGain);
mPeakCheckBox->SetValue(usePeak);
TransferDataFromWindow();
return true;
}
bool CompressorDialog::TransferDataFromWindow()
{
threshold = (double)mThresholdSlider->GetValue();
noisefloor = (double)mNoiseFloorSlider->GetValue() * 5.0;
ratio = (double)(mRatioSlider->GetValue() / 2.0);
attack = (double)(mAttackSlider->GetValue() / 100.0);
decay = (double)(mDecaySlider->GetValue() / 10.0);
useGain = mGainCheckBox->GetValue();
usePeak = mPeakCheckBox->GetValue();
mPanel->threshold = threshold;
mPanel->noisefloor = noisefloor;
mPanel->ratio = ratio;
mThresholdLabel->SetName(wxString::Format(_("Threshold %d dB"), (int) threshold));
/* i18n-hint: usually leave this as is as dB doesn't get translated*/
mThresholdText->SetLabel(wxString::Format(_("%3d dB"), (int) threshold));
mThresholdText->SetName(mThresholdText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
mNoiseFloorLabel->SetName(wxString::Format(_("Noise Floor %d dB"), (int) noisefloor));
mNoiseFloorText->SetLabel(wxString::Format(_("%3d dB"), (int) noisefloor));
mNoiseFloorText->SetName(mNoiseFloorText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
if (mRatioSlider->GetValue()%2 == 0) {
mRatioLabel->SetName(wxString::Format(_("Ratio %.0f to 1"), ratio));
/* i18n-hint: Unless your language has a different convention for ratios,
* like 8:1, leave as is.*/
mRatioText->SetLabel(wxString::Format(_("%.0f:1"), ratio));
}
else {
mRatioLabel->SetName(wxString::Format(_("Ratio %.1f to 1"), ratio));
/* i18n-hint: Unless your language has a different convention for ratios,
* like 8:1, leave as is.*/
mRatioText->SetLabel(wxString::Format(_("%.1f:1"), ratio));
}
mRatioText->SetName(mRatioText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
mAttackLabel->SetName(wxString::Format(_("Attack Time %.2f secs"), attack));
mAttackText->SetLabel(wxString::Format(_("%.2f secs"), attack));
mAttackText->SetName(mAttackText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
mDecayLabel->SetName(wxString::Format(_("Release Time %.1f secs"), decay));
mDecayText->SetLabel(wxString::Format(_("%.1f secs"), decay));
mDecayText->SetName(mDecayText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
mPanel->Refresh(false);
return true;
}
void CompressorDialog::OnSize(wxSizeEvent &event)
{
mPanel->Refresh( false );
event.Skip();
}
void CompressorDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
{
TransferDataFromWindow();
// Save & restore parameters around Preview, because we didn't do OK.
double oldAttackTime = mEffect->mAttackTime;
double oldDecayTime = mEffect->mDecayTime;
double oldThresholdDB = mEffect->mThresholdDB;
double oldNoiseFloorDB = mEffect->mNoiseFloorDB;
double oldRatio = mEffect->mRatio;
bool oldUseGain = mEffect->mNormalize;
bool oldUsePeak = mEffect->mUsePeak;
mEffect->mAttackTime = attack;
mEffect->mDecayTime = decay;
mEffect->mThresholdDB = threshold;
mEffect->mNoiseFloorDB = noisefloor;
mEffect->mRatio = ratio;
mEffect->mNormalize = useGain;
mEffect->mUsePeak = usePeak;
mEffect->Preview();
mEffect->mAttackTime = oldAttackTime;
mEffect->mDecayTime = oldDecayTime;
mEffect->mThresholdDB = oldThresholdDB;
mEffect->mNoiseFloorDB = oldNoiseFloorDB;
mEffect->mRatio = oldRatio;
mEffect->mNormalize = oldUseGain;
mEffect->mUsePeak = oldUsePeak;
}
void CompressorDialog::OnSlider(wxCommandEvent & WXUNUSED(event))
{
TransferDataFromWindow();
Refresh(false);
}

View File

@ -11,72 +11,78 @@
#ifndef __AUDACITY_EFFECT_COMPRESSOR__
#define __AUDACITY_EFFECT_COMPRESSOR__
class wxString;
#include <wx/defs.h>
#include <wx/dc.h>
#include <wx/dcclient.h>
#include <wx/bitmap.h>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/slider.h>
#include <wx/event.h>
#include <wx/gdicmn.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/slider.h>
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/intl.h>
#include <wx/window.h>
#include "../ShuttleGui.h"
#include "TwoPassSimpleMono.h"
class WaveTrack;
class EffectCompressorPanel;
class EffectCompressor: public EffectTwoPassSimpleMono {
#define COMPRESSOR_PLUGIN_SYMBOL wxTRANSLATE("Compressor")
class EffectCompressor : public EffectTwoPassSimpleMono
{
public:
EffectCompressor();
virtual ~EffectCompressor();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Compressor..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#CompressorPlugin"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Compressor"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Applying Dynamic Range Compression..."));
}
virtual EffectType GetType();
virtual bool Init();
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
// EffectClientInterface implementation
protected:
virtual bool TwoBufferProcessPass1(float *buffer1, sampleCount len1, float *buffer2, sampleCount len2);
virtual bool ProcessPass2(float *buffer, sampleCount len);
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
private:
// Effect implementation
virtual bool Startup();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
protected:
// EffectTwoPassSimpleMono implementation
virtual bool NewTrackPass1();
virtual bool InitPass1();
virtual bool InitPass2();
virtual bool NewTrackPass1();
virtual bool ProcessPass2(float *buffer, sampleCount len);
virtual bool TwoBufferProcessPass1(float *buffer1, sampleCount len1, float *buffer2, sampleCount len2);
private:
// EffectCompressor implementation
void FreshenCircle();
float AvgCircle(float x);
void Follow(float *buffer, float *env, int len, float *previous, int previous_len);
float DoCompression(float x, double env);
void OnSlider(wxCommandEvent & evt);
void UpdateUI();
private:
double mRMSSum;
int mCircleSize;
int mCirclePos;
double *mCircle;
void Follow(float *buffer, float *env, int len, float *previous, int previous_len);
float DoCompression(float x, double env);
double mAttackTime;
double mThresholdDB;
double mNoiseFloorDB;
@ -94,69 +100,13 @@ public:
int mNoiseCounter;
double mGain;
double mLastLevel;
float *mFollow1;
float *mFollow2;
float *mFollow1;
float *mFollow2;
sampleCount mFollowLen;
double mMax; //MJS
friend class CompressorDialog;
};
class CompressorPanel: public wxPanel
{
public:
CompressorPanel( wxWindow *parent, wxWindowID id,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize);
void OnPaint(wxPaintEvent & event);
double threshold;
double noisefloor;
double ratio;
private:
wxBitmap *mBitmap;
wxRect mEnvRect;
int mWidth;
int mHeight;
DECLARE_EVENT_TABLE()
};
// WDR: class declarations
//----------------------------------------------------------------------------
// CompressorDialog
//----------------------------------------------------------------------------
class CompressorDialog: public EffectDialog
{
public:
// constructors and destructors
CompressorDialog( EffectCompressor *effect, wxWindow *parent);
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
double threshold;
double noisefloor;
double ratio;
double attack;
double decay; // "release"
bool useGain;
bool usePeak;
private:
void OnSize( wxSizeEvent &event );
void OnSlider( wxCommandEvent &event );
void OnPreview( wxCommandEvent &event );
EffectCompressor *mEffect;
CompressorPanel *mPanel;
EffectCompressorPanel *mPanel;
wxStaticText *mThresholdLabel;
wxSlider *mThresholdSlider;
@ -181,8 +131,32 @@ private:
wxCheckBox *mGainCheckBox;
wxCheckBox *mPeakCheckBox;
DECLARE_EVENT_TABLE();
};
class EffectCompressorPanel: public wxPanel
{
public:
EffectCompressorPanel(wxWindow *parent,
double & threshold,
double & noiseFloor,
double & ratio);
private:
DECLARE_EVENT_TABLE()
void OnPaint(wxPaintEvent & evt);
void OnSize(wxSizeEvent & evt);
private:
double & threshold;
double & noiseFloor;
double & ratio;
wxBitmap *mBitmap;
wxRect mEnvRect;
int mWidth;
int mHeight;
DECLARE_EVENT_TABLE();
};
#endif

View File

@ -257,7 +257,7 @@ ContrastDialog::ContrastDialog(wxWindow * parent, wxWindowID id,
//Foreground
S.AddFixedText(_("&Foreground:"), false);
if (mForegroundStartT == NULL)
if (S.GetMode() == eIsCreating)
{
mForegroundStartT = new
NumericTextCtrl(NumericConverter::TIME, this,
@ -273,7 +273,7 @@ ContrastDialog::ContrastDialog(wxWindow * parent, wxWindowID id,
}
S.AddWindow(mForegroundStartT);
if (mForegroundEndT == NULL)
if (S.GetMode() == eIsCreating)
{
mForegroundEndT = new
NumericTextCtrl(NumericConverter::TIME, this,
@ -295,7 +295,7 @@ ContrastDialog::ContrastDialog(wxWindow * parent, wxWindowID id,
//Background
S.AddFixedText(_("&Background:"));
if (mBackgroundStartT == NULL)
if (S.GetMode() == eIsCreating)
{
mBackgroundStartT = new
NumericTextCtrl(NumericConverter::TIME, this,
@ -311,7 +311,7 @@ ContrastDialog::ContrastDialog(wxWindow * parent, wxWindowID id,
}
S.AddWindow(mBackgroundStartT);
if (mBackgroundEndT == NULL)
if (S.GetMode() == eIsCreating)
{
mBackgroundEndT = new
NumericTextCtrl(NumericConverter::TIME, this,

View File

@ -9,50 +9,269 @@
*******************************************************************//**
\class EffectDtmf
\brief An effect for the "Generator" menu to generate DTMF tones
\brief An effect that generates DTMF tones
*//*******************************************************************/
// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
// Include your minimal set of headers here, or wx.h
#include <wx/wx.h>
#endif
#include "DtmfGen.h"
#include "../Audacity.h"
#include "../Project.h"
#include "../Prefs.h"
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
#include "../widgets/NumericTextCtrl.h"
#include <wx/slider.h>
#include <wx/button.h>
#include <wx/choice.h>
#include <wx/radiobox.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/intl.h>
#include <wx/valgen.h>
#include <wx/valtext.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846 /* pi */
#endif
#define DUTY_MIN 0
#define DUTY_MAX 1000
#define DUTY_SCALE (DUTY_MAX/100.0) // ensure float division
#define FADEINOUT 250.0 // used for fadein/out needed to remove clicking noise
#define AMP_MIN 0
#define AMP_MAX 1
#include "../Prefs.h"
#include "../widgets/valnum.h"
#include "DtmfGen.h"
// Define keys, defaults, minimums, and maximums for the effect parameters
//
// Name Type Key Def Min Max Scale
Param( Sequence, wxString, wxTRANSLATE("Sequence"), wxT("audacity"), wxT(""), wxT(""), wxT(""));
Param( DutyCycle, double, wxTRANSLATE("Duty Cycle"), 55.0, 0.0, 100.0, 10.0 );
Param( Amplitude, double, wxTRANSLATE("Amplitude"), 0.0, 0.0, 1.0, 1 );
static const double kFadeInOut = 250.0; // used for fadein/out needed to remove clicking noise
const static wxChar *kSymbols[] =
{
wxT("0"), wxT("1"), wxT("2"), wxT("3"),
wxT("4"), wxT("5"), wxT("6"), wxT("7"),
wxT("8"), wxT("9"), wxT("*"), wxT("#"),
wxT("A"), wxT("B"), wxT("C"), wxT("D"),
wxT("a"), wxT("b"), wxT("c"), wxT("d"),
wxT("e"), wxT("f"), wxT("g"), wxT("h"),
wxT("i"), wxT("j"), wxT("k"), wxT("l"),
wxT("m"), wxT("n"), wxT("o"), wxT("p"),
wxT("q"), wxT("r"), wxT("s"), wxT("t"),
wxT("u"), wxT("v"), wxT("w"), wxT("x"),
wxT("y"), wxT("z")
};
//
// EffectDtmf
//
bool EffectDtmf::Init()
BEGIN_EVENT_TABLE(EffectDtmf, wxEvtHandler)
EVT_TEXT(wxID_ANY, EffectDtmf::OnText)
EVT_SLIDER(wxID_ANY, EffectDtmf::OnSlider)
END_EVENT_TABLE()
EffectDtmf::EffectDtmf()
{
dtmfDutyCycle = DEF_DutyCycle;
dtmfAmplitude = DEF_Amplitude;
dtmfString = DEF_Sequence;
mDuration = GetDefaultDuration();
dtmfTone = 0.0;
dtmfSilence = 0.0;
}
EffectDtmf::~EffectDtmf()
{
}
// IdentInterface implementation
wxString EffectDtmf::GetSymbol()
{
return DTMFTONES_PLUGIN_SYMBOL;
}
wxString EffectDtmf::GetDescription()
{
return wxTRANSLATE("Generates dual-tone multi-frequency (DTMF) tones like those produced by the keypad on telephones");
}
// EffectIdentInterface implementation
EffectType EffectDtmf::GetType()
{
return EffectTypeGenerate;
}
// EffectClientInterface implementation
int EffectDtmf::GetAudioOutCount()
{
return 1;
}
bool EffectDtmf::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames WXUNUSED(chanMap))
{
// all dtmf sequence durations in samples from seconds
// MJS: Note that mDuration is in seconds but will have been quantised to the units of the TTC.
// If this was 'samples' and the project rate was lower than the track rate,
// extra samples may get created as mDuration may now be > mT1 - mT0;
// However we are making our best efforts at creating what was asked for.
sampleCount nT0 = (sampleCount)floor(mT0 * mSampleRate + 0.5);
sampleCount nT1 = (sampleCount)floor((mT0 + mDuration) * mSampleRate + 0.5);
numSamplesSequence = nT1 - nT0; // needs to be exact number of samples selected
//make under-estimates if anything, and then redistribute the few remaining samples
numSamplesTone = (sampleCount)floor(dtmfTone * mSampleRate);
numSamplesSilence = (sampleCount)floor(dtmfSilence * mSampleRate);
// recalculate the sum, and spread the difference - due to approximations.
// Since diff should be in the order of "some" samples, a division (resulting in zero)
// is not sufficient, so we add the additional remaining samples in each tone/silence block,
// at least until available.
diff = numSamplesSequence - (dtmfNTones*numSamplesTone) - (dtmfNTones-1)*numSamplesSilence;
while (diff > 2*dtmfNTones - 1) { // more than one per thingToBeGenerated
// in this case, both numSamplesTone and numSamplesSilence would change, so it makes sense
// to recalculate diff here, otherwise just keep the value we already have
// should always be the case that dtmfNTones>1, as if 0, we don't even start processing,
// and with 1 there is no difference to spread (no silence slot)...
wxASSERT(dtmfNTones > 1);
numSamplesTone += (diff/(dtmfNTones));
numSamplesSilence += (diff/(dtmfNTones-1));
diff = numSamplesSequence - (dtmfNTones*numSamplesTone) - (dtmfNTones-1)*numSamplesSilence;
}
wxASSERT(diff >= 0); // should never be negative
curSeqPos = -1; // pointer to string in dtmfString
isTone = false;
numRemaining = 0;
return true;
}
sampleCount EffectDtmf::ProcessBlock(float **WXUNUSED(inbuf), float **outbuf, sampleCount size)
{
float *buffer = outbuf[0];
sampleCount processed = 0;
// for the whole dtmf sequence, we will be generating either tone or silence
// according to a bool value, and this might be done in small chunks of size
// 'block', as a single tone might sometimes be larger than the block
// tone and silence generally have different duration, thus two generation blocks
//
// Note: to overcome a 'clicking' noise introduced by the abrupt transition from/to
// silence, I added a fade in/out of 1/250th of a second (4ms). This can still be
// tweaked but gives excellent results at 44.1kHz: I haven't tried other freqs.
// A problem might be if the tone duration is very short (<10ms)... (?)
//
// One more problem is to deal with the approximations done when calculating the duration
// of both tone and silence: in some cases the final sum might not be same as the initial
// duration. So, to overcome this, we had a redistribution block up, and now we will spread
// the remaining samples in every bin in order to achieve the full duration: test case was
// to generate an 11 tone DTMF sequence, in 4 seconds, and with DutyCycle=75%: after generation
// you ended up with 3.999s or in other units: 3 seconds and 44097 samples.
//
while (size)
{
if (numRemaining == 0)
{
isTone = !isTone;
if (isTone)
{
curSeqPos++;
numRemaining = numSamplesTone;
curTonePos = 0;
}
else
{
numRemaining = numSamplesSilence;
}
// the statement takes care of extracting one sample from the diff bin and
// adding it into the current block until depletion
numRemaining += (diff-- > 0 ? 1 : 0);
}
sampleCount len = wxMin(numRemaining, size);
if (isTone)
{
// generate the tone and append
MakeDtmfTone(buffer, len, mSampleRate, dtmfString[curSeqPos], curTonePos, numSamplesTone, dtmfAmplitude);
curTonePos += len;
}
else
{
memset(buffer, 0, sizeof(float) * len);
}
numRemaining -= len;
buffer += len;
size -= len;
processed += len;
}
return processed;
}
bool EffectDtmf::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.Write(KEY_Sequence, dtmfString);
parms.Write(KEY_DutyCycle, dtmfDutyCycle);
parms.Write(KEY_Amplitude, dtmfAmplitude);
return true;
}
bool EffectDtmf::SetAutomationParameters(EffectAutomationParameters & parms)
{
ReadAndVerifyDouble(DutyCycle);
ReadAndVerifyDouble(Amplitude);
ReadAndVerifyString(Sequence);
wxString symbols;
for (unsigned int i = 0; i < WXSIZEOF(kSymbols); i++)
{
symbols += kSymbols[i];
}
if (Sequence.find_first_not_of(symbols) != wxString::npos)
{
return false;
}
dtmfDutyCycle = DutyCycle;
dtmfAmplitude = Amplitude;
dtmfString = Sequence;
Recalculate();
return true;
}
// Effect implementation
bool EffectDtmf::Startup()
{
wxString base = wxT("/Effects/DtmfGen/");
// Migrate settings from 2.1.0 or before
// Already migrated, so bail
if (gPrefs->Exists(base + wxT("Migrated")))
{
return true;
}
// Load the old "current" settings
if (gPrefs->Exists(base))
{
gPrefs->Read(base + wxT("String"), &dtmfString, wxT("audacity"));
gPrefs->Read(base + wxT("DutyCycle"), &dtmfDutyCycle, 550L);
gPrefs->Read(base + wxT("Amplitude"), &dtmfAmplitude, 0.8f);
SaveUserPreset(GetCurrentSettingsGroup());
// Do not migrate again
gPrefs->Write(base + wxT("Migrated"), true);
gPrefs->Flush();
}
return true;
}
void EffectDtmf::PopulateOrExchange(ShuttleGui & S)
{
// dialog will be passed values from effect
// Effect retrieves values from saved config
@ -61,75 +280,151 @@ bool EffectDtmf::Init()
// value from saved config: this is useful is user wants to
// replace selection with dtmf sequence
bool isSelection = false;
if (mT1 > mT0) {
// there is a selection: let's fit in there...
// MJS: note that this is just for the TTC and is independent of the track rate
// but we do need to make sure we have the right number of samples at the project rate
AudacityProject *p = GetActiveProject();
double projRate = p->GetRate();
double quantMT0 = QUANTIZED_TIME(mT0, projRate);
double quantMT1 = QUANTIZED_TIME(mT1, projRate);
double quantMT0 = QUANTIZED_TIME(mT0, mProjectRate);
double quantMT1 = QUANTIZED_TIME(mT1, mProjectRate);
mDuration = quantMT1 - quantMT0;
mIsSelection = true;
} else {
// retrieve last used values
gPrefs->Read(wxT("/Effects/DtmfGen/SequenceDuration"), &mDuration, 1L);
mIsSelection = false;
isSelection = true;
}
gPrefs->Read(wxT("/Effects/DtmfGen/String"), &dtmfString, wxT("audacity"));
gPrefs->Read(wxT("/Effects/DtmfGen/DutyCycle"), &dtmfDutyCycle, 550L);
gPrefs->Read(wxT("/Effects/DtmfGen/Amplitude"), &dtmfAmplitude, 0.8f);
dtmfNTones = wxStrlen(dtmfString);
S.AddSpace(0, 5);
S.StartMultiColumn(2, wxCENTER);
{
wxTextValidator vldDtmf(wxFILTER_INCLUDE_CHAR_LIST, &dtmfString);
vldDtmf.SetIncludes(wxArrayString(WXSIZEOF(kSymbols), kSymbols));
S.AddTextBox(_("DTMF sequence:"), wxT(""), 10)->SetValidator(vldDtmf);
return true;
FloatingPointValidator<double> vldAmp(1, &dtmfAmplitude);
vldAmp.SetRange(MIN_Amplitude, MAX_Amplitude);
S.AddTextBox(_("Amplitude (0-1):"), wxT(""), 10)->SetValidator(vldAmp);
S.AddPrompt(_("Duration:"));
mDtmfDurationT = new
NumericTextCtrl(NumericConverter::TIME,
S.GetParent(),
wxID_ANY,
/* use this instead of "seconds" because if a selection is passed to the
* effect, I want it (mDuration) to be used as the duration, and with
* "seconds" this does not always work properly. For example, it rounds
* down to zero... */
isSelection ? _("hh:mm:ss + samples") : _("hh:mm:ss + milliseconds"),
mDuration,
mProjectRate,
wxDefaultPosition,
wxDefaultSize,
true);
mDtmfDurationT->SetName(_("Duration"));
mDtmfDurationT->EnableMenu();
S.AddWindow(mDtmfDurationT);
S.AddFixedText(_("Tone/silence ratio:"), false);
S.SetStyle(wxSL_HORIZONTAL | wxEXPAND);
mDtmfDutyS = S.AddSlider(wxT(""),
dtmfDutyCycle * SCL_DutyCycle,
MAX_DutyCycle * SCL_DutyCycle,
MIN_DutyCycle * SCL_DutyCycle);
S.SetSizeHints(-1,-1);
}
S.EndMultiColumn();
S.StartMultiColumn(2, wxCENTER);
{
S.AddFixedText(_("Duty cycle:"), false);
mDtmfDutyT = S.AddVariableText(wxString::Format(wxT("%.1f %%"), dtmfDutyCycle), false);
S.AddFixedText(_("Tone duration:"), false);
mDtmfSilenceT = S.AddVariableText(wxString::Format(wxString(wxT("%.0f ")) + _("ms"), dtmfTone * 1000.0), false);
S.AddFixedText(_("Silence duration:"), false);
mDtmfToneT = S.AddVariableText(wxString::Format(wxString(wxT("%0.f ")) + _("ms"), dtmfSilence * 1000.0), false);
}
S.EndMultiColumn();
}
bool EffectDtmf::PromptUser()
bool EffectDtmf::TransferDataToWindow()
{
DtmfDialog dlog(this, mParent,
/* i18n-hint: DTMF stands for 'Dial Tone Modulation Format'. Leave as is.*/
_("DTMF Tone Generator"));
Recalculate();
Init();
// Initialize dialog locals
dlog.dIsSelection = mIsSelection;
dlog.dString = dtmfString;
dlog.dDutyCycle = dtmfDutyCycle;
dlog.dDuration = mDuration;
dlog.dAmplitude = dtmfAmplitude;
// start dialog
dlog.Init();
dlog.ShowModal();
if (dlog.GetReturnCode() == wxID_CANCEL)
if (!mUIParent->TransferDataToWindow())
{
return false;
}
// if there was an OK, retrieve values
dtmfString = dlog.dString;
dtmfDutyCycle = dlog.dDutyCycle;
mDuration = dlog.dDuration;
dtmfAmplitude = dlog.dAmplitude;
mDtmfDutyS->SetValue(dtmfDutyCycle * SCL_DutyCycle);
mDtmfDurationT->SetValue(mDuration);
dtmfNTones = dlog.dNTones;
dtmfTone = dlog.dTone;
dtmfSilence = dlog.dSilence;
UpdateUI();
return true;
}
bool EffectDtmf::TransferParameters( Shuttle & WXUNUSED(shuttle) )
bool EffectDtmf::TransferDataFromWindow()
{
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
dtmfDutyCycle = (double) mDtmfDutyS->GetValue() / SCL_DutyCycle;
mDuration = mDtmfDurationT->GetValue();
// recalculate to make sure all values are up-to-date. This is especially
// important if the user did not change any values in the dialog
Recalculate();
return true;
}
// EffectDtmf implementation
void EffectDtmf::Recalculate()
{
// remember that dtmfDutyCycle is in range (0.0-100.0)
dtmfNTones = (int) dtmfString.Length();
if (dtmfNTones==0) {
// no tones, all zero: don't do anything
// this should take care of the case where user got an empty
// dtmf sequence into the generator: track won't be generated
mDuration = 0;
dtmfTone = 0;
dtmfSilence = mDuration;
} else {
if (dtmfNTones==1) {
// single tone, as long as the sequence
dtmfTone = mDuration;
dtmfSilence = 0;
} else {
// Don't be fooled by the fact that you divide the sequence into dtmfNTones:
// the last slot will only contain a tone, not ending with silence.
// Given this, the right thing to do is to divide the sequence duration
// by dtmfNTones tones and (dtmfNTones-1) silences each sized according to the duty
// cycle: original division was:
// slot=mDuration / (dtmfNTones*(dtmfDutyCycle/MAX_DutyCycle)+(dtmfNTones-1)*(1.0-dtmfDutyCycle/MAX_DutyCycle))
// which can be simplified in the one below.
// Then just take the part that belongs to tone or silence.
//
double slot = mDuration / ((double)dtmfNTones + (dtmfDutyCycle / 100.0) - 1);
dtmfTone = slot * (dtmfDutyCycle / 100.0); // seconds
dtmfSilence = slot * (1.0 - (dtmfDutyCycle / 100.0)); // seconds
// Note that in the extremes we have:
// - dutyCycle=100%, this means no silence, so each tone will measure mDuration/dtmfNTones
// - dutyCycle=0%, this means no tones, so each silence slot will measure mDuration/(NTones-1)
// But we always count:
// - dtmfNTones tones
// - dtmfNTones-1 silences
}
}
}
bool EffectDtmf::MakeDtmfTone(float *buffer, sampleCount len, float fs, wxChar tone, sampleCount last, sampleCount total, float amplitude)
{
/*
--------------------------------------------
1209 Hz 1336 Hz 1477 Hz 1633 Hz
@ -232,7 +527,7 @@ bool EffectDtmf::MakeDtmfTone(float *buffer, sampleCount len, float fs, wxChar t
// generate a fade-in of duration 1/250th of second
if (last==0) {
A=(fs/FADEINOUT);
A=(fs/kFadeInOut);
for(sampleCount i=0; i<A; i++) {
buffer[i]*=i/A;
}
@ -242,8 +537,8 @@ bool EffectDtmf::MakeDtmfTone(float *buffer, sampleCount len, float fs, wxChar t
if (last==total-len) {
// we are at the last buffer of 'len' size, so, offset is to
// backup 'A' samples, from 'len'
A=(fs/FADEINOUT);
sampleCount offset=len-(sampleCount)(fs/FADEINOUT);
A=(fs/kFadeInOut);
sampleCount offset=len-(sampleCount)(fs/kFadeInOut);
// protect against negative offset, which can occur if too a
// small selection is made
if (offset>=0) {
@ -255,336 +550,30 @@ bool EffectDtmf::MakeDtmfTone(float *buffer, sampleCount len, float fs, wxChar t
return true;
}
bool EffectDtmf::GenerateTrack(WaveTrack *tmp,
const WaveTrack &track,
int ntrack)
void EffectDtmf::UpdateUI(void)
{
bool bGoodResult = true;
// all dtmf sequence durations in samples from seconds
// MJS: Note that mDuration is in seconds but will have been quantised to the units of the TTC.
// If this was 'samples' and the project rate was lower than the track rate,
// extra samples may get created as mDuration may now be > mT1 - mT0;
// However we are making our best efforts at creating what was asked for.
sampleCount nT0 = tmp->TimeToLongSamples(mT0);
sampleCount nT1 = tmp->TimeToLongSamples(mT0 + mDuration);
numSamplesSequence = nT1 - nT0; // needs to be exact number of samples selected
//make under-estimates if anything, and then redistribute the few remaining samples
numSamplesTone = (sampleCount)floor(dtmfTone * track.GetRate());
numSamplesSilence = (sampleCount)floor(dtmfSilence * track.GetRate());
// recalculate the sum, and spread the difference - due to approximations.
// Since diff should be in the order of "some" samples, a division (resulting in zero)
// is not sufficient, so we add the additional remaining samples in each tone/silence block,
// at least until available.
int diff = numSamplesSequence - (dtmfNTones*numSamplesTone) - (dtmfNTones-1)*numSamplesSilence;
while (diff > 2*dtmfNTones - 1) { // more than one per thingToBeGenerated
// in this case, both numSamplesTone and numSamplesSilence would change, so it makes sense
// to recalculate diff here, otherwise just keep the value we already have
// should always be the case that dtmfNTones>1, as if 0, we don't even start processing,
// and with 1 there is no difference to spread (no silence slot)...
wxASSERT(dtmfNTones > 1);
numSamplesTone += (diff/(dtmfNTones));
numSamplesSilence += (diff/(dtmfNTones-1));
diff = numSamplesSequence - (dtmfNTones*numSamplesTone) - (dtmfNTones-1)*numSamplesSilence;
}
wxASSERT(diff >= 0); // should never be negative
// this var will be used as extra samples distributor
int extra=0;
sampleCount i = 0;
sampleCount j = 0;
int n=0; // pointer to string in dtmfString
sampleCount block;
bool isTone = true;
float *data = new float[tmp->GetMaxBlockSize()];
// for the whole dtmf sequence, we will be generating either tone or silence
// according to a bool value, and this might be done in small chunks of size
// 'block', as a single tone might sometimes be larger than the block
// tone and silence generally have different duration, thus two generation blocks
//
// Note: to overcome a 'clicking' noise introduced by the abrupt transition from/to
// silence, I added a fade in/out of 1/250th of a second (4ms). This can still be
// tweaked but gives excellent results at 44.1kHz: I haven't tried other freqs.
// A problem might be if the tone duration is very short (<10ms)... (?)
//
// One more problem is to deal with the approximations done when calculating the duration
// of both tone and silence: in some cases the final sum might not be same as the initial
// duration. So, to overcome this, we had a redistribution block up, and now we will spread
// the remaining samples in every bin in order to achieve the full duration: test case was
// to generate an 11 tone DTMF sequence, in 4 seconds, and with DutyCycle=75%: after generation
// you ended up with 3.999s or in other units: 3 seconds and 44097 samples.
//
while ((i < numSamplesSequence) && bGoodResult) {
if (isTone)
{ // generate tone
// the statement takes care of extracting one sample from the diff bin and
// adding it into the tone block until depletion
extra=(diff-- > 0?1:0);
for(j=0; j < numSamplesTone+extra && bGoodResult; j+=block) {
block = tmp->GetBestBlockSize(j);
if (block > (numSamplesTone+extra - j))
block = numSamplesTone+extra - j;
// generate the tone and append
MakeDtmfTone(data, block, track.GetRate(), dtmfString[n], j, numSamplesTone, dtmfAmplitude);
tmp->Append((samplePtr)data, floatSample, block);
//Update the Progress meter
if (TrackProgress(ntrack, (double)(i+j) / numSamplesSequence))
bGoodResult = false;
}
i += numSamplesTone;
n++;
if(n>=dtmfNTones)break;
}
else
{ // generate silence
// the statement takes care of extracting one sample from the diff bin and
// adding it into the silence block until depletion
extra=(diff-- > 0?1:0);
for(j=0; j < numSamplesSilence+extra && bGoodResult; j+=block) {
block = tmp->GetBestBlockSize(j);
if (block > (numSamplesSilence+extra - j))
block = numSamplesSilence+extra - j;
// generate silence and append
memset(data, 0, sizeof(float)*block);
tmp->Append((samplePtr)data, floatSample, block);
//Update the Progress meter
if (TrackProgress(ntrack, (double)(i+j) / numSamplesSequence))
bGoodResult = false;
}
i += numSamplesSilence;
}
// flip flag
isTone=!isTone;
} // finished the whole dtmf sequence
wxLogDebug(wxT("Extra %d diff: %d"), extra, diff);
delete[] data;
return bGoodResult;
}
void EffectDtmf::Success()
{
/* save last used values
save duration unless value was got from selection, so we save only
when user explicitely setup a value
*/
if (mT1 == mT0)
gPrefs->Write(wxT("/Effects/DtmfGen/SequenceDuration"), mDuration);
gPrefs->Write(wxT("/Effects/DtmfGen/String"), dtmfString);
gPrefs->Write(wxT("/Effects/DtmfGen/DutyCycle"), dtmfDutyCycle);
gPrefs->Write(wxT("/Effects/DtmfGen/Amplitude"), dtmfAmplitude);
gPrefs->Flush();
}
//----------------------------------------------------------------------------
// DtmfDialog
//----------------------------------------------------------------------------
const static wxChar *dtmfSymbols[] =
{
wxT("0"), wxT("1"), wxT("2"), wxT("3"),
wxT("4"), wxT("5"), wxT("6"), wxT("7"),
wxT("8"), wxT("9"), wxT("*"), wxT("#"),
wxT("A"), wxT("B"), wxT("C"), wxT("D"),
wxT("a"), wxT("b"), wxT("c"), wxT("d"),
wxT("e"), wxT("f"), wxT("g"), wxT("h"),
wxT("i"), wxT("j"), wxT("k"), wxT("l"),
wxT("m"), wxT("n"), wxT("o"), wxT("p"),
wxT("q"), wxT("r"), wxT("s"), wxT("t"),
wxT("u"), wxT("v"), wxT("w"), wxT("x"),
wxT("y"), wxT("z")
};
#define ID_DTMF_DUTYCYCLE_SLIDER 10001
#define ID_DTMF_STRING_TEXT 10002
#define ID_DTMF_DURATION_TEXT 10003
#define ID_DTMF_DUTYCYCLE_TEXT 10004
#define ID_DTMF_TONELEN_TEXT 10005
#define ID_DTMF_SILENCE_TEXT 10006
BEGIN_EVENT_TABLE(DtmfDialog, EffectDialog)
EVT_TEXT(ID_DTMF_STRING_TEXT, DtmfDialog::OnDtmfStringText)
EVT_TEXT(ID_DTMF_DURATION_TEXT, DtmfDialog::OnDtmfDurationText)
EVT_COMMAND(wxID_ANY, EVT_TIMETEXTCTRL_UPDATED, DtmfDialog::OnTimeCtrlUpdate)
EVT_SLIDER(ID_DTMF_DUTYCYCLE_SLIDER, DtmfDialog::OnDutyCycleSlider)
END_EVENT_TABLE()
DtmfDialog::DtmfDialog(EffectDtmf * effect, wxWindow * parent, const wxString & title)
: EffectDialog(parent, title, INSERT_EFFECT),
mEffect(effect)
{
/*
wxString dString; // dtmf tone string
int dNTones; // total number of tones to generate
double dTone; // duration of a single tone
double dSilence; // duration of silence between tones
double dDuration; // duration of the whole dtmf tone sequence
*/
dTone = 0;
dSilence = 0;
dDuration = 0;
mDtmfDurationT = NULL;
}
void DtmfDialog::PopulateOrExchange( ShuttleGui & S )
{
wxTextValidator vldDtmf(wxFILTER_INCLUDE_CHAR_LIST);
vldDtmf.SetIncludes(wxArrayString(42, dtmfSymbols));
S.AddSpace(0, 5);
S.StartMultiColumn(2, wxEXPAND);
{
mDtmfStringT = S.Id(ID_DTMF_STRING_TEXT).AddTextBox(_("DTMF sequence:"), wxT(""), 10);
mDtmfStringT->SetValidator(vldDtmf);
// The added colon to improve visual consistency was placed outside
// the translatable strings to avoid breaking translations close to 2.0.
// TODO: Make colon part of the translatable string after 2.0.
S.TieNumericTextBox(_("Amplitude (0-1)") + wxString(wxT(":")), dAmplitude, 10);
S.AddPrompt(_("Duration:"));
if (mDtmfDurationT == NULL)
{
mDtmfDurationT = new
NumericTextCtrl(NumericConverter::TIME, this,
ID_DTMF_DURATION_TEXT,
/* use this instead of "seconds" because if a selection is passed to the
* effect, I want it (dDuration) to be used as the duration, and with
* "seconds" this does not always work properly. For example, it rounds
* down to zero... */
dIsSelection ? _("hh:mm:ss + samples") : _("hh:mm:ss + milliseconds"),
dDuration,
mEffect->mProjectRate,
wxDefaultPosition,
wxDefaultSize,
true);
mDtmfDurationT->SetName(_("Duration"));
mDtmfDurationT->EnableMenu();
}
S.AddWindow(mDtmfDurationT);
S.AddFixedText(_("Tone/silence ratio:"), false);
S.SetStyle(wxSL_HORIZONTAL | wxEXPAND);
mDtmfDutyS = S.Id(ID_DTMF_DUTYCYCLE_SLIDER).AddSlider(wxT(""), (int)dDutyCycle, DUTY_MAX, DUTY_MIN);
S.SetSizeHints(-1,-1);
}
S.EndMultiColumn();
S.StartMultiColumn(2, wxCENTER);
{
S.AddFixedText(_("Duty cycle:"), false);
mDtmfDutyT = S.Id(ID_DTMF_DUTYCYCLE_TEXT).AddVariableText(wxString::Format(wxT("%.1f %%"), (float) dDutyCycle/DUTY_SCALE), false);
S.AddFixedText(_("Tone duration:"), false);
mDtmfSilenceT = S.Id(ID_DTMF_TONELEN_TEXT).AddVariableText(wxString::Format(wxString(wxT("%d ")) + _("ms"), (int) dTone * 1000), false);
S.AddFixedText(_("Silence duration:"), false);
mDtmfToneT = S.Id(ID_DTMF_SILENCE_TEXT).AddVariableText(wxString::Format(wxString(wxT("%d ")) + _("ms"), (int) dSilence * 1000), false);
}
S.EndMultiColumn();
}
bool DtmfDialog::TransferDataToWindow()
{
mDtmfDutyS->SetValue((int)dDutyCycle);
mDtmfDurationT->SetValue(dDuration);
mDtmfStringT->SetValue(dString);
return true;
}
bool DtmfDialog::TransferDataFromWindow()
{
EffectDialog::TransferDataFromWindow();
dAmplitude = TrapDouble(dAmplitude, AMP_MIN, AMP_MAX);
// recalculate to make sure all values are up-to-date. This is especially
// important if the user did not change any values in the dialog
Recalculate();
return true;
}
/*
*
*/
void DtmfDialog::Recalculate(void) {
// remember that dDutyCycle is in range (0-1000)
double slot;
dString = mDtmfStringT->GetValue();
dDuration = mDtmfDurationT->GetValue();
dNTones = wxStrlen(dString);
dDutyCycle = TrapLong(mDtmfDutyS->GetValue(), DUTY_MIN, DUTY_MAX);
if (dNTones==0) {
// no tones, all zero: don't do anything
// this should take care of the case where user got an empty
// dtmf sequence into the generator: track won't be generated
dTone = 0;
dDuration = 0;
dSilence = dDuration;
} else
if (dNTones==1) {
// single tone, as long as the sequence
dSilence = 0;
dTone = dDuration;
} else {
// Don't be fooled by the fact that you divide the sequence into dNTones:
// the last slot will only contain a tone, not ending with silence.
// Given this, the right thing to do is to divide the sequence duration
// by dNTones tones and (dNTones-1) silences each sized according to the duty
// cycle: original division was:
// slot=dDuration / (dNTones*(dDutyCycle/DUTY_MAX)+(dNTones-1)*(1.0-dDutyCycle/DUTY_MAX))
// which can be simplified in the one below.
// Then just take the part that belongs to tone or silence.
//
slot=dDuration/((double)dNTones+(dDutyCycle/DUTY_MAX)-1);
dTone = slot * (dDutyCycle/DUTY_MAX); // seconds
dSilence = slot * (1.0 - (dDutyCycle/DUTY_MAX)); // seconds
// Note that in the extremes we have:
// - dutyCycle=100%, this means no silence, so each tone will measure dDuration/dNTones
// - dutyCycle=0%, this means no tones, so each silence slot will measure dDuration/(NTones-1)
// But we always count:
// - dNTones tones
// - dNTones-1 silences
}
mDtmfDutyT->SetLabel(wxString::Format(wxT("%.1f %%"), (float)dDutyCycle/DUTY_SCALE));
mDtmfDutyT->SetLabel(wxString::Format(wxT("%.1f %%"), dtmfDutyCycle));
mDtmfDutyT->SetName(mDtmfDutyT->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
mDtmfSilenceT->SetLabel(wxString::Format(wxString(wxT("%d ")) + _("ms"), (int) (dTone * 1000)));
mDtmfSilenceT->SetLabel(wxString::Format(wxString(wxT("%.0f ")) + _("ms"), dtmfTone * 1000.0));
mDtmfSilenceT->SetName(mDtmfSilenceT->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
mDtmfToneT->SetLabel(wxString::Format(wxString(wxT("%d ")) + _("ms"), (int) (dSilence * 1000)));
mDtmfToneT->SetLabel(wxString::Format(wxString(wxT("%0.f ")) + _("ms"), dtmfSilence * 1000.0));
mDtmfToneT->SetName(mDtmfToneT->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
}
void DtmfDialog::OnDutyCycleSlider(wxCommandEvent & WXUNUSED(event)) {
void EffectDtmf::OnSlider(wxCommandEvent & evt)
{
dtmfDutyCycle = (double) evt.GetInt() / SCL_DutyCycle;
mUIParent->TransferDataFromWindow();
Recalculate();
UpdateUI();
}
void DtmfDialog::OnDtmfStringText(wxCommandEvent & WXUNUSED(event)) {
void EffectDtmf::OnText(wxCommandEvent & WXUNUSED(evt))
{
mDuration = mDtmfDurationT->GetValue();
mUIParent->TransferDataFromWindow();
Recalculate();
}
void DtmfDialog::OnDtmfDurationText(wxCommandEvent & WXUNUSED(event)) {
Recalculate();
}
void DtmfDialog::OnTimeCtrlUpdate(wxCommandEvent & WXUNUSED(event)) {
this->Fit();
UpdateUI();
}

View File

@ -7,134 +7,92 @@
Salvo Ventura
Dec 2006
An effect for the "Generator" menu to generate DTMF tones
An effect that generates DTMF tones
**********************************************************************/
#ifndef __AUDACITY_EFFECT_DTMF__
#define __AUDACITY_EFFECT_DTMF__
#include <wx/choice.h>
#include <wx/defs.h>
#include <wx/intl.h>
#include <wx/sizer.h>
#include <wx/event.h>
#include <wx/slider.h>
#include <wx/stattext.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
#include "../widgets/NumericTextCtrl.h"
#include "Generator.h"
#include "Effect.h"
class NumericTextCtrl;
#define DTMFTONES_PLUGIN_SYMBOL wxTRANSLATE("DTMF Tones")
#define __UNINITIALIZED__ (-1)
class EffectDtmf : public Effect
{
public:
EffectDtmf();
virtual ~EffectDtmf();
class EffectDtmf : public Generator {
// IdentInterface implementation
public:
EffectDtmf() : mIsSelection(false) {
SetEffectFlags(BUILTIN_EFFECT | INSERT_EFFECT);
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("DTMF Tones..."));
}
// EffectIdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#GeneratorPlugin"));
return result;
}
virtual EffectType GetType();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("DTMF Tones"));
}
// EffectClientInterface implementation
// Return true if the effect supports processing via batch chains.
virtual bool SupportsChains() {
return false;
}
virtual int GetAudioOutCount();
virtual bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap = NULL);
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen);
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
virtual wxString GetEffectDescription() {
return wxString::Format(_("Applied effect: Generate DTMF tones, %.6lf seconds"), mDuration);
}
// Effect implementation
virtual wxString GetEffectAction() {
return wxString(_("Generating DTMF tones"));
}
virtual bool Startup();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataFromWindow();
virtual bool TransferDataToWindow();
virtual bool Init();
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
private:
// EffectDtmf implementation
private:
sampleCount numSamplesSequence, numSamplesTone, numSamplesSilence;
bool MakeDtmfTone(float *buffer, sampleCount len, float fs,
wxChar tone, sampleCount last,
sampleCount total, float amplitude);
void Recalculate();
wxString dtmfString; // dtmf tone string
int dtmfNTones; // total number of tones to generate
double dtmfTone; // duration of a single tone in ms
double dtmfSilence; // duration of silence between tones in ms
double dtmfDutyCycle; // ratio of dtmfTone/(dtmfTone+dtmfSilence)
double dtmfAmplitude; // amplitude of dtmf tone sequence, restricted to (0-1)
bool mIsSelection;
void UpdateUI();
protected:
virtual bool MakeDtmfTone(float *buffer, sampleCount len, float fs,
wxChar tone, sampleCount last,
sampleCount total, float amplitude);
bool GenerateTrack(WaveTrack *tmp, const WaveTrack &track, int ntrack);
void Success();
void OnText(wxCommandEvent & evt);
void OnSlider(wxCommandEvent & evt);
// friendship ...
friend class DtmfDialog;
private:
sampleCount numSamplesSequence; // total number of samples to generate
sampleCount numSamplesTone; // number of samples in a tone block
sampleCount numSamplesSilence; // number of samples in a silence block
sampleCount diff; // number of extra samples to redistribute
sampleCount numRemaining; // number of samples left to produce in the current block
sampleCount curTonePos; // position in tone to start the wave
bool isTone; // true if block is tone, otherwise silence
int curSeqPos; // index into dtmf tone string
};
wxString dtmfString; // dtmf tone string
int dtmfNTones; // total number of tones to generate
double dtmfTone; // duration of a single tone in ms
double dtmfSilence; // duration of silence between tones in ms
double dtmfDutyCycle; // ratio of dtmfTone/(dtmfTone+dtmfSilence)
double dtmfAmplitude; // amplitude of dtmf tone sequence, restricted to (0-1)
//----------------------------------------------------------------------------
// DtmfDialog
//----------------------------------------------------------------------------
// Declare window functions
class DtmfDialog:public EffectDialog {
public:
// constructors and destructors
DtmfDialog(EffectDtmf * effect, wxWindow * parent, const wxString & title);
// method declarations
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
private:
void OnDtmfStringText(wxCommandEvent & event);
void OnDtmfDurationText(wxCommandEvent & event);
void OnDutyCycleSlider(wxCommandEvent & event);
void OnTimeCtrlUpdate(wxCommandEvent & event);
void Recalculate(void);
private:
EffectDtmf *mEffect;
wxSlider *mDtmfDutyS;
wxTextCtrl *mDtmfStringT;
NumericTextCtrl *mDtmfDurationT;
wxStaticText *mDtmfToneT;
wxStaticText *mDtmfSilenceT;
wxStaticText *mDtmfDutyT;
DECLARE_EVENT_TABLE()
public:
wxString dString; // dtmf tone string
int dNTones; // total number of tones to generate
double dTone; // duration of a single tone
double dSilence; // duration of silence between tones
double dDuration; // duration of the whole dtmf tone sequence
double dDutyCycle; // ratio of dTone/(dTone+dSilence)
double dAmplitude; // amplitude of dtmf tone sequence, restricted to (0-1)
bool dIsSelection; // true if duration comes from selection
DECLARE_EVENT_TABLE();
};
#endif

View File

@ -19,246 +19,150 @@
*//*******************************************************************/
#include "../Audacity.h"
#include <wx/defs.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/validate.h>
#include <wx/valtext.h>
#include <float.h>
#include <wx/generic/textdlgg.h>
#include <wx/intl.h>
#include <math.h>
#include "../widgets/valnum.h"
#include "Echo.h"
#include "../WaveTrack.h"
// Define keys, defaults, minimums, and maximums for the effect parameters
//
// Name Type Key Def Min Max Scale
Param( Delay, float, wxTRANSLATE("Delay"), 1.0, 0.0, FLT_MAX, 1 );
Param( Decay, float, wxTRANSLATE("Decay"), 0.5, 1.0, 1.0, 1 );
EffectEcho::EffectEcho()
{
delay = float(1.0);
decay = float(0.5);
delay = DEF_Delay;
decay = DEF_Decay;
}
wxString EffectEcho::GetEffectDescription() {
// Note: This is useful only after values have been set.
return wxString::Format(_("Applied effect: %s delay = %f seconds, decay factor = %f"),
this->GetEffectName().c_str(), delay, decay);
}
bool EffectEcho::PromptUser()
EffectEcho::~EffectEcho()
{
EchoDialog dlog(this, mParent);
dlog.delay = delay;
dlog.decay = decay;
dlog.CentreOnParent();
dlog.ShowModal();
}
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
// IdentInterface implementation
delay = dlog.delay;
decay = dlog.decay;
wxString EffectEcho::GetSymbol()
{
return ECHO_PLUGIN_SYMBOL;
}
wxString EffectEcho::GetDescription()
{
return wxTRANSLATE("Repeats the selected audio again and again");
}
// EffectIdentInterface implementation
EffectType EffectEcho::GetType()
{
return EffectTypeProcess;
}
// EffectClientInterface implementation
int EffectEcho::GetAudioInCount()
{
return 1;
}
int EffectEcho::GetAudioOutCount()
{
return 1;
}
bool EffectEcho::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames WXUNUSED(chanMap))
{
histPos = 0;
histLen = (sampleCount) (mSampleRate * delay);
history = new float[histLen];
memset(history, 0, sizeof(float) * histLen);
return history != NULL;
}
bool EffectEcho::ProcessFinalize()
{
delete [] history;
return true;
}
bool EffectEcho::TransferParameters( Shuttle & shuttle )
sampleCount EffectEcho::ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen)
{
shuttle.TransferFloat(wxT("Delay"),delay,1.0);
shuttle.TransferFloat(wxT("Decay"),decay,0.5);
return true;
}
float *ibuf = inBlock[0];
float *obuf = outBlock[0];
bool EffectEcho::Process()
{
this->CopyInputTracks(); // Set up mOutputTracks.
bool bGoodResult = true;
SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks);
WaveTrack *track = (WaveTrack *) iter.First();
int count = 0;
while (track) {
double trackStart = track->GetStartTime();
double trackEnd = track->GetEndTime();
double t0 = mT0 < trackStart? trackStart: mT0;
double t1 = mT1 > trackEnd? trackEnd: mT1;
if (t1 > t0) {
sampleCount start = track->TimeToLongSamples(t0);
sampleCount end = track->TimeToLongSamples(t1);
sampleCount len = (sampleCount)(end - start);
if (!ProcessOne(count, track, start, len))
{
bGoodResult = false;
break;
}
for (sampleCount i = 0; i < blockLen; i++, histPos++)
{
if (histPos == histLen)
{
histPos = 0;
}
track = (WaveTrack *) iter.Next();
count++;
history[histPos] = obuf[i] = ibuf[i] + history[histPos] * decay;
}
this->ReplaceProcessedTracks(bGoodResult);
return bGoodResult;
return blockLen;
}
bool EffectEcho::ProcessOne(int count, WaveTrack * track,
sampleCount start, sampleCount len)
bool EffectEcho::GetAutomationParameters(EffectAutomationParameters & parms)
{
sampleCount s = 0;
sampleCount blockSize = (sampleCount) (track->GetRate() * delay);
//do nothing if the delay is less than 1 sample or greater than
//the length of the selection
if (blockSize < 1 || blockSize > len)
return true;
float *buffer0 = new float[blockSize];
float *buffer1 = new float[blockSize];
float *ptr0 = buffer0;
float *ptr1 = buffer1;
bool first = true;
while (s < len) {
sampleCount block = blockSize;
if (s + block > len)
block = len - s;
track->Get((samplePtr)ptr0, floatSample, start + s, block);
if (!first) {
for (sampleCount i = 0; i < block; i++)
ptr0[i] += ptr1[i] * decay;
track->Set((samplePtr)ptr0, floatSample, start + s, block);
}
float *ptrtemp = ptr0;
ptr0 = ptr1;
ptr1 = ptrtemp;
first = false;
s += block;
if (TrackProgress(count, s / (double) len)) {
delete[]buffer0;
delete[]buffer1;
return false;
}
}
delete[]buffer0;
delete[]buffer1;
parms.WriteFloat(KEY_Delay, delay);
parms.WriteFloat(KEY_Decay, decay);
return true;
}
//----------------------------------------------------------------------------
// EchoDialog
//----------------------------------------------------------------------------
// event table for EchoDialog
BEGIN_EVENT_TABLE(EchoDialog, EffectDialog)
EVT_BUTTON(ID_EFFECT_PREVIEW, EchoDialog::OnPreview)
END_EVENT_TABLE()
EchoDialog::EchoDialog(EffectEcho * effect, wxWindow * parent)
: EffectDialog(parent, _("Echo"))
bool EffectEcho::SetAutomationParameters(EffectAutomationParameters & parms)
{
m_bLoopDetect = false;
m_pEffect = effect;
ReadAndVerifyFloat(Delay);
ReadAndVerifyFloat(Decay);
// NULL out these control members because there are some cases where the
// event table handlers get called during this method, and those handlers that
// can cause trouble check for NULL.
m_pTextCtrl_Delay = NULL;
m_pTextCtrl_Decay = NULL;
delay = Delay;
decay = Decay;
// effect parameters
delay = float(1.0);
decay = float(0.5);
// Initialize dialog
Init();
return true;
}
void EchoDialog::PopulateOrExchange(ShuttleGui & S)
void EffectEcho::PopulateOrExchange(ShuttleGui & S)
{
S.AddSpace(0, 5);
S.StartMultiColumn(2, wxALIGN_CENTER);
{
m_pTextCtrl_Delay = S.AddTextBox(_("Delay time (seconds):"),
wxT("1.0"),
10);
m_pTextCtrl_Delay->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
FloatingPointValidator<double> vldDelay(3, &delay, NUM_VAL_NO_TRAILING_ZEROES);
vldDelay.SetRange(MIN_Delay, MAX_Delay);
S.AddTextBox(_("Delay time (seconds):"), wxT(""), 10)->SetValidator(vldDelay);
m_pTextCtrl_Decay = S.AddTextBox(_("Decay factor:"),
wxT("0.5"),
10);
m_pTextCtrl_Decay->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
FloatingPointValidator<double> vldDecay(3, &decay, NUM_VAL_NO_TRAILING_ZEROES);
vldDecay.SetRange(MIN_Decay, MAX_Decay);
S.AddTextBox(_("Decay factor:"), wxT(""), 10)->SetValidator(vldDecay);
}
S.EndMultiColumn();
}
bool EchoDialog::TransferDataToWindow()
bool EffectEcho::TransferDataToWindow()
{
m_bLoopDetect = true;
wxString str;
if (m_pTextCtrl_Delay) {
str.Printf(wxT("%g"), delay);
m_pTextCtrl_Delay->SetValue(str);
}
if (m_pTextCtrl_Decay) {
str.Printf(wxT("%g"), decay);
m_pTextCtrl_Decay->SetValue(str);
if (!mUIParent->TransferDataToWindow())
{
return false;
}
m_bLoopDetect = false;
return true;
}
bool EchoDialog::TransferDataFromWindow()
bool EffectEcho::TransferDataFromWindow()
{
double newValue;
wxString str;
if (m_pTextCtrl_Delay) {
str = m_pTextCtrl_Delay->GetValue();
str.ToDouble(&newValue);
delay = (float)(newValue);
}
if (m_pTextCtrl_Decay) {
str = m_pTextCtrl_Decay->GetValue();
str.ToDouble(&newValue);
decay = (float)(newValue);
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
return true;
}
// handler implementations for EchoDialog
void EchoDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
{
TransferDataFromWindow();
// Save & restore parameters around Preview, because we didn't do OK.
float oldDelay = m_pEffect->delay;
float oldDecay = m_pEffect->decay;
m_pEffect->delay = delay;
m_pEffect->decay = decay;
m_pEffect->Preview();
m_pEffect->delay = oldDelay;
m_pEffect->decay = oldDecay;
}

View File

@ -12,91 +12,55 @@
#ifndef __AUDACITY_EFFECT_ECHO__
#define __AUDACITY_EFFECT_ECHO__
class wxString;
#include <wx/event.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include <wx/dialog.h>
#include <wx/intl.h>
#include "../ShuttleGui.h"
#include "Effect.h"
class wxStaticText;
class WaveTrack;
class EffectEcho:public Effect {
public:
#define ECHO_PLUGIN_SYMBOL wxTRANSLATE("Echo")
class EffectEcho : public Effect
{
public:
EffectEcho();
virtual ~EffectEcho();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Echo..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#DelayPlugin"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Echo"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Performing Echo"));
}
virtual EffectType GetType();
// Useful only after PromptUser values have been set.
virtual wxString GetEffectDescription();
// EffectClientInterface implementation
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual int GetAudioInCount();
virtual int GetAudioOutCount();
virtual bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap = NULL);
virtual bool ProcessFinalize();
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen);
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
virtual bool Process();
// Effect implementation
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
private:
bool ProcessOne(int count, WaveTrack * t,
sampleCount start, sampleCount len);
private:
// EffectEcho implementation
float delay;
float decay;
friend class EchoDialog;
};
//----------------------------------------------------------------------------
// EchoDialog
//----------------------------------------------------------------------------
class EchoDialog:public EffectDialog {
public:
EchoDialog(EffectEcho * effect, wxWindow * parent);
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
private:
// handlers
void OnPreview( wxCommandEvent &event );
private:
bool m_bLoopDetect;
EffectEcho * m_pEffect;
// controls
wxTextCtrl * m_pTextCtrl_Delay;
wxTextCtrl * m_pTextCtrl_Decay;
public:
// effect parameters
float delay;
float decay;
private:
DECLARE_EVENT_TABLE()
private:
double delay;
double decay;
float *history;
sampleCount histPos;
sampleCount histLen;
};
#endif // __AUDACITY_EFFECT_ECHO__

File diff suppressed because it is too large Load Diff

View File

@ -34,39 +34,20 @@ class wxWindow;
#include "../Internat.h"
#include "../widgets/ProgressDialog.h"
#define BUILTIN_EFFECT_PREFIX wxT("Builtin Effect: ")
class SelectedRegion;
class TimeWarper;
class EffectUIHost;
#define PLUGIN_EFFECT 0x0001
#define BUILTIN_EFFECT 0x0002
// ADVANCED_EFFECT was introduced for Lynn Allan's 'CleanSpeech'
// it allows the list of effects to be filtered to exclude
// the advanced effects.
// Left in when CLEANSPEECH was removed, as it may be useful at some point.
#define ADVANCED_EFFECT 0x0004
// HIDDEN_EFFECT allows an item to be excluded from the effects
// menu
#define HIDDEN_EFFECT 0x0008
// TODO: Apr-06-2015
// TODO: Much more cleanup of old methods and variables is needed, but
// TODO: can't be done until after all effects are using the new API.
#define INSERT_EFFECT 0x0010
#define PROCESS_EFFECT 0x0020
#define ANALYZE_EFFECT 0x0040
#define ALL_EFFECTS 0x00FF
// Flag used to disable prompting for configuration
// parameteres.
#define CONFIGURED_EFFECT 0x8000
//CLEAN-ME: Rogue value to skip unwanted effects in a chain.
//lda: SKIP_EFFECT_MILLISECOND is a rogue value, used where a millisecond
//time is required to indicate "Don't do this effect".
//It is used in SpikeCleaner and TruncSilence.
//MERGE: Maybe we can remove this now that we have configurable batch
//and so can just drop the steps we don't want?
#define SKIP_EFFECT_MILLISECOND 99999
class AUDACITY_DLL_API Effect : public EffectHostInterface
class AUDACITY_DLL_API Effect : public wxEvtHandler,
public EffectClientInterface,
public EffectUIClientInterface,
public EffectHostInterface
{
//
// public methods
@ -99,8 +80,70 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface
virtual bool SupportsRealtime();
virtual bool SupportsAutomation();
// EffectClientInterface implementation
virtual bool SetHost(EffectHostInterface *host);
virtual int GetAudioInCount();
virtual int GetAudioOutCount();
virtual int GetMidiInCount();
virtual int GetMidiOutCount();
virtual sampleCount GetLatency();
virtual sampleCount GetTailSize();
virtual void SetSampleRate(sampleCount rate);
virtual sampleCount SetBlockSize(sampleCount maxBlockSize);
virtual bool IsReady();
virtual bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap = NULL);
virtual bool ProcessFinalize();
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen);
virtual bool RealtimeInitialize();
virtual bool RealtimeAddProcessor(int numChannels, float sampleRate);
virtual bool RealtimeFinalize();
virtual bool RealtimeSuspend();
virtual bool RealtimeResume();
virtual bool RealtimeProcessStart();
virtual sampleCount RealtimeProcess(int group,
float **inbuf,
float **outbuf,
sampleCount numSamples);
virtual bool RealtimeProcessEnd();
virtual bool ShowInterface(wxWindow *parent, bool forceModal = false);
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
virtual bool LoadUserPreset(const wxString & name);
virtual bool SaveUserPreset(const wxString & name);
virtual wxArrayString GetFactoryPresets();
virtual bool LoadFactoryPreset(int id);
virtual bool LoadFactoryDefaults();
// EffectUIClientInterface implementation
virtual void SetHostUI(EffectUIHostInterface *host);
virtual bool PopulateUI(wxWindow *parent);
virtual bool IsGraphicalUI();
virtual bool ValidateUI();
virtual bool HideUI();
virtual bool CloseUI();
virtual bool CanExportPresets();
virtual void ExportPresets();
virtual void ImportPresets();
virtual bool HasOptions();
virtual void ShowOptions();
// EffectHostInterface implementation
virtual double GetDefaultDuration();
virtual double GetDuration();
virtual bool SetDuration(double duration);
@ -156,142 +199,43 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface
// Effect implementation
virtual PluginID GetID();
virtual bool Startup(EffectClientInterface *client);
virtual bool Startup();
virtual bool GetAutomationParameters(wxString & parms);
virtual bool SetAutomationParameters(const wxString & parms);
// Each subclass of Effect should override this method.
// This name will go in the menu bar;
// append "..." if your effect pops up a dialog
virtual wxString GetEffectName();
// Each subclass of Effect should override this method.
// This should return the category of this effect, which
// will determine where in the menu it's placed.
#ifdef EFFECT_CATEGORIES
virtual std::set<wxString> GetEffectCategories() = 0;
#endif
// Previously optional. Now required to identify effects for Chain support.
// Each subclass of Effect should override this method.
// This should be human-readable, but should NOT be translated. Use wxT(""), not _("").
virtual wxString GetEffectIdentifier();
// Each subclass of Effect should override this method.
// This name will go in the progress dialog, but can be used
// elsewhere, and it should describe what is being done.
// For example, if the effect is "Filter", the action is
// "Filtering", or if the effect is "Bass Boost", the action
// is "Boosting Bass Frequencies".
virtual wxString GetEffectAction();
// Each subclass of Effect should override this method.
// This description will go in the History state.
// Override to include effect parameters, so typically useful only after PromptUser.
virtual wxString GetEffectDescription() {
// Default provides effect name.
return wxString::Format(_("Applied effect: %s"),
this->GetEffectName().c_str());
}
// Return flags which tell you what kind of effect this is.
// It will be either a built-in or a plug-in effect, and it
// will be one of Insert, Process, or Analyze.
virtual int GetEffectFlags() {
// Default of BUILTIN_EFFECT | PROCESS_EFFECT | ADVANCED_EFFECT (set in constructor) -
// covers most built-in effects.
return mFlags;
}
// Return true if the effect supports processing via batch chains.
virtual bool SupportsChains() {
// All builtin effect support chains (???)
return (mFlags & BUILTIN_EFFECT) != 0;
}
// Preview normally requires a selection, but INSERT_EFFECTs do not.
// Return true to override the need for a selection.
virtual bool GeneratorPreview(){
return false;
}
// Called to set or retrieve parameter values. Return true if successful.
virtual bool TransferParameters( Shuttle & WXUNUSED(shuttle) ) {
return true;
}
void SetPresetParameters( const wxArrayString * Names, const wxArrayString * Values ){
if( Names ) mPresetNames = *Names;
if( Values ) mPresetValues = *Values;
}
void SetEffectFlags( int NewFlags )
{
mFlags = NewFlags;
}
// The Effect class fully implements the Preview method for you.
// Only override it if you need to do preprocessing or cleanup.
virtual void Preview(bool dryOnly);
// Most effects just use the previewLength, but time-stretching/compressing
// effects need to use a different input length, so override this method.
virtual double CalcPreviewInputLength(double previewLength);
// Get an unique ID assigned to each registered effect.
// The first effect will have ID zero.
int GetEffectID() {
return mEffectID;
}
// Set an unique ID assigned to each registered effect.
void SetEffectID(int id) {
mEffectID = id;
}
// Returns true on success. Will only operate on tracks that
// have the "selected" flag set to true, which is consistent with
// Audacity's standard UI.
bool DoEffect(wxWindow *parent, int flags, double projectRate, TrackList *list,
bool DoEffect(wxWindow *parent, double projectRate, TrackList *list,
TrackFactory *factory, SelectedRegion *selectedRegion,
wxString params);
wxString GetPreviewName();
//ANSWER-ME: Isn't this pointless?
// None of the built-in functions has an ampersand in the result of
// GetEffectName(), the only strings on which this method is used.
// In fact, the example 'E&qualizer' does not exist in the code!
// Strip ampersand ('&' char) from string. This effectively removes the
// shortcut from the string ('E&qualizer' becomes 'Equalizer'). This is
// important for sorting.
static wxString StripAmpersand(const wxString& str);
int GetAudioInCount();
int GetAudioOutCount();
bool shouldPrompt = true);
// Realtime Effect Processing
bool RealtimeInitialize();
bool RealtimeAddProcessor(int group, int chans, float rate);
bool RealtimeFinalize();
bool RealtimeSuspend();
bool RealtimeResume();
bool RealtimeProcessStart();
sampleCount RealtimeProcess(int group,
int chans,
float **inbuf,
float **outbuf,
sampleCount numSamples);
bool RealtimeProcessEnd();
bool IsRealtimeActive();
//
// protected virtual methods
//
// Each subclass of Effect overrides one or more of these methods to
// do its processing.
//
protected:
virtual bool IsHidden();
//
// protected virtual methods
//
// Each subclass of Effect overrides one or more of these methods to
// do its processing.
//
protected:
// Called once each time an effect is called. Perform any initialization;
// make sure that the effect can be performed on the selected tracks and
// return false otherwise
@ -301,8 +245,7 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface
// This method will not always be called (for example if a user
// repeats an effect) but if it is called, it will be called
// after Init.
virtual bool PromptUser();
virtual bool PromptUser(wxWindow *parent, bool forceModal = false);
virtual bool PromptUser(wxWindow *parent = NULL, bool isBatch = false);
// Check whether effect should be skipped
// Typically this is only useful in automation, for example
@ -313,42 +256,28 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface
// Actually do the effect here.
virtual bool Process();
virtual bool ProcessPass();
virtual bool InitPass1();
virtual bool InitPass2();
virtual int GetPass();
// clean up any temporary memory
virtual void End();
//
// protected data
//
// The Effect base class will set these variables, some or all of which
// may be needed by any particular subclass of Effect.
//
protected:
wxWindow *mParent;
ProgressDialog *mProgress;
double mProjectRate; // Sample rate of the project - new tracks should
// be created with this rate...
TrackFactory *mFactory;
TrackList *mTracks; // the complete list of all tracks
TrackList *mOutputTracks; // used only if CopyInputTracks() is called.
double mT0;
double mT1;
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
double mF0;
double mF1;
#endif
TimeWarper *mWarper;
wxArrayString mPresetNames;
wxArrayString mPresetValues;
// Most effects just use the previewLength, but time-stretching/compressing
// effects need to use a different input length, so override this method.
virtual double CalcPreviewInputLength(double previewLength);
// The Effect class fully implements the Preview method for you.
// Only override it if you need to do preprocessing or cleanup.
virtual void Preview(bool dryOnly);
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
virtual bool EnableApply(bool enable = true);
virtual bool EnablePreview(bool enable = true);
//
// protected methods
//
// These methods can be used by subclasses of Effect in order to display a
// progress dialog or perform common calculations
//
protected:
// The Progress methods all return true if the user has cancelled;
// you should exit immediately if this happens (cleaning up memory
// is okay, but don't try to undo).
@ -374,22 +303,6 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface
void SetTimeWarper(TimeWarper *warper);
TimeWarper *GetTimeWarper();
//
// protected static data
//
// Preferences shared by all effects
//
protected:
static double sDefaultGenerateLen;
int mFlags;
double mDuration;
// type of the tracks on mOutputTracks
int mOutputTracksType;
//
// private methods
//
// Use these two methods to copy the input tracks to mOutputTracks, if
// doing the processing on them, and replacing the originals only on success (and not cancel).
void CopyInputTracks(int trackType = Track::Wave);
@ -402,6 +315,41 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface
// Use this to append a new output track.
void AddToOutputTracks(Track *t);
//
// protected data
//
// The Effect base class will set these variables, some or all of which
// may be needed by any particular subclass of Effect.
//
protected:
ProgressDialog *mProgress;
double mProjectRate; // Sample rate of the project - new tracks should
// be created with this rate...
double mSampleRate;
TrackFactory *mFactory;
TrackList *mTracks; // the complete list of all tracks
TrackList *mOutputTracks; // used only if CopyInputTracks() is called.
double mT0;
double mT1;
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
double mF0;
double mF1;
#endif
TimeWarper *mWarper;
wxArrayString mPresetNames;
wxArrayString mPresetValues;
int mPass;
// UI
wxDialog *mUIDialog;
wxWindow *mUIParent;
double mDuration;
sampleCount mSampleCnt;
// type of the tracks on mOutputTracks
int mOutputTracksType;
// Used only by the base Effect class
//
private:
@ -410,6 +358,7 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface
// Driver for client effects
bool ProcessTrack(int count,
ChannelNames map,
WaveTrack *left,
WaveTrack *right,
sampleCount leftStart,
@ -421,15 +370,15 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface
//
// Used only by the base Effect class
//
private:
private:
wxWindow *mParent;
wxArrayPtrVoid mIMap;
wxArrayPtrVoid mOMap;
int mNumTracks; //v This is really mNumWaveTracks, per CountWaveTracks() and GetNumWaveTracks().
int mNumGroups;
int mEffectID;
// For client driver
EffectClientInterface *mClient;
int mNumAudioIn;
@ -452,9 +401,13 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface
friend class EffectManager;// so it can call PromptUser in support of batch commands.
friend class EffectRack;
friend class EffectUIHost;
};
// Base dialog for generate effect
// FIXME:
// FIXME: Remove this once all effects are using the new dialog
// FIXME:
#define ID_EFFECT_PREVIEW ePreviewID
@ -465,7 +418,7 @@ public:
// constructors and destructors
EffectDialog(wxWindow * parent,
const wxString & title,
int type = PROCESS_EFFECT,
int type = 0,
int flags = wxDEFAULT_DIALOG_STYLE,
int additionalButtons = 0);
@ -475,8 +428,8 @@ public:
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
virtual bool Validate();
virtual void OnPreview(wxCommandEvent & event);
virtual void OnOk(wxCommandEvent & event);
virtual void OnPreview(wxCommandEvent & evt);
virtual void OnOk(wxCommandEvent & evt);
private:
int mType;
@ -485,8 +438,6 @@ private:
DECLARE_EVENT_TABLE();
};
WX_DECLARE_OBJARRAY(wxAcceleratorEntry, AccelArray);
//
class EffectUIHost : public wxDialog,
public EffectUIHostInterface
@ -498,9 +449,22 @@ public:
EffectUIClientInterface *client);
virtual ~EffectUIHost();
#if defined(__WXMAC__)
virtual bool Show(bool show = true);
#endif
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
#if defined(__WXMAC__)
virtual int ShowModal();
#endif
bool Initialize();
private:
void OnErase(wxEraseEvent & evt);
void OnPaint(wxPaintEvent & evt);
void OnClose(wxCloseEvent & evt);
void OnApply(wxCommandEvent & evt);
void OnCancel(wxCommandEvent & evt);
@ -524,6 +488,9 @@ private:
wxBitmap CreateBitmap(const char *xpm[], bool up, bool pusher);
void LoadUserPresets();
void InitializeRealtime();
void CleanupRealtime();
private:
AudacityProject *mProject;
wxWindow *mParent;
@ -532,9 +499,13 @@ private:
wxArrayString mUserPresets;
bool mInitialized;
bool mSupportsRealtime;
bool mIsGUI;
#if defined(__WXMAC__)
bool mIsModal;
#endif
wxButton *mApplyBtn;
wxButton *mCloseBtn;
wxButton *mMenuBtn;
@ -560,15 +531,85 @@ private:
SelectedRegion mRegion;
double mPlayPos;
AccelArray mAccels;
DECLARE_EVENT_TABLE();
};
// Utility functions
float TrapFloat(float x, float min, float max);
double TrapDouble(double x, double min, double max);
long TrapLong(long x, long min, long max);
inline float TrapFloat(float x, float min, float max)
{
if (x <= min)
return min;
if (x >= max)
return max;
return x;
}
inline double TrapDouble(double x, double min, double max)
{
if (x <= min)
return min;
if (x >= max)
return max;
return x;
}
inline long TrapLong(long x, long min, long max)
{
if (x <= min)
return min;
if (x >= max)
return max;
return x;
}
// Helper macros for defining, reading and verifying effect parameters
#define Param(name, type, key, def, min, max, scale) \
static const wxChar * KEY_ ## name = (key); \
static const type DEF_ ## name = (def); \
static const type MIN_ ## name = (min); \
static const type MAX_ ## name = (max); \
static const type SCL_ ## name = (scale);
#define PBasic(name, type, key, def) \
static const wxChar * KEY_ ## name = (key); \
static const type DEF_ ## name = (def);
#define PRange(name, type, key, def, min, max) \
PBasic(name, type, key, def); \
static const type MIN_ ## name = (min); \
static const type MAX_ ## name = (max);
#define PScale(name, type, key, def, min, max, scale) \
PRange(name, type, key, def, min, max); \
static const type SCL_ ## name = (scale);
#define ReadParam(type, name) \
type name; \
if (!parms.ReadAndVerify(KEY_ ## name, &name, DEF_ ## name, MIN_ ## name, MAX_ ## name)) \
return false;
#define ReadBasic(type, name) \
type name; \
if (!parms.ReadAndVerify(KEY_ ## name, &name, DEF_ ## name)) \
return false;
#define ReadAndVerifyEnum(name, list) \
int name; \
if (!parms.ReadAndVerify(KEY_ ## name, &name, DEF_ ## name, list)) \
return false;
#define ReadAndVerifyInt(name) ReadParam(int, name)
#define ReadAndVerifyDouble(name) ReadParam(double, name)
#define ReadAndVerifyFloat(name) ReadParam(float, name)
#define ReadAndVerifyBool(name) ReadBasic(bool, name)
#define ReadAndVerifyString(name) ReadBasic(wxString, name)
#endif

View File

@ -1,100 +0,0 @@
/**********************************************************************
Audacity: A Digital Audio Editor
EffectCategory.cpp
Audacity(R) is copyright (c) 1999-2008 Audacity Team.
License: GPL v2. See License.txt.
**********************************************************************/
#include "../Audacity.h"
#include "Effect.h"
#include "EffectCategory.h"
EffectCategory::EffectCategory(const wxString& uri, const wxString& name)
: mUri(uri),
mName(name),
mParentsFrozen(false) {
}
const wxString& EffectCategory::GetUri() const {
return mUri;
}
const wxString& EffectCategory::GetName() const {
return mName;
}
const CategorySet& EffectCategory::GetParents() const {
return mParents;
}
const CategorySet& EffectCategory::GetSubCategories() const {
return mSubCategories;
}
EffectSet EffectCategory::GetEffects(int type) const {
EffectSet result;
EffectSet::const_iterator iter;
for (iter = mEffects.begin(); iter != mEffects.end(); ++iter) {
int g = (*iter)->GetEffectFlags();
if ((g & type) == g)
result.insert(*iter);
}
return result;
}
// Return all the effects that belong to this immediate category or any
// of its subcategories), filtered by effect type.
EffectSet EffectCategory::GetAllEffects(int type) const {
EffectSet result = GetEffects(type);
CategorySet::const_iterator iter;
for (iter = mSubCategories.begin(); iter != mSubCategories.end(); ++iter) {
EffectSet tmp = (*iter)->GetAllEffects(type);
EffectSet::const_iterator itr2;
for (itr2 = tmp.begin(); itr2 != tmp.end(); ++itr2)
result.insert(*itr2);
}
return result;
}
bool EffectCategory::AddParent(EffectCategory* parent) {
if (mParentsFrozen)
return false;
if (parent->IsDescendantOf(this))
return false;
mParents.insert(parent);
parent->mSubCategories.insert(this);
return true;
}
bool EffectCategory::AddEffect(Effect* effect) {
mEffects.insert(effect);
return true;
}
void EffectCategory::FreezeParents() {
mParentsFrozen = true;
}
void EffectCategory::UnfreezeParents() {
mParentsFrozen = false;
}
bool EffectCategory::IsDescendantOf(EffectCategory* category) {
if (category == this)
return true;
CategorySet::const_iterator iter;
for (iter = mParents.begin(); iter != mParents.end(); ++iter) {
if ((*iter)->IsDescendantOf(category))
return true;
}
return false;
}

View File

@ -1,139 +0,0 @@
/**********************************************************************
Audacity: A Digital Audio Editor
EffectCategory.h
Audacity(R) is copyright (c) 1999-2008 Audacity Team.
License: GPL v2. See License.txt.
******************************************************************//**
\class EffectCategory
\brief EffectManager contains all the information about an effect category.
That includes links to parent categories and subcategories, name and
URI, and of course the effects that belong to this category.
*//*******************************************************************/
#ifndef __AUDACITY_EFFECTCATEGORY__
#define __AUDACITY_EFFECTCATEGORY__
#include <set>
#include <wx/string.h>
#include "Effect.h"
class EffectCategory {
public:
/** This is used in the EffectSet typedef. It compares effect pointers,
first by their names and then by pointer values. This makes EffectSets
automatically sorted by name while allowing for different effects with
the same name. */
struct CompareEffects {
bool operator()(Effect* a, Effect* b) const {
return (a->GetEffectName() < b->GetEffectName()) ||
((a->GetEffectName() == b->GetEffectName()) && (a < b));
}
};
typedef std::set<Effect*, CompareEffects> EffectSet;
/** This is used in the CategorySet typedef. It compares category pointers,
first by their names and then by pointer values. This makes CategorySets
automatically sorted by name while allowing for different categories
with the same name. */
struct CompareCategories {
bool operator()(const EffectCategory* a, const EffectCategory* b) const {
return (a->GetName() < b->GetName()) ||
((a->GetName() == b->GetName()) && (a < b));
}
};
typedef std::set<EffectCategory*, CompareCategories> CategorySet;
/** Return the URI for this category, which is used as a global, persistent
string identifier for the category. */
const wxString& GetUri() const;
/** Return the (possibly i18n'd) name for the category. */
const wxString& GetName() const;
/** Return all the parent categories of this category. A category may
have 0, 1 or more parents - the structure of all categories forms
a DAG, not necessarily a tree, since LV2 allows for categories to
have multiple parents (e.g. Reverb is a subcategory of both Simulator
and Delay). */
const CategorySet& GetParents() const;
/** Return all the subcategories of this category. A category may have 0, 1
or more subcategories. */
const CategorySet& GetSubCategories() const;
/** Return all the effects that belong to this immediate category (not any
of its subcategories), filtered by effect type. */
EffectSet GetEffects(int type = ALL_EFFECTS) const;
/** Return all the effects that belong to this immediate category or any
of its subcategories), filtered by effect type. */
EffectSet GetAllEffects(int type = ALL_EFFECTS) const;
protected:
/** All constructors and destructors are non-public, allowing only
EffectManager (which is our friend) to create new categories. */
EffectCategory(const wxString& uri, const wxString& name);
/** Add a new parent category to this category, making this a subcategory of
the parent. Returns true if the parent was added (or already had been
added), false if the parent could not be added because FreezeParents()
has been called. This is protected so only our friend EffectManager
can change the category graph (it needs to keep track of root nodes). */
bool AddParent(EffectCategory* parent);
/** Add an effect to this category. This is protected so only our friend
EffectManager can call it. */
bool AddEffect(Effect* effect);
/** This function sets a flag that makes AddParent() fail when called for
this category object, preventing anyone from adding new parents to
this category. This is useful if you are mapping a different category
tree onto the already existing one (e.g. LRDF onto LV2) and don't
want to add more internal parent/subcategory relations between already
existing categories, but still want to allow adding of completely
new, unmapped subcategories. */
void FreezeParents();
/** Reset the flag set by FreezeParents(), allowing to add parent categories
again. */
void UnfreezeParents();
/** Returns true if category is an ancestor of this category, false
if not. */
bool IsDescendantOf(EffectCategory* category);
friend class EffectManager;
wxString mUri;
wxString mName;
CategorySet mParents;
CategorySet mSubCategories;
EffectSet mEffects;
bool mParentsFrozen;
};
// Add these in the global namespace to reduce typing
typedef EffectCategory::EffectSet EffectSet;
typedef EffectCategory::CategorySet CategorySet;
#endif

View File

@ -37,153 +37,11 @@ EffectManager & EffectManager::Get()
EffectManager::EffectManager()
{
#ifdef EFFECT_CATEGORIES
mCategories = new CategoryMap();
mRootCategories = new CategorySet();
mUnsorted = new EffectSet();
// Create effect category graph. These categories and relationships
// are taken from revision 2 of lv2.ttl, loaders for other plugin systems
// (such as LADSPA/LRDF) should map their categories to these ones when
// applicable. Individual LADSPA/LRDF and LV2 plugins can add new
// categories and make them subcategories of the existing ones, but not
// add subcategory relationships between these categories.
//
// We need some persistent, global identifiers for categories - LRDF
// and LV2 uses URI strings so we do that too. The URIs here are the
// same ones as in lv2.ttl. Category identifiers in other plugin systems
// must be mapped to URIs by their loaders.
#define LV2PREFIX "http://lv2plug.in/ns/lv2core#"
typedef EffectCategory* CatPtr;
CatPtr gen = AddCategory(wxT(LV2PREFIX) wxT("GeneratorPlugin"),
_("Generator"));
CatPtr inst = AddCategory(wxT(LV2PREFIX) wxT("InstrumentPlugin"),
/* i18n-hint: (noun).*/
_("Instrument"));
CatPtr osc = AddCategory(wxT(LV2PREFIX) wxT("OscillatorPlugin"),
_("Oscillator"));
CatPtr util = AddCategory(wxT(LV2PREFIX) wxT("UtilityPlugin"),
_("Utility"));
CatPtr conv = AddCategory(wxT(LV2PREFIX) wxT("ConverterPlugin"),
_("Converter"));
CatPtr anal = AddCategory(wxT(LV2PREFIX) wxT("AnalyserPlugin"),
_("Analyser"));
CatPtr mix = AddCategory(wxT(LV2PREFIX) wxT("MixerPlugin"),
_("Mixer"));
CatPtr sim = AddCategory(wxT(LV2PREFIX) wxT("SimulatorPlugin"),
_("Simulator"));
CatPtr del = AddCategory(wxT(LV2PREFIX) wxT("DelayPlugin"),
_("Delay"));
CatPtr mod = AddCategory(wxT(LV2PREFIX) wxT("ModulatorPlugin"),
_("Modulator"));
CatPtr rev = AddCategory(wxT(LV2PREFIX) wxT("ReverbPlugin"),
_("Reverb"));
CatPtr phas = AddCategory(wxT(LV2PREFIX) wxT("PhaserPlugin"),
_("Phaser"));
CatPtr flng = AddCategory(wxT(LV2PREFIX) wxT("FlangerPlugin"),
_("Flanger"));
CatPtr chor = AddCategory(wxT(LV2PREFIX) wxT("ChorusPlugin"),
_("Chorus"));
CatPtr flt = AddCategory(wxT(LV2PREFIX) wxT("FilterPlugin"),
_("Filter"));
CatPtr lp = AddCategory(wxT(LV2PREFIX) wxT("LowpassPlugin"),
_("Lowpass"));
CatPtr bp = AddCategory(wxT(LV2PREFIX) wxT("BandpassPlugin"),
_("Bandpass"));
CatPtr hp = AddCategory(wxT(LV2PREFIX) wxT("HighpassPlugin"),
_("Highpass"));
CatPtr comb = AddCategory(wxT(LV2PREFIX) wxT("CombPlugin"),
_("Comb"));
CatPtr alp = AddCategory(wxT(LV2PREFIX) wxT("AllpassPlugin"),
_("Allpass"));
CatPtr eq = AddCategory(wxT(LV2PREFIX) wxT("EQPlugin"),
_("Equaliser"));
CatPtr peq = AddCategory(wxT(LV2PREFIX) wxT("ParaEQPlugin"),
_("Parametric"));
CatPtr meq = AddCategory(wxT(LV2PREFIX) wxT("MultiEQPlugin"),
_("Multiband"));
CatPtr spec = AddCategory(wxT(LV2PREFIX) wxT("SpectralPlugin"),
_("Spectral Processor"));
CatPtr ptch = AddCategory(wxT(LV2PREFIX) wxT("PitchPlugin"),
_("Pitch Shifter"));
CatPtr amp = AddCategory(wxT(LV2PREFIX) wxT("AmplifierPlugin"),
_("Amplifier"));
CatPtr dist = AddCategory(wxT(LV2PREFIX) wxT("DistortionPlugin"),
_("Distortion"));
CatPtr shp = AddCategory(wxT(LV2PREFIX) wxT("WaveshaperPlugin"),
_("Waveshaper"));
CatPtr dyn = AddCategory(wxT(LV2PREFIX) wxT("DynamicsPlugin"),
_("Dynamics Processor"));
CatPtr cmp = AddCategory(wxT(LV2PREFIX) wxT("CompressorPlugin"),
_("Compressor"));
CatPtr exp = AddCategory(wxT(LV2PREFIX) wxT("ExpanderPlugin"),
_("Expander"));
CatPtr lim = AddCategory(wxT(LV2PREFIX) wxT("LimiterPlugin"),
_("Limiter"));
CatPtr gate = AddCategory(wxT(LV2PREFIX) wxT("GatePlugin"),
_("Gate"));
AddCategoryParent(inst, gen);
AddCategoryParent(osc, gen);
AddCategoryParent(conv, util);
AddCategoryParent(anal, util);
AddCategoryParent(mix, util);
AddCategoryParent(rev, sim);
AddCategoryParent(rev, del);
AddCategoryParent(phas, mod);
AddCategoryParent(flng, mod);
AddCategoryParent(chor, mod);
AddCategoryParent(lp, flt);
AddCategoryParent(bp, flt);
AddCategoryParent(hp, flt);
AddCategoryParent(comb, flt);
AddCategoryParent(alp, flt);
AddCategoryParent(eq, flt);
AddCategoryParent(peq, eq);
AddCategoryParent(meq, eq);
AddCategoryParent(ptch, spec);
AddCategoryParent(shp, dist);
AddCategoryParent(cmp, dyn);
AddCategoryParent(exp, dyn);
AddCategoryParent(lim, dyn);
AddCategoryParent(gate, dyn);
// We also add a couple of categories for internal use. These are not
// in lv2.ttl.
#define ATEAM "http://audacityteam.org/namespace#"
CatPtr nrm = AddCategory(wxT(ATEAM) wxT("NoiseRemoval"),
_("Noise Removal"));
CatPtr pnt = AddCategory(wxT(ATEAM) wxT("PitchAndTempo"),
_("Pitch and Tempo"));
CatPtr tim = AddCategory(wxT(ATEAM) wxT("TimelineChanger"),
_("Timeline Changer"));
CatPtr aTim = AddCategory(wxT(ATEAM) wxT("TimeAnalyser"),
_("Time"));
CatPtr onst = AddCategory(wxT(ATEAM) wxT("OnsetDetector"),
_("Onsets"));
AddCategoryParent(nrm, util);
AddCategoryParent(tim, util);
AddCategoryParent(aTim, anal);
AddCategoryParent(onst, aTim);
// We freeze the internal subcategory relations between the categories
// added so far so LADSPA/LRDF or other category systems don't ruin
// our hierarchy.
FreezeCategories();
#endif
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
mRealtimeLock.Enter();
mRealtimeActive = false;
mRealtimeSuspended = true;
mRealtimeLatency = 0;
mRealtimeLock.Leave();
#endif
#if defined(EXPERIMENTAL_EFFECTS_RACK)
mRack = NULL;
@ -192,90 +50,35 @@ EffectManager::EffectManager()
EffectManager::~EffectManager()
{
#ifdef EFFECT_CATEGORIES
CategoryMap::iterator i;
for (i = mCategories->begin(); i != mCategories->end(); ++i)
delete i->second;
delete mUnsorted;
delete mRootCategories;
delete mCategories;
#endif
#if defined(EXPERIMENTAL_EFFECTS_RACK)
// wxWidgets has already destroyed the rack since it was derived from wxFrame. So
// no need to delete it here.
#endif
EffectMap::iterator iter = mEffects.begin();
while (iter != mEffects.end())
EffectMap::iterator iter = mHostEffects.begin();
while (iter != mHostEffects.end())
{
delete iter->second;
iter++;
}
}
void EffectManager::RegisterEffect(ModuleInterface *p, Effect *f, int NewFlags)
// Here solely for the purpose of Nyquist Workbench until
// a better solution is devised.
void EffectManager::RegisterEffect(Effect *f)
{
f->SetEffectID(mNumEffects++);
if( NewFlags != 0)
{
f->SetEffectFlags( NewFlags );
}
mEffects[PluginManager::Get().RegisterEffectPlugin(p, f)] = f;
}
void EffectManager::RegisterEffect(Effect *f, int NewFlags)
{
f->SetEffectID(mNumEffects++);
if( NewFlags != 0)
{
f->SetEffectFlags( NewFlags );
}
// This will go away after all effects have been converted
mEffects[PluginManager::Get().RegisterLegacyEffectPlugin(f)] = f;
#ifdef EFFECT_CATEGORIES
// Add the effect in the right categories
std::set<wxString> catUris = f->GetEffectCategories();
bool oneValid = false;
std::set<wxString>::const_iterator iter;
for (iter = catUris.begin(); iter != catUris.end(); ++iter) {
EffectCategory* cat = LookupCategory(*iter);
if (cat != 0) {
cat->AddEffect(f);
oneValid = true;
}
}
if (!oneValid)
mUnsorted->insert(f);
#endif
}
void EffectManager::UnregisterEffects()
{
#ifdef EFFECT_CATEGORIES
mUnsorted->clear();
CategoryMap::iterator iter;
for (iter = mCategories->begin(); iter != mCategories->end(); ++iter)
iter->second->mEffects.clear();
#endif
mEffects[PluginManager::Get().RegisterPlugin(f)] = f;
}
bool EffectManager::DoEffect(const PluginID & ID,
wxWindow *parent,
int flags,
double projectRate,
TrackList *list,
TrackFactory *factory,
SelectedRegion *selectedRegion,
wxString params)
bool shouldPrompt /* = true */)
{
Effect *effect = GetEffect(ID);
@ -284,7 +87,7 @@ bool EffectManager::DoEffect(const PluginID & ID,
return false;
}
#if defined(EXPERIMENTAL_REALTIME_EFFECTS) && defined(EXPERIMENTAL_EFFECTS_RACK)
#if defined(EXPERIMENTAL_EFFECTS_RACK)
if (effect->SupportsRealtime())
{
GetRack()->Add(effect);
@ -292,12 +95,11 @@ bool EffectManager::DoEffect(const PluginID & ID,
#endif
return effect->DoEffect(parent,
flags,
projectRate,
list,
factory,
selectedRegion,
params);
shouldPrompt);
}
wxString EffectManager::GetEffectName(const PluginID & ID)
@ -337,7 +139,7 @@ wxString EffectManager::GetEffectDescription(const PluginID & ID)
if (effect)
{
return effect->GetEffectDescription();
return wxString::Format(_("Applied effect: %s"), effect->GetName().c_str());
}
return wxEmptyString;
@ -484,7 +286,6 @@ void EffectManager::RealtimeSetEffects(const EffectArray & effects)
}
#endif
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
bool EffectManager::RealtimeIsActive()
{
return mRealtimeEffects.GetCount() != 0;
@ -538,8 +339,6 @@ void EffectManager::RealtimeRemoveEffect(Effect *effect)
RealtimeResume();
}
#endif
void EffectManager::RealtimeInitialize()
{
// The audio thread should not be running yet, but protect anyway
@ -772,29 +571,31 @@ int EffectManager::GetRealtimeLatency()
Effect *EffectManager::GetEffect(const PluginID & ID)
{
Effect *effect;
// TODO: This is temporary and should be redone when all effects are converted
if (mEffects.find(ID) == mEffects.end())
{
Effect *effect;
// This will instantiate the effect client if it hasn't already been done
EffectIdentInterface *ident = dynamic_cast<EffectIdentInterface *>(PluginManager::Get().GetInstance(ID));
if (ident && ident->IsLegacy())
{
effect = dynamic_cast<Effect *>(ident);
effect->SetEffectID(mNumEffects++);
mEffects[ID] = effect;
return effect;
if (effect && effect->Startup(NULL))
{
mEffects[ID] = effect;
return effect;
}
}
effect = new Effect();
if (effect)
{
// This will instantiate the effect client if it hasn't already been done
EffectClientInterface *client = dynamic_cast<EffectClientInterface *>(ident);
if (client && effect->Startup(client))
{
effect->SetEffectID(mNumEffects++);
mEffects[ID] = effect;
mHostEffects[ID] = effect;
return effect;
}
@ -832,63 +633,3 @@ const PluginID & EffectManager::GetEffectByIdentifier(const wxString & strTarget
return empty;;
}
#ifdef EFFECT_CATEGORIES
EffectCategory* EffectManager::AddCategory(const wxString& URI,
const wxString& name) {
CategoryMap::const_iterator iter = mCategories->find(URI);
if (iter != mCategories->end())
return iter->second;
EffectCategory* cat = new EffectCategory(URI, name);
mCategories->insert(std::make_pair(URI, cat));
mRootCategories->insert(cat);
return cat;
}
EffectCategory* EffectManager::LookupCategory(const wxString& URI) {
CategoryMap::const_iterator iter = mCategories->find(URI);
if (iter != mCategories->end())
return iter->second;
return 0;
}
bool EffectManager::AddCategoryParent(EffectCategory* child,
EffectCategory* parent) {
bool result = child->AddParent(parent);
if (!result)
return false;
CategorySet::iterator iter = mRootCategories->find(child);
if (iter != mRootCategories->end())
mRootCategories->erase(iter);
return true;
}
void EffectManager::FreezeCategories() {
CategoryMap::iterator iter;
for (iter = mCategories->begin(); iter != mCategories->end(); ++iter)
iter->second->FreezeParents();
}
const CategorySet& EffectManager::GetRootCategories() const {
return *mRootCategories;
}
EffectSet EffectManager::GetUnsortedEffects(int flags) const {
if (flags == ALL_EFFECTS)
return *mUnsorted;
EffectSet result;
EffectSet::const_iterator iter;
for (iter = mUnsorted->begin(); iter != mUnsorted->end(); ++iter) {
int g = (*iter)->GetEffectFlags();
if ((flags & g) == g)
result.insert(*iter);
}
return result;
}
#endif

View File

@ -21,18 +21,10 @@ effects.
#ifndef __AUDACITY_EFFECTMANAGER__
#define __AUDACITY_EFFECTMANAGER__
#include <map>
#include <string>
#include <vector>
#include "audacity/EffectInterface.h"
#include "../PluginManager.h"
#include "Effect.h"
#ifdef EFFECT_CATEGORIES
#include "EffectCategory.h"
#endif
WX_DEFINE_USER_EXPORTED_ARRAY(Effect *, EffectArray, class AUDACITY_DLL_API);
WX_DECLARE_STRING_HASH_MAP_WITH_DECL(Effect *, EffectMap, class AUDACITY_DLL_API);
@ -42,35 +34,26 @@ class EffectRack;
class AUDACITY_DLL_API EffectManager
{
#if defined(EXPERIMENTAL_EFFECTS_RACK)
friend class EffectRack;
#endif
public:
public:
/** Get the singleton instance of the EffectManager. Probably not safe
for multi-thread use. */
static EffectManager& Get();
//
// public methods
//
// Used by the outside program to register the list of effects and retrieve
// them by index number, usually when the user selects one from a menu.
//
public:
static EffectManager & Get();
//
// public methods
//
// Used by the outside program to register the list of effects and retrieve
// them by index number, usually when the user selects one from a menu.
//
public:
EffectManager();
virtual ~EffectManager();
/** A destructor is needed so we can delete all categories. */
~EffectManager();
/** Register an effect so it will appear in the menu. */
void RegisterEffect(Effect *f, int AdditionalFlags=0);
void RegisterEffect(ModuleInterface *p, Effect *f, int AdditionalFlags=0);
/** Unregister all effects. */
void UnregisterEffects();
/** Register an effect so it can be executed. */
// Here solely for the purpose of Nyquist Workbench until
// a better solution is devised.
void RegisterEffect(Effect *f);
/** Run an effect given the plugin ID */
// Returns true on success. Will only operate on tracks that
@ -78,12 +61,11 @@ class AUDACITY_DLL_API EffectManager
// Audacity's standard UI.
bool DoEffect(const PluginID & ID,
wxWindow *parent,
int flags,
double projectRate,
TrackList *list,
TrackFactory *factory,
SelectedRegion *selectedRegion,
wxString params);
bool shouldPrompt = true);
wxString GetEffectName(const PluginID & ID);
wxString GetEffectIdentifier(const PluginID & ID);
@ -95,7 +77,6 @@ class AUDACITY_DLL_API EffectManager
bool SetEffectParameters(const PluginID & ID, const wxString & params);
bool PromptUser(const PluginID & ID, wxWindow *parent);
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
// Realtime effect processing
bool RealtimeIsActive();
bool RealtimeIsSuspended();
@ -111,7 +92,6 @@ class AUDACITY_DLL_API EffectManager
sampleCount RealtimeProcess(int group, int chans, float **buffers, sampleCount numSamples);
void RealtimeProcessEnd();
int GetRealtimeLatency();
#endif
#if defined(EXPERIMENTAL_EFFECTS_RACK)
void ShowRack();
@ -119,37 +99,7 @@ class AUDACITY_DLL_API EffectManager
const PluginID & GetEffectByIdentifier(const wxString & strTarget);
#ifdef EFFECT_CATEGORIES
/** Add a new effect category with the given URI and name and
return a pointer to it. If a category with this URI already
exists, return that instead. */
EffectCategory* AddCategory(const wxString& URI,
const wxString& name);
/** Return a pointer to the effect category with the given URI
or 0 if no such category has been added. */
EffectCategory* LookupCategory(const wxString& URI);
/** Make one category the parent of another category. Both categories
must have been returned from AddCategory() or LookupCategory().
If the new parent-child relationship would create any loops
in the graph of categories false will be returned and the graph
will not be modified, otherwise the function will return true. */
bool AddCategoryParent(EffectCategory* child, EffectCategory* parent);
/** Freeze the subcategory relations between all categories added so far. */
void FreezeCategories();
/** Return the set of all root categories, i.e. the ones without parents. */
const CategorySet& GetRootCategories() const;
/** Return the set of all uncategorised effects. */
EffectSet GetUnsortedEffects(int flags = ALL_EFFECTS) const;
#endif
private:
private:
/** Return an effect by its ID. */
Effect *GetEffect(const PluginID & ID);
@ -159,14 +109,10 @@ class AUDACITY_DLL_API EffectManager
private:
EffectMap mEffects;
EffectMap mHostEffects;
int mNumEffects;
#if defined(EXPERIMENTAL_EFFECTS_RACK)
EffectRack *mRack;
#endif
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
wxCriticalSection mRealtimeLock;
EffectArray mRealtimeEffects;
int mRealtimeLatency;
@ -174,20 +120,11 @@ private:
bool mRealtimeActive;
wxArrayInt mRealtimeChans;
wxArrayDouble mRealtimeRates;
#endif
#ifdef EFFECT_CATEGORIES
// This maps URIs to EffectCategory pointers for all added categories.
// It is needed for fast lookup and easy deletion.
typedef std::map<wxString, EffectCategory*> CategoryMap;
CategoryMap *mCategories;
#if defined(EXPERIMENTAL_EFFECTS_RACK)
EffectRack *mRack;
// These are the root categories, i.e. the ones without parents.
CategorySet *mRootCategories;
// Special category that all effects with unknown category URIs
// are placed in.
EffectSet *mUnsorted;
friend class EffectRack;
#endif
};

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,10 @@
#include "../widgets/Ruler.h"
#include "../RealFFTf.h"
class EqualizationDialog;
#define EQUALIZATION_PLUGIN_SYMBOL wxTRANSLATE("Equalization")
class EqualizationPanel;
//
// One point in a curve
@ -67,7 +70,7 @@ WX_DECLARE_OBJARRAY( EQPoint, EQPointArray);
class EQCurve
{
public:
EQCurve( const wxString & name ) { Name = name; }
EQCurve( const wxString & name = wxEmptyString ) { Name = name; }
EQCurve( const wxChar * name ) { Name = name; }
wxString Name;
EQPointArray points;
@ -78,38 +81,46 @@ WX_DECLARE_OBJARRAY( EQCurve, EQCurveArray );
class EffectEqualization48x;
#endif
class EffectEqualization: public Effect {
class EffectEqualization : public Effect,
public XMLTagHandler
{
public:
EffectEqualization();
virtual ~EffectEqualization();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Equalization..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#EQPlugin"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Equalization"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Performing Equalization"));
}
virtual EffectType GetType();
// EffectClientInterface implementation
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
// EffectUIClientInterface implementation
virtual bool ValidateUI();
// Effect implementation
virtual bool Startup();
virtual bool Init();
virtual bool PromptUser();
virtual bool DontPromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual bool Process();
virtual bool PopulateUI(wxWindow *parent);
virtual bool CloseUI();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
private:
// EffectEqualization implementation
// Number of samples in an FFT window
enum {windowSize=16384}; //MJS - work out the optimum for this at run time? Have a dialog box for it?
@ -117,17 +128,57 @@ public:
// low range of human hearing
enum {loFreqI=20};
private:
bool ProcessOne(int count, WaveTrack * t,
sampleCount start, sampleCount len);
virtual bool CalcFilter();
void Filter(sampleCount len, float *buffer);
void EnvelopeUpdated();
void EnvelopeUpdated(Envelope *env, bool lin);
void Filter(sampleCount len,
float *buffer);
void LoadCurves(wxString fileName = wxT(""), bool append = false);
void SaveCurves(wxString fileName = wxT(""));
void Select(int sel);
void setCurve(int currentCurve);
void setCurve(wxString curveName);
void setCurve(void);
// XMLTagHandler callback methods for loading and saving
bool HandleXMLTag(const wxChar *tag, const wxChar **attrs);
XMLTagHandler *HandleXMLChild(const wxChar *tag);
void WriteXML(XMLWriter &xmlFile);
void ReadPrefs();
void LayoutEQSliders();
void UpdateGraphic(void);
void EnvLogToLin(void);
void EnvLinToLog(void);
void ErrMin(void);
void GraphicEQ(Envelope *env);
void spline(double x[], double y[], int n, double y2[]);
double splint(double x[], double y[], int n, double y2[], double xr);
void OnSize( wxSizeEvent & event );
void OnErase( wxEraseEvent & event );
void OnPaint( wxPaintEvent & event );
void OnSlider( wxCommandEvent & event );
void OnInterp( wxCommandEvent & event );
void OnSliderM( wxCommandEvent & event );
void OnSliderDBMAX( wxCommandEvent & event );
void OnSliderDBMIN( wxCommandEvent & event );
void OnDrawMode( wxCommandEvent &event );
void OnGraphicMode( wxCommandEvent &event );
void OnCurve( wxCommandEvent & event );
void OnManage( wxCommandEvent & event );
void OnClear( wxCommandEvent & event );
void OnInvert( wxCommandEvent & event );
void OnGridOnOff( wxCommandEvent & event );
void OnLinFreq( wxCommandEvent & event );
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
void OnProcessingRadio( wxCommandEvent & event );
void OnBench( wxCommandEvent & event );
#endif
private:
HFFT hFFT;
float *mFFTBuffer;
float *mFilterFuncR;
@ -135,231 +186,40 @@ private:
int mM;
wxString mCurveName;
bool mLin;
double mdBMax;
double mdBMin;
float mdBMax;
float mdBMin;
bool mDrawMode;
int mInterp;
bool mPrompting;
bool mDrawGrid;
bool mEditingBatchParams;
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
bool mBench;
EffectEqualization48x *mEffectEqualization48x;
friend class EffectEqualization48x;
#endif
public:
friend class EqualizationDialog;
friend class EqualizationPanel;
};
class EqualizationPanel: public wxPanel
{
public:
EqualizationPanel( double loFreq, double hiFreq,
Envelope *env,
EqualizationDialog *parent,
float *filterFuncR, float *filterFuncI, long windowSize,
wxWindowID id,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize);
~EqualizationPanel();
void OnMouseEvent(wxMouseEvent & event);
void OnCaptureLost(wxMouseCaptureLostEvent & event);
void OnPaint(wxPaintEvent & event);
void OnSize (wxSizeEvent & event);
// We don't need or want to accept focus.
bool AcceptsFocus() const { return false; }
void Recalc();
int M;
float dBMax;
float dBMin;
bool RecalcRequired;
Envelope *mEnvelope;
private:
wxBitmap *mBitmap;
wxRect mEnvRect;
EqualizationDialog *mParent;
int mWidth;
int mHeight;
long mWindowSize;
float *mFilterFuncR;
float *mFilterFuncI;
float *mOutr;
float *mOuti;
double mLoFreq;
double mHiFreq;
DECLARE_EVENT_TABLE()
};
// WDR: class declarations
//----------------------------------------------------------------------------
// EqualizationDialog
//----------------------------------------------------------------------------
class EqualizationDialog: public wxDialog, public XMLTagHandler
{
public:
// constructors and destructors
EqualizationDialog(EffectEqualization * effect,
double loFreq, double hiFreq,
float *filterFuncR, float *filterFuncI, long windowSize, wxString CurveName, bool disallowCustom,
wxWindow *parent, wxWindowID id,
const wxString &title,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_DIALOG_STYLE );
~EqualizationDialog();
// WDR: method declarations for EqualizationDialog
virtual bool Validate();
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
virtual bool CalcFilter();
void EnvelopeUpdated();
void EnvelopeUpdated(Envelope *env, bool lin);
static const double thirdOct[];
wxRadioButton *mFaderOrDraw[2];
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
wxRadioButton *mMathProcessingType[5]; // default, sse, sse threaded, AVX, AVX threaded (note AVX is not implemented yet
#endif
wxChoice *mInterpChoice;
wxCheckBox *mLinFreq;
int M;
wxString curveName;
bool linCheck;
float dBMin;
float dBMax;
double whens[NUM_PTS];
double whenSliders[NUMBER_OF_BANDS+1];
int bandsInUse;
bool drawMode;
int interp;
bool drawGrid;
RulerPanel *dBRuler;
RulerPanel *freqRuler;
friend class EditCurvesDialog;
private:
void MakeEqualizationDialog();
void CreateChoice();
void LoadCurves(wxString fileName = wxT(""), bool append = false);
void SaveCurves(wxString fileName = wxT(""));
void Select(int sel);
void setCurve(int currentCurve);
void setCurve(wxString curveName);
void setCurve(void);
void GraphicEQ(Envelope *env);
void spline(double x[], double y[], int n, double y2[]);
double splint(double x[], double y[], int n, double y2[], double xr);
void LayoutEQSliders();
void RevertCustom();
void Finish(bool ok);
// XMLTagHandler callback methods for loading and saving
bool HandleXMLTag(const wxChar *tag, const wxChar **attrs);
XMLTagHandler *HandleXMLChild(const wxChar *tag);
void WriteXML(XMLWriter &xmlFile);
private:
// WDR: member variable declarations for EqualizationDialog
enum
{
ID_FILTERPANEL = 10000,
ID_LENGTH,
ID_DBMAX,
ID_DBMIN,
ID_CURVE,
ID_MANAGE,
ID_DELETE,
ID_CLEAR,
ID_INVERT,
drawRadioID,
sliderRadioID,
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
defaultMathRadioID,
sSERadioID,
sSEThreadedRadioID,
aVXRadioID,
aVXThreadedRadioID,
ID_BENCH,
#endif
ID_INTERP,
ID_LIN_FREQ,
GridOnOffID,
ID_SLIDER // needs to come last
};
private:
// WDR: handler declarations for EqualizationDialog
void OnPaint( wxPaintEvent &event );
void OnSize( wxSizeEvent &event );
void OnErase( wxEraseEvent &event );
void OnSlider( wxCommandEvent &event );
void OnInterp( wxCommandEvent &event );
void OnSliderM( wxCommandEvent &event );
void OnSliderDBMAX( wxCommandEvent &event );
void OnSliderDBMIN( wxCommandEvent &event );
void OnDrawRadio(wxCommandEvent &event );
void OnSliderRadio(wxCommandEvent &event );
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
void OnProcessingRadio(wxCommandEvent &event );
void OnBench( wxCommandEvent & event);
#endif
void OnLinFreq(wxCommandEvent &event );
void UpdateGraphic(void);
void EnvLogToLin(void);
void EnvLinToLog(void);
void ErrMin(void);
void OnCurve( wxCommandEvent &event );
void OnManage( wxCommandEvent &event );
void OnClear( wxCommandEvent &event );
void OnInvert( wxCommandEvent &event );
void OnPreview(wxCommandEvent &event);
void OnOk( wxCommandEvent &event );
void OnCancel( wxCommandEvent &event );
void OnGridOnOff( wxCommandEvent &event );
private:
EffectEqualization * m_pEffect;
double mWhens[NUM_PTS];
double mWhenSliders[NUMBER_OF_BANDS+1];
int mBandsInUse;
RulerPanel *mdBRuler;
RulerPanel *mFreqRuler;
wxArrayString mInterpolations;
bool mDisallowCustom;
double mLoFreq;
double mHiFreq;
float *mFilterFuncR;
float *mFilterFuncI;
long mWindowSize;
bool mDirty;
wxSlider * m_sliders[NUMBER_OF_BANDS];
int m_sliders_old[NUMBER_OF_BANDS];
double m_EQVals[NUMBER_OF_BANDS+1];
int mSlidersOld[NUMBER_OF_BANDS];
double mEQVals[NUMBER_OF_BANDS+1];
EQCurveArray mCurves;
EQCurve mCustomBackup;
EqualizationPanel *mPanel;
Envelope *mLogEnvelope;
Envelope *mLinEnvelope;
wxBoxSizer *mCurveSizer;
wxChoice *mCurve;
wxButton *mDelete;
wxButton *mManage;
wxStaticText *mMText;
wxStaticText *octText;
wxSlider *MSlider;
wxSlider *dBMinSlider;
wxSlider *dBMaxSlider;
Envelope *mEnvelope;
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
bool mBench;
EffectEqualization48x *mEffectEqualization48x;
friend class EffectEqualization48x;
#endif
wxBoxSizer *szrC;
wxBoxSizer *szrG;
wxBoxSizer *szrV;
@ -374,22 +234,87 @@ private:
wxBoxSizer *szr3;
wxBoxSizer *szr4;
wxBoxSizer *szr5;
wxSize size;
wxSizerItem *mLeftSpacer;
EqualizationPanel *mPanel;
wxRadioButton *mDraw;
wxRadioButton *mGraphic;
wxCheckBox *mLinFreq;
wxCheckBox *mGridOnOff;
EQCurveArray mCurves;
EQCurve mCustomBackup;
wxChoice *mInterpChoice;
wxChoice *mCurve;
wxButton *mManage;
wxStaticText *mMText;
wxSlider *mMSlider;
wxSlider *mdBMinSlider;
wxSlider *mdBMaxSlider;
wxSlider *mSliders[NUMBER_OF_BANDS];
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
wxRadioButton *mMathProcessingType[5]; // default, sse, sse threaded, AVX, AVX threaded (note AVX is not implemented yet
wxBoxSizer *szrM;
#endif
DECLARE_EVENT_TABLE();
friend class EqualizationPanel;
friend class EditCurvesDialog;
};
class EqualizationPanel: public wxPanel
{
public:
EqualizationPanel(EffectEqualization *effect, wxWindow *parent);
~EqualizationPanel();
// We don't need or want to accept focus.
bool AcceptsFocus() const { return false; }
void ForceRecalc();
private:
DECLARE_EVENT_TABLE()
void Recalc();
void OnMouseEvent(wxMouseEvent & event);
void OnCaptureLost(wxMouseCaptureLostEvent & event);
void OnPaint(wxPaintEvent & event);
void OnSize (wxSizeEvent & event);
public:
// int & mM;
// float & mdBMax;
// float & mdBMin;
// Envelope & mEnvelope;
private:
wxWindow *mParent;
EffectEqualization *mEffect;
bool mRecalcRequired;
wxBitmap *mBitmap;
wxRect mEnvRect;
int mWidth;
int mHeight;
// long mWindowSize;
// float *mFilterFuncR;
// float *mFilterFuncI;
float *mOutr;
float *mOuti;
// double mLoFreq;
// double mHiFreq;
DECLARE_EVENT_TABLE();
};
// EditCurvesDialog. Note that the 'modified' curve used to be called 'custom' but is now called 'unnamed'
// Some things that deal with 'unnamed' curves still use, for example, 'mCustomBackup' as variable names.
class EditCurvesDialog:public wxDialog
class EditCurvesDialog : public wxDialog
{
public:
EditCurvesDialog(EqualizationDialog * parent, int position);
EditCurvesDialog(wxWindow * parent, EffectEqualization * effect, int position);
~EditCurvesDialog();
private:
@ -409,7 +334,8 @@ private:
wxListCtrl *mList; // List of curves.
EQCurveArray mEditCurves; // Copy of curves to muck about with
EqualizationDialog *mParent; // the parent EQ Dialog
wxWindow *mParent; // the parent EQ Dialog
EffectEqualization *mEffect; // the parent EQ effect
int mPosition; // position of current curve in list
void Populate();
void PopulateOrExchange(ShuttleGui &S);
@ -427,7 +353,6 @@ private:
DECLARE_EVENT_TABLE()
};
#if wxUSE_ACCESSIBILITY
class SliderAx: public wxWindowAccessible

View File

@ -251,8 +251,8 @@ bool EffectEqualization48x::FreeBuffersWorkers()
}
#pragma warning(push)
// Disable the unreachable code warning in MSVC, for this function.
#pragma warning(push)
// Disable the unreachable code warning in MSVC, for this function.
#pragma warning(disable: 4702)
bool EffectEqualization48x::RunFunctionSelect(int flags, int count, WaveTrack * track, sampleCount start, sampleCount len)
{

View File

@ -8,57 +8,92 @@
*******************************************************************//**
\class EffectFadeIn
\brief An EffectSimpleMono
*//****************************************************************//**
\class EffectFadeOut
\brief An EffectSimpleMono
\class EffectFade
\brief An Effect
*//*******************************************************************/
#include "../Audacity.h"
#include <wx/intl.h>
#include "Fade.h"
#include "../WaveTrack.h"
#include <wx/generic/textdlgg.h>
#include <math.h>
bool EffectFadeIn::NewTrackSimpleMono()
EffectFade::EffectFade(bool fadeIn)
{
mFadeIn = fadeIn;
}
EffectFade::~EffectFade()
{
}
// IdentInterface implementation
wxString EffectFade::GetSymbol()
{
return mFadeIn
? FADEIN_PLUGIN_SYMBOL
: FADEOUT_PLUGIN_SYMBOL;
}
wxString EffectFade::GetDescription()
{
return mFadeIn
? wxTRANSLATE("Applies a linear fade-in to the selected audio")
: wxTRANSLATE("Applies a linear fade-out to the selected audio");
}
// EffectIdentInterface implementation
EffectType EffectFade::GetType()
{
return EffectTypeProcess;
}
bool EffectFade::IsInteractive()
{
return false;
}
// EffectClientInterface implementation
int EffectFade::GetAudioInCount()
{
return 1;
}
int EffectFade::GetAudioOutCount()
{
return 1;
}
bool EffectFade::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames WXUNUSED(chanMap))
{
mLen = (int)((mCurT1 - mCurT0) * mCurRate + 0.5);
mSample = 0;
return true;
}
bool EffectFadeIn::ProcessSimpleMono(float *buffer, sampleCount len)
sampleCount EffectFade::ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen)
{
for (sampleCount i = 0; i < len; i++)
buffer[i] = (float) (buffer[i] * (float) (mSample + i)
/ (float) (mLen));
mSample += len;
float *ibuf = inBlock[0];
float *obuf = outBlock[0];
return true;
}
bool EffectFadeOut::NewTrackSimpleMono()
{
mLen = (int)((mCurT1 - mCurT0) * mCurRate + 0.5);
mSample = 0;
return true;
}
bool EffectFadeOut::ProcessSimpleMono(float *buffer, sampleCount len)
{
for (sampleCount i = 0; i < len; i++)
buffer[i] = (float) (buffer[i]
* (float) (mLen - 1 - (mSample + i))
/ (float) (mLen));
mSample += len;
return true;
if (mFadeIn)
{
for (sampleCount i = 0; i < blockLen; i++)
{
obuf[i] = (ibuf[i] * ((float) mSample++)) / mSampleCnt;
}
}
else
{
for (sampleCount i = 0; i < blockLen; i++)
{
obuf[i] = (ibuf[i] * ((float) mSampleCnt - 1 - mSample++)) / mSampleCnt;
}
}
return blockLen;
}

View File

@ -11,78 +11,41 @@
#ifndef __AUDACITY_EFFECT_FADE__
#define __AUDACITY_EFFECT_FADE__
#include "SimpleMono.h"
#include <wx/string.h>
#include <wx/intl.h>
#include "Effect.h"
class wxString;
#define FADEIN_PLUGIN_SYMBOL wxTRANSLATE("Fade In")
#define FADEOUT_PLUGIN_SYMBOL wxTRANSLATE("Fade Out")
class EffectFadeIn: public EffectSimpleMono {
class EffectFade : public Effect
{
public:
EffectFade(bool fadeIn = false);
virtual ~EffectFade();
public:
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Fade In"));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#UtilityPlugin"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Fade In"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Fading In"));
}
virtual EffectType GetType();
virtual bool IsInteractive();
virtual bool PromptUser() {
return true;
}
// EffectClientInterface implementation
protected:
virtual int GetAudioInCount();
virtual int GetAudioOutCount();
virtual bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap = NULL);
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen);
private:
// EffectFadeIn implementation
bool mFadeIn;
sampleCount mSample;
sampleCount mLen;
virtual bool NewTrackSimpleMono();
virtual bool ProcessSimpleMono(float *buffer, sampleCount len);
};
class EffectFadeOut:public EffectSimpleMono {
public:
virtual wxString GetEffectName() {
return wxString(_("Fade Out"));
}
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#UtilityPlugin"));
return result;
}
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Fade Out"));
}
virtual wxString GetEffectAction() {
return wxString(_("Fading Out"));
}
virtual bool PromptUser() {
return true;
}
protected:
sampleCount mSample;
sampleCount mLen;
virtual bool NewTrackSimpleMono();
virtual bool ProcessSimpleMono(float *buffer, sampleCount len);
};
#endif

View File

@ -20,55 +20,78 @@
#include "../Audacity.h"
#include "../AudacityApp.h"
#include <wx/defs.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/validate.h>
#include <wx/valtext.h>
#include <wx/generic/textdlgg.h>
#include <wx/intl.h>
#include <math.h>
#include <wx/intl.h>
#include "../AudacityApp.h"
#include "../widgets/valnum.h"
#include "FindClipping.h"
#include "../LabelTrack.h"
#include "../WaveTrack.h"
#define DEF_Start 3
#define MIN_Start 1
#define DEF_Stop 3
#define MIN_Stop 1
EffectFindClipping::EffectFindClipping()
{
SetEffectFlags(BUILTIN_EFFECT | ANALYZE_EFFECT);
mStart = 3;
mStop = 3;
mStart = DEF_Start;
mStop = DEF_Stop;
}
wxString EffectFindClipping::GetEffectDescription()
EffectFindClipping::~EffectFindClipping()
{
return wxString::Format(_("Detect clipping"));
}
bool EffectFindClipping::PromptUser()
{
FindClippingDialog dlg(this, mParent);
dlg.CentreOnParent();
// IdentInterface implementation
if (dlg.ShowModal() == wxID_CANCEL) {
wxString EffectFindClipping::GetSymbol()
{
return FINDCLIPPING_PLUGIN_SYMBOL;
}
wxString EffectFindClipping::GetDescription()
{
return wxTRANSLATE("This displays runs of clipped samples in a Label Track");
}
// EffectIdentInterface implementation
EffectType EffectFindClipping::GetType()
{
return EffectTypeAnalyze;
}
// EffectClientInterface implementation
bool EffectFindClipping::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.Write(wxT("Start"), mStart);
parms.Write(wxT("Stop"), mStop);
return true;
}
bool EffectFindClipping::SetAutomationParameters(EffectAutomationParameters & parms)
{
int start;
int stop;
parms.Read(wxT("Start"), &start, DEF_Start);
parms.Read(wxT("Stop"), &stop, DEF_Stop);
if (start < MIN_Start || stop < MIN_Stop)
{
return false;
}
return true;
}
bool EffectFindClipping::TransferParameters(Shuttle & shuttle)
{
shuttle.TransferInt(wxT("Start"), mStart, 3);
shuttle.TransferInt(wxT("Stop"), mStop, 3);
return true;
}
// Effect implementation
bool EffectFindClipping::Process()
{
@ -203,41 +226,42 @@ bool EffectFindClipping::ProcessOne(LabelTrack * l,
return bGoodResult;
}
//----------------------------------------------------------------------------
// FindClippingDialog
//----------------------------------------------------------------------------
FindClippingDialog::FindClippingDialog(EffectFindClipping * effect, wxWindow * parent)
: EffectDialog(parent, _("Find Clipping"), INSERT_EFFECT)
{
mEffect = effect;
Init();
}
void FindClippingDialog::PopulateOrExchange(ShuttleGui & S)
void EffectFindClipping::PopulateOrExchange(ShuttleGui & S)
{
S.StartMultiColumn(2, wxALIGN_CENTER);
{
IntegerValidator<int> vldStart(&mStart);
vldStart.SetMin(MIN_Start);
S.TieTextBox(_("Start threshold (samples):"),
mEffect->mStart,
10)->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
mStart,
10)->SetValidator(vldStart);
IntegerValidator<int> vldStop(&mStop);
vldStop.SetMin(MIN_Stop);
S.TieTextBox(_("Stop threshold (samples):"),
mEffect->mStop,
10)->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
mStop,
10)->SetValidator(vldStop);
}
S.EndMultiColumn();
}
bool FindClippingDialog::TransferDataFromWindow()
bool EffectFindClipping::TransferDataToWindow()
{
EffectDialog::TransferDataFromWindow();
if (mEffect->mStart <= 0 || mEffect->mStop <= 0) {
wxMessageBox(_("Start and stop must be greater than 0."));
return false;
}
ShuttleGui S(mUIParent, eIsSettingToDialog);
PopulateOrExchange(S);
return true;
}
bool EffectFindClipping::TransferDataFromWindow()
{
if (!mUIParent->Validate())
{
return false;
}
ShuttleGui S(mUIParent, eIsGettingFromDialog);
PopulateOrExchange(S);
return true;
}

View File

@ -14,73 +14,51 @@
class wxString;
#include <wx/dialog.h>
#include <wx/string.h>
#include <wx/intl.h>
#include "../LabelTrack.h"
#include "../WaveTrack.h"
#include "Effect.h"
class wxStaticText;
#define FINDCLIPPING_PLUGIN_SYMBOL wxTRANSLATE("Find Clipping")
class WaveTrack;
class EffectFindClipping:public Effect
class EffectFindClipping : public Effect
{
friend class FindClippingDialog;
public:
public:
EffectFindClipping();
virtual ~EffectFindClipping();
virtual wxString GetEffectName()
{
return wxString(wxTRANSLATE("Find Clipping..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories()
{
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#AnalyserPlugin"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier()
{
return wxString(wxT("Find Clipping"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction()
{
return wxString(_("Detecting clipping"));
}
virtual EffectType GetType();
virtual wxString GetEffectDescription();
// EffectClientInterface implementation
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
// Effect implementation
virtual bool Process();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
private:
// EffectFindCliping implementation
private:
bool ProcessOne(LabelTrack *l, int count, WaveTrack * t,
sampleCount start, sampleCount len);
private:
int mStart; ///< Using int rather than sampleCount because values are only ever small numbers
int mStop; ///< Using int rather than sampleCount because values are only ever small numbers
};
//----------------------------------------------------------------------------
// FindClippingDialog
//----------------------------------------------------------------------------
class FindClippingDialog:public EffectDialog {
public:
FindClippingDialog(EffectFindClipping * effect, wxWindow * parent);
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataFromWindow();
private:
EffectFindClipping *mEffect;
};
#endif // __AUDACITY_EFFECT_FINDCLIPPING__

View File

@ -24,7 +24,7 @@
class Generator : public Effect
{
public:
Generator() : mDuration(sDefaultGenerateLen) { }
Generator() : mDuration(GetDefaultDuration()) { }
protected:
// Amount of time to generate, in seconds

View File

@ -10,20 +10,69 @@
*******************************************************************//**
\class EffectInvert
\brief An EffectSimpleMono that inverts the selected audio.
\brief An Effect that inverts the selected audio.
*//*******************************************************************/
#include "../Audacity.h"
#include <wx/intl.h>
#include "Invert.h"
bool EffectInvert::ProcessSimpleMono(float *buffer, sampleCount len)
EffectInvert::EffectInvert()
{
sampleCount i;
for (i = 0; i < len; i++)
buffer[i] = -buffer[i];
return true;
}
EffectInvert::~EffectInvert()
{
}
// IdentInterface implementation
wxString EffectInvert::GetSymbol()
{
return INVERT_PLUGIN_SYMBOL;
}
wxString EffectInvert::GetDescription()
{
return wxTRANSLATE("Flips the audio samples upside-down, reversing their polarity");
}
// EffectIdentInterface implementation
EffectType EffectInvert::GetType()
{
return EffectTypeProcess;
}
bool EffectInvert::IsInteractive()
{
return false;
}
// EffectClientInterface implementation
int EffectInvert::GetAudioInCount()
{
return 1;
}
int EffectInvert::GetAudioOutCount()
{
return 1;
}
sampleCount EffectInvert::ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen)
{
float *ibuf = inBlock[0];
float *obuf = outBlock[0];
for (sampleCount i = 0; i < blockLen; i++)
{
obuf[i] = -ibuf[i];
}
return blockLen;
}

View File

@ -13,40 +13,33 @@
#ifndef __AUDACITY_EFFECT_INVERT__
#define __AUDACITY_EFFECT_INVERT__
#include <wx/intl.h>
#include <wx/string.h>
#include "SimpleMono.h"
#include "Effect.h"
class WaveTrack;
#define INVERT_PLUGIN_SYMBOL wxTRANSLATE("Invert")
class EffectInvert:public EffectSimpleMono {
class EffectInvert : public Effect
{
public:
EffectInvert();
virtual ~EffectInvert();
public:
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Invert"));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#UtilityPlugin"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Invert"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Inverting"));
}
virtual EffectType GetType();
virtual bool IsInteractive();
virtual bool PromptUser() {
return true;
}
// EffectClientInterface implementation
protected:
virtual bool ProcessSimpleMono(float *buffer, sampleCount len);
virtual int GetAudioInCount();
virtual int GetAudioOutCount();
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen);
};
#endif

View File

@ -9,75 +9,253 @@
******************************************************************//**
\class EffectLeveller
\brief An EffectSimpleMono
*//***************************************************************//**
\class LevellerDialog
\brief Dialog for EffectLeveller
\brief An Effect
*//*******************************************************************/
#include "../Audacity.h"
// For compilers that support precompilation, includes "wx.h".
#include <wx/wxprec.h>
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
// Include your minimal set of headers here, or wx.h
#include <wx/wx.h>
#endif
#include <math.h>
#include <wx/choice.h>
#include <wx/intl.h>
#include <wx/valgen.h>
#include "../Prefs.h"
#include "Leveller.h"
enum kPasses
{
kLight,
kModerate,
kHeavy,
kHeavier,
kHeaviest,
kNumPasses
};
static const wxString kPassStrings[kNumPasses] =
{
/* i18n-hint: Of strength of an effect. Not strongly.*/
wxTRANSLATE("Light"),
wxTRANSLATE("Moderate"),
/* i18n-hint: Of strength of an effect. Strongly.*/
wxTRANSLATE("Heavy"),
wxTRANSLATE("Heavier"),
wxTRANSLATE("Heaviest"),
};
// Define keys, defaults, minimums, and maximums for the effect parameters
//
// Name Type Key Def Min Max Scale
Param( Level, int, wxTRANSLATE("dB"), 10, 0, Enums::NumDbChoices - 1, 1 );
Param( Passes, int, wxTRANSLATE("Passes"), kModerate, 0, kNumPasses - 1, 1 );
//
// EffectLeveller
//
EffectLeveller::EffectLeveller()
{
Init();
mPassIndex = DEF_Passes;
mDbIndex = DEF_Level;
mNumPasses = mPassIndex + 1;
mDbSilenceThreshold = Enums::Db2Signal[mDbIndex];
CalcLevellerFactors();
}
#define NUM_PASSES_CHOICES 5
bool EffectLeveller::Init()
EffectLeveller::~EffectLeveller()
{
mLevellerNumPasses = gPrefs->Read(wxT("/Effects/Leveller/LevellerNumPasses"), 2L) ;
if ((mLevellerNumPasses <= 0) || (mLevellerNumPasses > NUM_PASSES_CHOICES)) { // corrupted Prefs?
mLevellerNumPasses = 1;
gPrefs->Write(wxT("/Effects/Leveller/LevellerNumPasses"), 1);
}
mLevellerDbChoiceIndex = gPrefs->Read(wxT("/Effects/Leveller/LevellerDbChoiceIndex"), 10L);
if ((mLevellerDbChoiceIndex < 0) || (mLevellerDbChoiceIndex >= Enums::NumDbChoices)) { // corrupted Prefs?
mLevellerDbChoiceIndex = 0; //Least dB
gPrefs->Write(wxT("/Effects/Leveller/LevellerDbChoiceIndex"), mLevellerDbChoiceIndex);
}
gPrefs->Flush();
}
mLevellerDbSilenceThreshold = Enums::Db2Signal[mLevellerDbChoiceIndex];
// IdentInterface implementation
wxString EffectLeveller::GetSymbol()
{
return LEVELLER_PLUGIN_SYMBOL;
}
wxString EffectLeveller::GetDescription()
{
return wxTRANSLATE("Leveler is a simple, combined compressor and limiter effect for reducing the dynamic range of audio");
}
// EffectIdentInterface implementation
EffectType EffectLeveller::GetType()
{
return EffectTypeProcess;
}
// EffectClientInterface implementation
int EffectLeveller::GetAudioInCount()
{
return 1;
}
int EffectLeveller::GetAudioOutCount()
{
return 1;
}
sampleCount EffectLeveller::ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen)
{
float *ibuf = inBlock[0];
float *obuf = outBlock[0];
for (sampleCount i = 0; i < blockLen; i++)
{
float frame = ibuf[i];
for (int pass = 0; pass < mNumPasses; pass++)
{
frame = LevelOneFrame(frame);
}
obuf[i] = frame;
}
return blockLen;
}
bool EffectLeveller::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.Write(KEY_Level, Enums::DbChoices[mDbIndex]);
parms.Write(KEY_Passes, kPassStrings[mPassIndex]);
return true;
}
bool EffectLeveller::SetAutomationParameters(EffectAutomationParameters & parms)
{
// Allow for 2.1.0 and before
wxArrayString passChoices(kNumPasses, kPassStrings);
passChoices.Insert(wxT("1"), 0);
passChoices.Insert(wxT("2"), 1);
passChoices.Insert(wxT("3"), 2);
passChoices.Insert(wxT("4"), 3);
passChoices.Insert(wxT("5"), 4);
ReadAndVerifyEnum(Level, wxArrayString(Enums::NumDbChoices,Enums::GetDbChoices()));
ReadAndVerifyEnum(Passes, passChoices);
mDbIndex = Level;
mPassIndex = Passes;
// Readjust for 2.1.0 or before
if (mPassIndex >= kNumPasses)
{
mPassIndex -= kNumPasses;
}
mNumPasses = mPassIndex + 1;
mDbSilenceThreshold = Enums::Db2Signal[mDbIndex];
CalcLevellerFactors();
return true;
}
bool EffectLeveller::CheckWhetherSkipEffect()
// Effect implementation
bool EffectLeveller::Startup()
{
return mLevellerNumPasses == 0;
wxString base = wxT("/Effects/Leveller/");
// Migrate settings from 2.1.0 or before
// Already migrated, so bail
if (gPrefs->Exists(base + wxT("Migrated")))
{
return true;
}
// Load the old "current" settings
if (gPrefs->Exists(base))
{
mNumPasses = gPrefs->Read(base + wxT("LevellerNumPasses"), 2L);
if ((mNumPasses <= 0) || (mNumPasses > kNumPasses))
{ // corrupted Pr
mNumPasses = 1;
}
mDbIndex = gPrefs->Read(base + wxT("LevellerDbChoiceIndex"), 10L);
if ((mDbIndex < 0) || (mDbIndex >= Enums::NumDbChoices))
{ // cor
mDbIndex = 0; //Least dB
}
SaveUserPreset(GetCurrentSettingsGroup());
// Do not migrate again
gPrefs->Write(base + wxT("Migrated"), true);
gPrefs->Flush();
}
return true;
}
void EffectLeveller::End()
void EffectLeveller::PopulateOrExchange(ShuttleGui & S)
{
int frameSum = (int)mFrameSum;
gPrefs->Write(wxT("/Validate/LevellerFrameSum"), frameSum);
gPrefs->Flush();
wxASSERT(kNumPasses == WXSIZEOF(kPassStrings));
wxArrayString passChoices;
for (int i = 0; i < kNumPasses; i++)
{
passChoices.Add(wxGetTranslation(kPassStrings[i]));
}
wxArrayString dBChoices(Enums::NumDbChoices,Enums::GetDbChoices());
S.SetBorder(5);
S.StartVerticalLay();
{
S.AddSpace(5);
S.StartMultiColumn(2, wxALIGN_CENTER);
{
S.AddChoice(_("Degree of Leveling:"),
wxT(""),
&passChoices)->SetValidator(wxGenericValidator(&mPassIndex));
S.AddChoice(_("Noise Threshold:"),
wxT(""),
&dBChoices)->SetValidator(wxGenericValidator(&mDbIndex));
}
S.EndMultiColumn();
}
S.EndVerticalLay();
return;
}
bool EffectLeveller::TransferDataToWindow()
{
if (!mUIParent->TransferDataToWindow())
{
return false;
}
return true;
}
bool EffectLeveller::TransferDataFromWindow()
{
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
mNumPasses = mPassIndex + 1;
mDbSilenceThreshold = Enums::Db2Signal[mDbIndex];
CalcLevellerFactors();
return true;
}
// EffectLeveller implementation
#define LEVELER_FACTORS 6
static double gLimit[LEVELER_FACTORS] = { 0.0001, 0.0, 0.1, 0.3, 0.5, 1.0 };
static double gAdjLimit[LEVELER_FACTORS];
@ -87,8 +265,7 @@ static double gAdjFactor[LEVELER_FACTORS] = { 0.80, 1.00, 1.20, 1.20, 1.00, 0.80
void EffectLeveller::CalcLevellerFactors()
{
mFrameSum = 0.0;
gLimit[1] = mLevellerDbSilenceThreshold;
gLimit[1] = mDbSilenceThreshold;
int prev = 0;
double addOnValue = 0.0;
double prevLimit = 0.0;
@ -113,40 +290,6 @@ void EffectLeveller::CalcLevellerFactors()
}
}
bool EffectLeveller::PromptUser()
{
LevellerDialog dlog(this, mParent);
dlog.mLevellerDbChoiceIndex = mLevellerDbChoiceIndex;
dlog.mLevellerNumPassesChoiceIndex = mLevellerNumPasses-1;
dlog.TransferDataToWindow();
dlog.CentreOnParent();
dlog.ShowModal();
if (dlog.GetReturnCode() == wxID_CANCEL) {
return false;
}
mLevellerNumPasses = dlog.mLevellerNumPassesChoiceIndex+1;
mLevellerDbChoiceIndex = dlog.mLevellerDbChoiceIndex;
mLevellerDbSilenceThreshold = Enums::Db2Signal[mLevellerDbChoiceIndex];
gPrefs->Write(wxT("/Effects/Leveller/LevellerDbChoiceIndex"), mLevellerDbChoiceIndex);
gPrefs->Write(wxT("/Effects/Leveller/LevellerNumPasses"), mLevellerNumPasses);
gPrefs->Flush();
CalcLevellerFactors();
return true;
}
bool EffectLeveller::TransferParameters( Shuttle & shuttle )
{
shuttle.TransferEnum(wxT("dB"),mLevellerDbChoiceIndex,Enums::NumDbChoices,Enums::GetDbChoices());
shuttle.TransferInt(wxT("Passes"),mLevellerNumPasses,1);
return true;
}
float EffectLeveller::LevelOneFrame(float frameInBuffer)
{
float curFrame;
@ -161,7 +304,6 @@ float EffectLeveller::LevelOneFrame(float frameInBuffer)
curSign = 1.0;
}
fabsCurFrame = (float)fabs(curFrame);
mFrameSum += fabsCurFrame;
for (int f = 0; f < LEVELER_FACTORS; ++f) {
if (fabsCurFrame <= gLimit[f]) {
@ -173,74 +315,3 @@ float EffectLeveller::LevelOneFrame(float frameInBuffer)
return (float)0.99;
}
bool EffectLeveller::ProcessSimpleMono(float *buffer, sampleCount len)
{
for (int pass = 0; pass < mLevellerNumPasses; ++pass) {
for (int i = 0; i < len; ++i) {
buffer[i] = LevelOneFrame(buffer[i]);
}
}
return true;
}
//----------------------------------------------------------------------------
// LevellerDialog
//----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(LevellerDialog, EffectDialog)
EVT_BUTTON(ID_EFFECT_PREVIEW, LevellerDialog::OnPreview)
END_EVENT_TABLE()
LevellerDialog::LevellerDialog(EffectLeveller *effect, wxWindow *parent)
: EffectDialog(parent, _("Leveler"), PROCESS_EFFECT), // Lynn called it "Leveller", but preferred spelling is "Leveler".
mEffect(effect)
{
mLevellerNumPassesChoiceIndex = 0;//
mLevellerDbChoiceIndex = 0;
Init();
}
void LevellerDialog::PopulateOrExchange(ShuttleGui & S)
{
wxArrayString db(Enums::NumDbChoices, Enums::GetDbChoices());
wxArrayString numPasses;
/* i18n-hint: Of strength of an effect. Not strongly.*/
numPasses.Add(_("Light"));
numPasses.Add(_("Moderate"));
/* i18n-hint: Of strength of an effect. Strongly.*/
numPasses.Add(_("Heavy"));
numPasses.Add(_("Heavier"));
numPasses.Add(_("Heaviest"));
S.SetBorder(5);
S.AddSpace(5);
S.StartMultiColumn(2);
{
S.TieChoice(_("Degree of Leveling:"),
mLevellerNumPassesChoiceIndex,
&numPasses);
S.TieChoice(_("Noise Threshold:"),
mLevellerDbChoiceIndex,
&db);
}
S.EndMultiColumn();
}
void LevellerDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
{
TransferDataFromWindow();
// Save & restore parameters around Preview.
int oldLevellerDbChoiceIndex = mEffect->mLevellerDbChoiceIndex;
int oldLevellerNumPasses = mEffect->mLevellerNumPasses;
mEffect->mLevellerDbChoiceIndex = mLevellerDbChoiceIndex;
mEffect->mLevellerNumPasses = mLevellerNumPassesChoiceIndex+1;
mEffect->Preview();
mEffect->mLevellerDbChoiceIndex = oldLevellerDbChoiceIndex;
mEffect->mLevellerNumPasses = oldLevellerNumPasses;
}

View File

@ -11,83 +11,57 @@
#ifndef __AUDACITY_EFFECT_LEVELER__
#define __AUDACITY_EFFECT_LEVELER__
#include "SimpleMono.h"
#include <wx/choice.h>
#include <wx/arrstr.h>
#include <wx/string.h>
#include <wx/textctrl.h>
class EffectLeveller: public EffectSimpleMono
#include "../ShuttleGui.h"
#include "Effect.h"
#define LEVELLER_PLUGIN_SYMBOL wxTRANSLATE("Leveller")
class EffectLeveller : public Effect
{
friend class LevellerDialog;
public:
public:
EffectLeveller();
virtual ~EffectLeveller();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Leveler..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#CompressorPlugin"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Leveller"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Applying Leveler..."));
}
virtual bool Init();
virtual void End();
virtual bool CheckWhetherSkipEffect();
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual EffectType GetType();
protected:
virtual bool ProcessSimpleMono(float *buffer, sampleCount len);
// EffectClientInterface implementation
private:
void CalcLevellerFactors();
int mLevellerDbChoiceIndex;
int mLevellerNumPasses;
double mFrameSum;
double mLevellerDbSilenceThreshold;
float LevelOneFrame(float frame);
};
virtual int GetAudioInCount();
virtual int GetAudioOutCount();
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen);
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
//----------------------------------------------------------------------------
// LevellerDialog
//----------------------------------------------------------------------------
// Effect implementation
class LevellerDialog: public EffectDialog
{
public:
// constructors and destructors
LevellerDialog(EffectLeveller *effect, wxWindow * parent);
virtual bool Startup();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
// method declarations
void PopulateOrExchange(ShuttleGui & S);
// bool TransferDataToWindow();
// bool TransferDataFromWindow();
private:
// EffectLeveller implementation
private:
// handlers
void OnPreview( wxCommandEvent &event );
void CalcLevellerFactors();
float LevelOneFrame(float frame);
private:
EffectLeveller *mEffect;
wxChoice *mLevellerDbSilenceThresholdChoice;
wxChoice *mLevellerNumPassesChoice;
private:
int mNumPasses;
double mDbSilenceThreshold;
DECLARE_EVENT_TABLE()
public:
int mLevellerDbChoiceIndex;
int mLevellerNumPassesChoiceIndex;
int mDbIndex;
int mPassIndex;
};
#endif

View File

@ -57,216 +57,269 @@
#include "ChangeTempo.h"
#endif
void LoadEffects()
//
// Include the SoundTouch effects, if requested
//
#if defined(USE_SOUNDTOUCH)
#define SOUNDTOUCH_EFFECTS \
EFFECT( CHANGEPITCH, EffectChangePitch() ) \
EFFECT( CHANGETEMPO, EffectChangeTempo() )
#else
#define SOUNDTOUCH_EFFECTS
#endif
//
// Select the desired Noise Reduction/Removal effect
//
#if defined(EXPERIMENTAL_NOISE_REDUCTION)
#define NOISEREDUCTION_EFFECT \
EFFECT( NOISEREDUCTION, EffectNoiseReduction() )
#else
#define NOISEREDUCTION_EFFECT \
EFFECT( NOISEREMOVAL, EffectNoiseRemoval() )
#endif
//
// Include the Classic Filters effect, if requested
//
#if defined(EXPERIMENTAL_SCIENCE_FILTERS)
#define CLASSICFILTER_EFFECT \
EFFECT( CLASSICFILTERS, EffectScienFilter() )
#else
#define CLASSICFILTER_EFFECT
#endif
//
// Include the SBSMS effect, if requested
//
#if defined(USE_SBSMS)
#define SBSMS_EFFECTS \
EFFECT( TIMESCALE, EffectTimeScale() )
#else
#define SBSMS_EFFECTS
#endif
//
// Define the complete list of effects and how to instantiate each
//
#define EFFECT_LIST \
EFFECT( CHIRP, EffectToneGen(true) ) \
EFFECT( DTMFTONES, EffectDtmf() ) \
EFFECT( NOISE, EffectNoise() ) \
EFFECT( SILENCE, EffectSilence() ) \
EFFECT( TONE, EffectToneGen(false) ) \
EFFECT( AMPLIFY, EffectAmplify() ) \
EFFECT( AUTODUCK, EffectAutoDuck() ) \
EFFECT( BASSTREBLE, EffectBassTreble() ) \
EFFECT( CHANGESPEED, EffectChangeSpeed() ) \
EFFECT( CLICKREMOVAL, EffectClickRemoval() ) \
EFFECT( COMPRESSOR, EffectCompressor() ) \
EFFECT( ECHO, EffectEcho() ) \
EFFECT( PAULSTRETCH, EffectPaulstretch() ) \
EFFECT( EQUALIZATION, EffectEqualization() ) \
EFFECT( FADEIN, EffectFade(true) ) \
EFFECT( FADEOUT, EffectFade(false) ) \
EFFECT( INVERT, EffectInvert() ) \
EFFECT( LEVELLER, EffectLeveller() ) \
EFFECT( NORMALIZE, EffectNormalize() ) \
EFFECT( PHASER, EffectPhaser() ) \
EFFECT( REPEAT, EffectRepeat() ) \
EFFECT( REVERB, EffectReverb() ) \
EFFECT( REVERSE, EffectReverse() ) \
EFFECT( STEREOTOMONO, EffectStereoToMono() ) \
EFFECT( TRUNCATESILENCE, EffectTruncSilence() ) \
EFFECT( WAHWAH, EffectWahwah() ) \
EFFECT( FINDCLIPPING, EffectFindClipping() ) \
NOISEREDUCTION_EFFECT \
CLASSICFILTER_EFFECT \
SOUNDTOUCH_EFFECTS \
SBSMS_EFFECTS
//
// Define the EFFECT() macro to generate enum names
//
#define EFFECT(n, i) ENUM_ ## n,
//
// Create the enum for the list of effects (will be used in a switch statement)
//
enum
{
EFFECT_LIST
};
EffectManager& em = EffectManager::Get();
//
// Redefine EFFECT() to add the effect's name to an array
//
#undef EFFECT
#define EFFECT(n, i) n ## _PLUGIN_SYMBOL,
#ifdef EFFECT_CATEGORIES
//
// Create the effect name array
//
static const wxChar *kEffectNames[] =
{
EFFECT_LIST
};
// Create effect category graph. These categories and relationships
// are taken from revision 2 of lv2.ttl, loaders for other plugin systems
// (such as LADSPA/LRDF) should map their categories to these ones when
// applicable. Individual LADSPA/LRDF and LV2 plugins can add new
// categories and make them subcategories of the existing ones, but not
// add subcategory relationships between these categories.
//
// We need some persistent, global identifiers for categories - LRDF
// and LV2 uses URI strings so we do that too. The URIs here are the
// same ones as in lv2.ttl. Category identifiers in other plugin systems
// must be mapped to URIs by their loaders.
//
// Redefine EFFECT() to generate a case statement for the lookup switch
//
#undef EFFECT
#define EFFECT(n, i) case ENUM_ ## n: return new i;
#define LV2PREFIX "http://lv2plug.in/ns/lv2core#"
typedef EffectCategory* CatPtr;
CatPtr gen = em.AddCategory(wxT(LV2PREFIX) wxT("GeneratorPlugin"),
_("Generator"));
CatPtr inst = em.AddCategory(wxT(LV2PREFIX) wxT("InstrumentPlugin"),
/* i18n-hint: (noun).*/
_("Instrument"));
CatPtr osc = em.AddCategory(wxT(LV2PREFIX) wxT("OscillatorPlugin"),
_("Oscillator"));
CatPtr util = em.AddCategory(wxT(LV2PREFIX) wxT("UtilityPlugin"),
_("Utility"));
CatPtr conv = em.AddCategory(wxT(LV2PREFIX) wxT("ConverterPlugin"),
_("Converter"));
CatPtr anal = em.AddCategory(wxT(LV2PREFIX) wxT("AnalyserPlugin"),
_("Analyser"));
CatPtr mix = em.AddCategory(wxT(LV2PREFIX) wxT("MixerPlugin"),
_("Mixer"));
CatPtr sim = em.AddCategory(wxT(LV2PREFIX) wxT("SimulatorPlugin"),
_("Simulator"));
CatPtr del = em.AddCategory(wxT(LV2PREFIX) wxT("DelayPlugin"),
_("Delay"));
CatPtr mod = em.AddCategory(wxT(LV2PREFIX) wxT("ModulatorPlugin"),
_("Modulator"));
CatPtr rev = em.AddCategory(wxT(LV2PREFIX) wxT("ReverbPlugin"),
_("Reverb"));
CatPtr phas = em.AddCategory(wxT(LV2PREFIX) wxT("PhaserPlugin"),
_("Phaser"));
CatPtr flng = em.AddCategory(wxT(LV2PREFIX) wxT("FlangerPlugin"),
_("Flanger"));
CatPtr chor = em.AddCategory(wxT(LV2PREFIX) wxT("ChorusPlugin"),
_("Chorus"));
CatPtr flt = em.AddCategory(wxT(LV2PREFIX) wxT("FilterPlugin"),
_("Filter"));
CatPtr lp = em.AddCategory(wxT(LV2PREFIX) wxT("LowpassPlugin"),
_("Lowpass"));
CatPtr bp = em.AddCategory(wxT(LV2PREFIX) wxT("BandpassPlugin"),
_("Bandpass"));
CatPtr hp = em.AddCategory(wxT(LV2PREFIX) wxT("HighpassPlugin"),
_("Highpass"));
CatPtr comb = em.AddCategory(wxT(LV2PREFIX) wxT("CombPlugin"),
_("Comb"));
CatPtr alp = em.AddCategory(wxT(LV2PREFIX) wxT("AllpassPlugin"),
_("Allpass"));
CatPtr eq = em.AddCategory(wxT(LV2PREFIX) wxT("EQPlugin"),
_("Equaliser"));
CatPtr peq = em.AddCategory(wxT(LV2PREFIX) wxT("ParaEQPlugin"),
_("Parametric"));
CatPtr meq = em.AddCategory(wxT(LV2PREFIX) wxT("MultiEQPlugin"),
_("Multiband"));
CatPtr spec = em.AddCategory(wxT(LV2PREFIX) wxT("SpectralPlugin"),
_("Spectral Processor"));
CatPtr ptch = em.AddCategory(wxT(LV2PREFIX) wxT("PitchPlugin"),
_("Pitch Shifter"));
CatPtr amp = em.AddCategory(wxT(LV2PREFIX) wxT("AmplifierPlugin"),
_("Amplifier"));
CatPtr dist = em.AddCategory(wxT(LV2PREFIX) wxT("DistortionPlugin"),
_("Distortion"));
CatPtr shp = em.AddCategory(wxT(LV2PREFIX) wxT("WaveshaperPlugin"),
_("Waveshaper"));
CatPtr dyn = em.AddCategory(wxT(LV2PREFIX) wxT("DynamicsPlugin"),
_("Dynamics Processor"));
CatPtr cmp = em.AddCategory(wxT(LV2PREFIX) wxT("CompressorPlugin"),
_("Compressor"));
CatPtr exp = em.AddCategory(wxT(LV2PREFIX) wxT("ExpanderPlugin"),
_("Expander"));
CatPtr lim = em.AddCategory(wxT(LV2PREFIX) wxT("LimiterPlugin"),
_("Limiter"));
CatPtr gate = em.AddCategory(wxT(LV2PREFIX) wxT("GatePlugin"),
_("Gate"));
em.AddCategoryParent(inst, gen);
em.AddCategoryParent(osc, gen);
em.AddCategoryParent(conv, util);
em.AddCategoryParent(anal, util);
em.AddCategoryParent(mix, util);
em.AddCategoryParent(rev, sim);
em.AddCategoryParent(rev, del);
em.AddCategoryParent(phas, mod);
em.AddCategoryParent(flng, mod);
em.AddCategoryParent(chor, mod);
em.AddCategoryParent(lp, flt);
em.AddCategoryParent(bp, flt);
em.AddCategoryParent(hp, flt);
em.AddCategoryParent(comb, flt);
em.AddCategoryParent(alp, flt);
em.AddCategoryParent(eq, flt);
em.AddCategoryParent(peq, eq);
em.AddCategoryParent(meq, eq);
em.AddCategoryParent(ptch, spec);
em.AddCategoryParent(shp, dist);
em.AddCategoryParent(cmp, dyn);
em.AddCategoryParent(exp, dyn);
em.AddCategoryParent(lim, dyn);
em.AddCategoryParent(gate, dyn);
// We also add a couple of categories for internal use. These are not
// in lv2.ttl.
#define ATEAM "http://audacityteam.org/namespace#"
#ifdef EXPERIMENTAL_NOISE_REDUCTION
CatPtr nrm = em.AddCategory(wxT(ATEAM) wxT("NoiseReduction"),
_("Noise Reduction"));
#else
CatPtr nrm = em.AddCategory(wxT(ATEAM) wxT("NoiseRemoval"),
_("Noise Removal"));
#endif
CatPtr pnt = em.AddCategory(wxT(ATEAM) wxT("PitchAndTempo"),
_("Pitch and Tempo"));
CatPtr tim = em.AddCategory(wxT(ATEAM) wxT("TimelineChanger"),
_("Timeline Changer"));
CatPtr aTim = em.AddCategory(wxT(ATEAM) wxT("TimeAnalyser"),
_("Time"));
CatPtr onst = em.AddCategory(wxT(ATEAM) wxT("OnsetDetector"),
_("Onsets"));
em.AddCategoryParent(nrm, util);
em.AddCategoryParent(tim, util);
em.AddCategoryParent(aTim, anal);
em.AddCategoryParent(onst, aTim);
// We freeze the internal subcategory relations between the categories
// added so far so LADSPA/LRDF or other category systems don't ruin
// our hierarchy.
em.FreezeCategories();
#endif
// Generate menu
em.RegisterEffect(new EffectNoise());
em.RegisterEffect(new EffectSilence());
em.RegisterEffect(new EffectToneGen());
em.RegisterEffect(new EffectDtmf());
// A little magic to convert 'Tone' to chirps.
em.RegisterEffect(&((new EffectToneGen())->EnableForChirps()));
// Effect menu
em.RegisterEffect(new EffectAmplify());
//Commented out now that the Compressor effect works better
//em.RegisterEffect(new EffectAvcCompressor());
const int SIMPLE_EFFECT = BUILTIN_EFFECT | PROCESS_EFFECT;
// In this list, designating an effect as 'SIMPLE_EFFECT' just means
// that it should be included in even the most basic of menus.
em.RegisterEffect(new EffectAutoDuck());
em.RegisterEffect(new EffectBassTreble());
em.RegisterEffect(new EffectChangeSpeed());
#ifdef USE_SOUNDTOUCH
em.RegisterEffect(new EffectChangePitch());
em.RegisterEffect(new EffectChangeTempo());
#endif
em.RegisterEffect(new EffectClickRemoval());
em.RegisterEffect(new EffectCompressor());
em.RegisterEffect(new EffectEcho());
em.RegisterEffect(new EffectPaulstretch());
em.RegisterEffect(new EffectEqualization());
em.RegisterEffect(new EffectFadeIn(), SIMPLE_EFFECT);
em.RegisterEffect(new EffectFadeOut(), SIMPLE_EFFECT);
em.RegisterEffect(new EffectInvert());
em.RegisterEffect(new EffectLeveller(), SIMPLE_EFFECT);
#ifdef EXPERIMENTAL_NOISE_REDUCTION
em.RegisterEffect(new EffectNoiseReduction(), SIMPLE_EFFECT);
#else
em.RegisterEffect(new EffectNoiseRemoval(), SIMPLE_EFFECT);
#endif
em.RegisterEffect(new EffectNormalize(), SIMPLE_EFFECT);
em.RegisterEffect(new EffectPhaser());
em.RegisterEffect(new EffectRepair());
em.RegisterEffect(new EffectRepeat());
em.RegisterEffect(new EffectReverb());
em.RegisterEffect(new EffectReverse());
#ifdef EXPERIMENTAL_SCIENCE_FILTERS
em.RegisterEffect(new EffectScienFilter());
#endif
em.RegisterEffect(new EffectStereoToMono(), HIDDEN_EFFECT);// NOT in normal effects list.
em.RegisterEffect(new EffectTruncSilence(), SIMPLE_EFFECT);
#ifdef USE_SBSMS
em.RegisterEffect(new EffectTimeScale());
#endif
em.RegisterEffect(new EffectWahwah());
// Analyze menu
em.RegisterEffect(new EffectFindClipping());
// ============================================================================
// Module registration entry point
//
// This is the symbol that Audacity looks for when the module is built as a
// dynamic library.
//
// When the module is builtin to Audacity, we use the same function, but it is
// declared static so as not to clash with other builtin modules.
// ============================================================================
DECLARE_MODULE_ENTRY(AudacityModule)
{
// Create and register the importer
return new BuiltinEffectsModule(moduleManager, path);
}
void UnloadEffects()
// ============================================================================
// Register this as a builtin module
// ============================================================================
DECLARE_BUILTIN_MODULE(BuiltinsEffectBuiltin);
///////////////////////////////////////////////////////////////////////////////
//
// BuiltinEffectsModule
//
///////////////////////////////////////////////////////////////////////////////
BuiltinEffectsModule::BuiltinEffectsModule(ModuleManagerInterface *moduleManager,
const wxString *path)
{
EffectManager::Get().UnregisterEffects();
mModMan = moduleManager;
if (path)
{
mPath = *path;
}
}
BuiltinEffectsModule::~BuiltinEffectsModule()
{
mPath.Clear();
}
// ============================================================================
// IdentInterface implementation
// ============================================================================
wxString BuiltinEffectsModule::GetPath()
{
return mPath;
}
wxString BuiltinEffectsModule::GetSymbol()
{
return wxTRANSLATE("Builtin Effects");
}
wxString BuiltinEffectsModule::GetName()
{
return wxTRANSLATE("Builtin Effects");
}
wxString BuiltinEffectsModule::GetVendor()
{
return wxTRANSLATE("The Audacity Team");
}
wxString BuiltinEffectsModule::GetVersion()
{
// This "may" be different if this were to be maintained as a separate DLL
return AUDACITY_VERSION_STRING;
}
wxString BuiltinEffectsModule::GetDescription()
{
return wxTRANSLATE("Provides builtin effects to Audacity");
}
// ============================================================================
// ModuleInterface implementation
// ============================================================================
bool BuiltinEffectsModule::Initialize()
{
for (size_t i = 0; i < WXSIZEOF(kEffectNames); i++)
{
mNames.Add(wxString(BUILTIN_EFFECT_PREFIX) + kEffectNames[i]);
}
return true;
}
void BuiltinEffectsModule::Terminate()
{
// Nothing to do here
return;
}
bool BuiltinEffectsModule::AutoRegisterPlugins(PluginManagerInterface & WXUNUSED(pm))
{
// Nothing to do here
return false;
}
wxArrayString BuiltinEffectsModule::FindPlugins(PluginManagerInterface & WXUNUSED(pm))
{
return mNames;
}
bool BuiltinEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxString & path)
{
Effect *effect = Instantiate(path);
if (effect)
{
pm.RegisterPlugin(this, effect);
delete effect;
return true;
}
return false;
}
bool BuiltinEffectsModule::IsPluginValid(const wxString & path)
{
return mNames.Index(path) != wxNOT_FOUND;
}
IdentInterface *BuiltinEffectsModule::CreateInstance(const wxString & path)
{
return Instantiate(path);
}
void BuiltinEffectsModule::DeleteInstance(IdentInterface *instance)
{
Effect *effect = dynamic_cast<Effect *>(instance);
if (effect)
{
delete effect;
}
}
// ============================================================================
// BuiltinEffectsModule implementation
// ============================================================================
Effect *BuiltinEffectsModule::Instantiate(const wxString & path)
{
wxASSERT(path.StartsWith(BUILTIN_EFFECT_PREFIX));
wxASSERT(mNames.Index(path) != wxNOT_FOUND);
switch (mNames.Index(path))
{
EFFECT_LIST;
}
return NULL;
}

View File

@ -8,12 +8,55 @@
**********************************************************************/
#ifndef __AUDACITY_LOAD_EFFECTS__
#define __AUDACITY_LOAD_EFFECTS__
#include "audacity/ModuleInterface.h"
#include "audacity/EffectInterface.h"
#include "audacity/PluginInterface.h"
#include <wx/string.h>
#include "Effect.h"
void LoadEffects();
void UnloadEffects();
///////////////////////////////////////////////////////////////////////////////
//
// BuiltinEffectsModule
//
///////////////////////////////////////////////////////////////////////////////
#endif // define __AUDACITY_LOAD_EFFECTS__
class BuiltinEffectsModule : public ModuleInterface
{
public:
BuiltinEffectsModule(ModuleManagerInterface *moduleManager, const wxString *path);
virtual ~BuiltinEffectsModule();
// IdentInterface implementatino
virtual wxString GetPath();
virtual wxString GetSymbol();
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 wxString & path);
virtual IdentInterface *CreateInstance(const wxString & path);
virtual void DeleteInstance(IdentInterface *instance);
private:
// BuiltinEffectModule implementation
Effect *Instantiate(const wxString & path);
private:
ModuleManagerInterface *mModMan;
wxString mPath;
wxArrayString mNames;
};

View File

@ -9,238 +9,260 @@
*******************************************************************//**
\class EffectNoise
\brief An Effect for the "Generator" menu to add white noise.
\brief An effect to add white noise.
*//*******************************************************************/
#include "../Audacity.h"
#include "../Project.h"
#include "../Prefs.h"
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
#include "../widgets/NumericTextCtrl.h"
#include "Noise.h"
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846 /* pi */
#endif
#define AMP_MIN 0
#define AMP_MAX 1
#include <wx/choice.h>
#include <wx/intl.h>
#include <wx/textctrl.h>
#include <wx/valgen.h>
#include "../Prefs.h"
#include "../widgets/valnum.h"
#include "Noise.h"
enum kTypes
{
kWhite,
kPink,
kBrownian,
kNumTypes
};
static const wxChar *kTypeStrings[kNumTypes] =
{
wxTRANSLATE("White"),
wxTRANSLATE("Pink"),
wxTRANSLATE("Brownian")
};
// Name Type Key Def Min Max Scale
Param( Type, int, wxTRANSLATE("Type"), kWhite, 0, kNumTypes - 1, 1 );
Param( Amp, double, wxTRANSLATE("Amplitude"), 0.8, 0.0, 1.0, 1 );
//
// EffectNoise
//
bool EffectNoise::Init()
EffectNoise::EffectNoise()
{
gPrefs->Read(wxT("/Effects/Noise/Duration"), &mDuration, 1L);
return true;
mType = DEF_Type;
mAmp = DEF_Amp;
mDuration = GetDefaultDuration();
y = z = buf0 = buf1 = buf2 = buf3 = buf4 = buf5 = buf6 = 0;
}
bool EffectNoise::PromptUser()
EffectNoise::~EffectNoise()
{
wxArrayString noiseTypeList;
noiseTypeList.Add(_("White"));
noiseTypeList.Add(_("Pink"));
noiseTypeList.Add(_("Brownian"));
NoiseDialog dlog(this, mParent, _("Noise Generator"));
// dialog will be passed values from effect
// Effect retrieves values from saved config
// Dialog will take care of using them to initialize controls
// If there is a selection, use that duration, otherwise use
// value from saved config: this is useful is user wants to
// replace selection with noise
//
if (mT1 > mT0) {
mDuration = mT1 - mT0;
dlog.nIsSelection = true;
} else {
gPrefs->Read(wxT("/Effects/Noise/Duration"), &mDuration, 30L);
dlog.nIsSelection = false;
}
gPrefs->Read(wxT("/Effects/Noise/Type"), &noiseType, 0L);
gPrefs->Read(wxT("/Effects/Noise/Amplitude"), &noiseAmplitude, 0.8f);
// Initialize dialog locals
dlog.nDuration = mDuration;
dlog.nAmplitude = noiseAmplitude;
dlog.nType = noiseType;
dlog.nTypeList = &noiseTypeList;
// start dialog
dlog.Init();
dlog.TransferDataToWindow();
dlog.Fit();
dlog.ShowModal();
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
// if there was an OK, retrieve values
noiseType = dlog.nType;
mDuration = dlog.nDuration;
noiseAmplitude = dlog.nAmplitude;
return true;
}
bool EffectNoise::TransferParameters( Shuttle & WXUNUSED(shuttle) )
// IdentInterface implementation
wxString EffectNoise::GetSymbol()
{
return true;
return NOISE_PLUGIN_SYMBOL;
}
bool EffectNoise::MakeNoise(float *buffer, sampleCount len, float fs, float amplitude)
wxString EffectNoise::GetDescription()
{
return wxTRANSLATE("Generates one of three different types of noise");
}
// EffectIdentInterface implementation
EffectType EffectNoise::GetType()
{
return EffectTypeGenerate;
}
// EffectClientInterface implementation
int EffectNoise::GetAudioOutCount()
{
return 1;
}
sampleCount EffectNoise::ProcessBlock(float **WXUNUSED(inbuf), float **outbuf, sampleCount size)
{
float *buffer = outbuf[0];
float white;
sampleCount i;
float div = ((float)RAND_MAX) / 2.0f;
float amplitude;
float div = ((float) RAND_MAX) / 2.0f;
switch (noiseType) {
switch (mType)
{
default:
case 0: // white
for(i=0; i<len; i++)
buffer[i] = amplitude * ((rand() / div) - 1.0f);
case kWhite: // white
for (sampleCount i = 0; i < size; i++)
{
buffer[i] = mAmp * ((rand() / div) - 1.0f);
}
break;
case 1: // pink
case kPink: // pink
// based on Paul Kellet's "instrumentation grade" algorithm.
white=0;
// 0.129f is an experimental normalization factor.
amplitude *= 0.129f;
for(i=0; i<len; i++) {
white=(rand() / div) - 1.0f;
buf0=0.99886f * buf0 + 0.0555179f * white;
buf1=0.99332f * buf1 + 0.0750759f * white;
buf2=0.96900f * buf2 + 0.1538520f * white;
buf3=0.86650f * buf3 + 0.3104856f * white;
buf4=0.55000f * buf4 + 0.5329522f * white;
buf5=-0.7616f * buf5 - 0.0168980f * white;
buffer[i] = amplitude *
(buf0 + buf1 + buf2 + buf3 + buf4 + buf5 + buf6 + white * 0.5362);
buf6 = white * 0.115926;
amplitude = mAmp * 0.129f;
for (sampleCount i = 0; i < size; i++)
{
white = (rand() / div) - 1.0f;
buf0 = 0.99886f * buf0 + 0.0555179f * white;
buf1 = 0.99332f * buf1 + 0.0750759f * white;
buf2 = 0.96900f * buf2 + 0.1538520f * white;
buf3 = 0.86650f * buf3 + 0.3104856f * white;
buf4 = 0.55000f * buf4 + 0.5329522f * white;
buf5 = -0.7616f * buf5 - 0.0168980f * white;
buffer[i] = amplitude *
(buf0 + buf1 + buf2 + buf3 + buf4 + buf5 + buf6 + white * 0.5362);
buf6 = white * 0.115926;
}
break;
case 2: // Brownian
white=0;
//float leakage=0.997; // experimental value at 44.1kHz
//double scaling = 0.05; // experimental value at 44.1kHz
// min and max protect against instability at extreme sample rates.
float leakage = ((fs-144.0)/fs < 0.9999)? (fs-144.0)/fs : 0.9999;
float scaling = (9.0/sqrt(fs) > 0.01)? 9.0/sqrt(fs) : 0.01;
case kBrownian: // Brownian
//float leakage=0.997; // experimental value at 44.1kHz
//double scaling = 0.05; // experimental value at 44.1kHz
// min and max protect against instability at extreme sample rates.
float leakage = ((mSampleRate - 144.0) / mSampleRate < 0.9999)
? (mSampleRate - 144.0) / mSampleRate
: 0.9999f;
for(i=0; i<len; i++){
white=(rand() / div) - 1.0f;
float scaling = (9.0 / sqrt(mSampleRate) > 0.01)
? 9.0 / sqrt(mSampleRate)
: 0.01f;
for (sampleCount i = 0; i < size; i++)
{
white = (rand() / div) - 1.0f;
z = leakage * y + white * scaling;
y = (fabs(z) > 1.0) ? (leakage * y - white * scaling) : z;
buffer[i] = amplitude * y;
}
break;
y = fabs(z) > 1.0
? leakage * y - white * scaling
: z;
buffer[i] = mAmp * y;
}
break;
}
return size;
}
bool EffectNoise::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.Write(KEY_Type, kTypeStrings[mType]);
parms.Write(KEY_Amp, mAmp);
return true;
}
void EffectNoise::GenerateBlock(float *data,
const WaveTrack &track,
sampleCount block)
bool EffectNoise::SetAutomationParameters(EffectAutomationParameters & parms)
{
MakeNoise(data, block, track.GetRate(), noiseAmplitude);
ReadAndVerifyEnum(Type, wxArrayString(kNumTypes, kTypeStrings));
ReadAndVerifyDouble(Amp);
mType = Type;
mAmp = Amp;
return true;
}
void EffectNoise::Success()
{
/* save last used values
save duration unless value was got from selection, so we save only
when user explicitely setup a value
*/
if (mT1 == mT0)
gPrefs->Write(wxT("/Effects/Noise/Duration"), mDuration);
// Effect implementation
gPrefs->Write(wxT("/Effects/Noise/Type"), noiseType);
gPrefs->Write(wxT("/Effects/Noise/Amplitude"), noiseAmplitude);
gPrefs->Flush();
bool EffectNoise::Startup()
{
wxString base = wxT("/Effects/Noise/");
// Migrate settings from 2.1.0 or before
// Already migrated, so bail
if (gPrefs->Exists(base + wxT("Migrated")))
{
return true;
}
// Load the old "current" settings
if (gPrefs->Exists(base))
{
gPrefs->Read(base + wxT("Type"), &mType, 0L);
gPrefs->Read(base + wxT("Amplitude"), &mAmp, 0.8f);
SaveUserPreset(GetCurrentSettingsGroup());
// Do not migrate again
gPrefs->Write(base + wxT("Migrated"), true);
gPrefs->Flush();
}
return true;
}
//----------------------------------------------------------------------------
// NoiseDialog
//----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(NoiseDialog, EffectDialog)
EVT_COMMAND(wxID_ANY, EVT_TIMETEXTCTRL_UPDATED, NoiseDialog::OnTimeCtrlUpdate)
END_EVENT_TABLE()
NoiseDialog::NoiseDialog(EffectNoise * effect, wxWindow * parent, const wxString & title)
: EffectDialog(parent, title, INSERT_EFFECT),
mEffect(effect)
void EffectNoise::PopulateOrExchange(ShuttleGui & S)
{
mNoiseDurationT = NULL;
/* // already initialized in EffectNoise::PromptUser
nDuration = mDuration;
nAmplitude = noiseAmplitude;
nType = noiseType;
*/
}
wxASSERT(kNumTypes == WXSIZEOF(kTypeStrings));
wxArrayString typeChoices;
for (int i = 0; i < kNumTypes; i++)
{
typeChoices.Add(wxGetTranslation(kTypeStrings[i]));
}
void NoiseDialog::PopulateOrExchange( ShuttleGui & S )
{
S.StartMultiColumn(2, wxCENTER);
{
S.TieChoice(_("Noise type:"), nType, nTypeList);
S.TieNumericTextBox(_("Amplitude (0-1)") + wxString(wxT(":")), nAmplitude, 10);
S.AddPrompt(_("Duration") + wxString(wxT(":")));
if (mNoiseDurationT == NULL)
{
mNoiseDurationT = new
NumericTextCtrl(NumericConverter::TIME, this,
wxID_ANY,
wxT(""),
nDuration,
mEffect->mProjectRate,
wxDefaultPosition,
wxDefaultSize,
true);
/* use this instead of "seconds" because if a selection is passed to
* the effect, I want it (nDuration) to be used as the duration, and
* with "seconds" this does not always work properly. For example,
* it rounds down to zero... */
mNoiseDurationT->SetName(_("Duration"));
mNoiseDurationT->SetFormatString(mNoiseDurationT->GetBuiltinFormat(nIsSelection==true?(_("hh:mm:ss + samples")):(_("hh:mm:ss + milliseconds"))));
mNoiseDurationT->EnableMenu();
}
S.AddChoice(_("Noise type:"), wxT(""), &typeChoices)->SetValidator(wxGenericValidator(&mType));
FloatingPointValidator<double> vldAmp(1, &mAmp, NUM_VAL_NO_TRAILING_ZEROES);
vldAmp.SetRange(MIN_Amp, MAX_Amp);
S.AddTextBox(_("Amplitude (0-1):"), wxT(""), 12)->SetValidator(vldAmp);
S.AddPrompt(_("Duration:"));
mNoiseDurationT = new
NumericTextCtrl(NumericConverter::TIME,
S.GetParent(),
wxID_ANY,
/* use this instead of "seconds" because if a selection is passed to
* the effect, I want it (nDuration) to be used as the duration, and
* with "seconds" this does not always work properly. For example,
* it rounds down to zero... */
(mT1 > mT0) ? _("hh:mm:ss + samples") : _("hh:mm:ss + milliseconds"),
mDuration,
mProjectRate,
wxDefaultPosition,
wxDefaultSize,
true);
mNoiseDurationT->SetName(_("Duration"));
mNoiseDurationT->EnableMenu();
S.AddWindow(mNoiseDurationT, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL);
}
S.EndMultiColumn();
}
bool NoiseDialog::TransferDataToWindow()
bool EffectNoise::TransferDataToWindow()
{
EffectDialog::TransferDataToWindow();
if (!mUIParent->TransferDataToWindow())
{
return false;
}
// Must handle this ourselves since ShuttleGui doesn't know about it
mNoiseDurationT->SetValue(nDuration);
mNoiseDurationT->SetValue(mDuration);
return true;
}
bool NoiseDialog::TransferDataFromWindow()
bool EffectNoise::TransferDataFromWindow()
{
EffectDialog::TransferDataFromWindow();
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
nAmplitude = TrapDouble(nAmplitude, AMP_MIN, AMP_MAX);
// Must handle this ourselves since ShuttleGui doesn't know about it
nDuration = mNoiseDurationT->GetValue();
mDuration = mNoiseDurationT->GetValue();
return true;
}
void NoiseDialog::OnTimeCtrlUpdate(wxCommandEvent & WXUNUSED(event)) {
Fit();
}

View File

@ -6,119 +6,60 @@
Dominic Mazzoni
An effect for the "Generator" menu to add white noise.
An effect to add white noise.
**********************************************************************/
#ifndef __AUDACITY_EFFECT_NOISE__
#define __AUDACITY_EFFECT_NOISE__
#include <wx/defs.h>
#include <wx/intl.h>
#include <wx/string.h>
#include "Generator.h"
#include "../ShuttleGui.h"
#include "../widgets/NumericTextCtrl.h"
class wxString;
class wxChoice;
class wxTextCtrl;
class NumericTextCtrl;
class ShuttleGui;
#include "Effect.h"
#define __UNINITIALIZED__ (-1)
#define NOISE_PLUGIN_SYMBOL wxTRANSLATE("Noise")
class WaveTrack;
class EffectNoise : public Effect
{
public:
EffectNoise();
virtual ~EffectNoise();
// IdentInterface implementation
class EffectNoise : public BlockGenerator {
virtual wxString GetSymbol();
virtual wxString GetDescription();
public:
EffectNoise() {
SetEffectFlags(BUILTIN_EFFECT | INSERT_EFFECT);
noiseType = 0;
noiseAmplitude = 1.0;
y = z = buf0 = buf1 = buf2 = buf3 = buf4 = buf5 = buf6 = 0;
}
virtual bool Init();
// EffectIdentInterface implementation
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Noise..."));
}
virtual EffectType GetType();
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#GeneratorPlugin"));
return result;
}
// EffectClientInterface implementation
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Noise"));
}
virtual int GetAudioOutCount();
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen);
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
// Return true if the effect supports processing via batch chains.
virtual bool SupportsChains() {
return false;
}
// Effect implementation
virtual wxString GetEffectDescription() {
return wxString::Format(_("Applied effect: Generate Noise, %.6lf seconds"), mDuration);
}
virtual bool Startup();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
virtual wxString GetEffectAction() {
return wxString(_("Generating Noise"));
}
private:
// EffectNoise implementation
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
private:
int mType;
double mAmp;
void GenerateBlock(float *data, const WaveTrack &track, sampleCount block);
void Success();
private:
sampleCount numSamples;
int noiseType;
double noiseAmplitude;
float y, z, buf0, buf1, buf2, buf3, buf4, buf5, buf6;
protected:
virtual bool MakeNoise(float *buffer, sampleCount len, float fs, float amplitude);
//double mCurRate;
// friendship ...
friend class NoiseDialog;
};
//----------------------------------------------------------------------------
// NoiseDialog
//----------------------------------------------------------------------------
// Declare window functions
class NoiseDialog:public EffectDialog {
public:
// constructors and destructors
NoiseDialog(EffectNoise * effect, wxWindow * parent, const wxString & title);
// method declarations
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
private:
void OnTimeCtrlUpdate(wxCommandEvent & event);
DECLARE_EVENT_TABLE()
public:
double nRate;
double nTime;
wxArrayString *nTypeList;
double nDuration;
int nType;
double nAmplitude;
bool nIsSelection;
private:
EffectNoise *mEffect;
NumericTextCtrl *mNoiseDurationT;
};

View File

@ -417,6 +417,25 @@ EffectNoiseReduction::~EffectNoiseReduction()
{
}
// IdentInterface implementation
wxString EffectNoiseReduction::GetSymbol()
{
return NOISEREDUCTION_PLUGIN_SYMBOL;
}
wxString EffectNoiseReduction::GetDescription()
{
return wxTRANSLATE("Removes background noise such as fans, tape noise, or hums");
}
// EffectIdentInterface implementation
EffectType EffectNoiseReduction::GetType()
{
return EffectTypeProcess;
}
bool EffectNoiseReduction::Init()
{
return true;
@ -427,37 +446,12 @@ bool EffectNoiseReduction::CheckWhetherSkipEffect()
return false;
}
wxString EffectNoiseReduction::GetEffectName()
{
return wxString(wxTRANSLATE("Noise Reduction..."));
}
std::set<wxString> EffectNoiseReduction::GetEffectCategories()
{
std::set<wxString> result;
result.insert(wxT("http://audacityteam.org/namespace#NoiseReduction"));
return result;
}
wxString EffectNoiseReduction::GetEffectIdentifier()
{
return wxString(wxT("Noise Reduction"));
}
wxString EffectNoiseReduction::GetEffectAction()
{
if (mSettings->mDoProfile)
return wxString(_("Creating Noise Profile"));
else
return wxString(_("Reducing Noise"));
}
bool EffectNoiseReduction::PromptUser()
bool EffectNoiseReduction::PromptUser(wxWindow *parent, bool isBatch)
{
// We may want to twiddle the levels if we are setting
// from an automation dialog, the only case in which we can
// get here without any wavetracks.
return mSettings->PromptUser(this, mParent,
return mSettings->PromptUser(this, parent,
(mStatistics.get() != 0), (GetNumWaveTracks() == 0));
}
@ -596,13 +590,6 @@ bool EffectNoiseReduction::Settings::Validate() const
return true;
}
bool EffectNoiseReduction::TransferParameters( Shuttle & WXUNUSED(shuttle) )
{
//shuttle.TransferDouble(wxT("Gain"), mNoiseGain, 0.0);
//shuttle.TransferDouble(wxT("Freq"), mFreqSmoothingHz, 0.0);
return true;
}
bool EffectNoiseReduction::Process()
{
// This same code will either reduce noise or profile it
@ -1540,7 +1527,7 @@ EffectNoiseReduction::Dialog::Dialog
(EffectNoiseReduction *effect,
EffectNoiseReduction::Settings *settings,
wxWindow *parent, bool bHasProfile, bool bAllowTwiddleSettings)
: EffectDialog( parent, _("Noise Reduction"), PROCESS_EFFECT)
: EffectDialog( parent, _("Noise Reduction"), EffectTypeProcess)
, m_pEffect(effect)
, m_pSettings(settings) // point to
, mTempSettings(*settings) // copy

View File

@ -17,6 +17,8 @@
#include <memory>
#define NOISEREDUCTION_PLUGIN_SYMBOL wxTRANSLATE("Noise Reduction")
class EffectNoiseReduction: public Effect {
public:
@ -25,13 +27,20 @@ public:
using Effect::TrackProgress;
virtual wxString GetEffectName();
virtual std::set<wxString> GetEffectCategories();
virtual wxString GetEffectIdentifier();
virtual wxString GetEffectAction();
// IdentInterface implementation
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual wxString GetSymbol();
virtual wxString GetDescription();
// EffectIdentInterface implementation
virtual EffectType GetType();
// Effect implementation
// using Effect::TrackProgress;
virtual bool PromptUser(wxWindow *parent = NULL, bool isBatch = false);
virtual bool Init();
virtual bool CheckWhetherSkipEffect();

View File

@ -39,6 +39,9 @@
*//*******************************************************************/
#include "../Audacity.h"
#include "../Experimental.h"
#if !defined(EXPERIMENTAL_NOISE_REDUCTION)
#include "NoiseRemoval.h"
@ -108,6 +111,32 @@ EffectNoiseRemoval::~EffectNoiseRemoval()
delete [] mNoiseThreshold;
}
// IdentInterface implementation
wxString EffectNoiseRemoval::GetSymbol()
{
return wxTRANSLATE("Noise Removal");
}
wxString EffectNoiseRemoval::GetDescription()
{
return wxTRANSLATE("Removes constant background noise such as fans, tape noise, or hums");
}
// EffectIdentInterface implementation
EffectType EffectNoiseRemoval::GetType()
{
return EffectTypeProcess;
}
bool EffectNoiseRemoval::SupportsAutomation()
{
return false;
}
// Effect implementation
#define MAX_NOISE_LEVEL 30
bool EffectNoiseRemoval::Init()
{
@ -121,8 +150,7 @@ bool EffectNoiseRemoval::Init()
bool EffectNoiseRemoval::CheckWhetherSkipEffect()
{
bool rc = (mLevel == 0);
return rc;
return (mLevel == 0);
}
bool EffectNoiseRemoval::PromptUser()
@ -174,14 +202,6 @@ bool EffectNoiseRemoval::PromptUser()
return gPrefs->Flush();
}
bool EffectNoiseRemoval::TransferParameters( Shuttle & WXUNUSED(shuttle) )
{
//shuttle.TransferDouble(wxT("Gain"), mNoiseGain, 0.0);
//shuttle.TransferDouble(wxT("Freq"), mFreqSmoothingHz, 0.0);
//shuttle.TransferDouble(wxT("Time"), mAttackDecayTime, 0.0);
return true;
}
bool EffectNoiseRemoval::Process()
{
Initialize();
@ -866,3 +886,5 @@ void NoiseRemovalDialog::OnTimeSlider(wxCommandEvent & WXUNUSED(event))
mTime = mTimeS->GetValue() / (TIME_MAX*1.0);
mTimeT->SetValue(wxString::Format(wxT("%.2f"), mTime));
}
#endif

View File

@ -12,6 +12,10 @@
#ifndef __AUDACITY_EFFECT_NOISE_REMOVAL__
#define __AUDACITY_EFFECT_NOISE_REMOVAL__
#include "../Audacity.h"
#if !defined(EXPERIMENTAL_NOISE_REDUCTION)
#include "Effect.h"
#include <wx/dialog.h>
@ -26,37 +30,25 @@ class WaveTrack;
#include "../RealFFTf.h"
class EffectNoiseRemoval: public Effect {
class EffectNoiseRemoval : public Effect
{
public:
EffectNoiseRemoval();
virtual ~EffectNoiseRemoval();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Noise Removal..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://audacityteam.org/namespace#NoiseRemoval"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Noise Removal"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
if (mDoProfile)
return wxString(_("Creating Noise Profile"));
else
return wxString(_("Removing Noise"));
}
virtual EffectType GetType();
virtual bool SupportsAutomation();
// Effect implementation
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual bool Init();
virtual bool CheckWhetherSkipEffect();
virtual bool Process();
@ -123,7 +115,7 @@ private:
float **mRealFFTs; // mHistoryLen x mWindowSize
float **mImagFFTs; // mHistoryLen x mWindowSize
friend class NoiseRemovalDialog;
friend class NoiseRemovalDialog;
};
// WDR: class declarations
@ -199,3 +191,5 @@ private:
};
#endif
#endif

View File

@ -12,11 +12,6 @@
\class EffectNormalize
\brief An Effect.
*//****************************************************************//**
\class NormalizeDialog
\brief Dialog used with EffectNormalize
*//*******************************************************************/
@ -24,122 +19,128 @@
#include <math.h>
#include "Normalize.h"
#include "../ShuttleGui.h"
#include "../Internat.h"
#include "../WaveTrack.h"
#include "../Prefs.h"
#include "../Project.h"
#include "../Shuttle.h"
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/defs.h>
#include <wx/intl.h>
#include <wx/msgdlg.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textdlg.h>
#include <wx/valgen.h>
#define NORMALIZE_DB_MIN -145
#define NORMALIZE_DB_MAX 60
#include "../Internat.h"
#include "../Prefs.h"
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
#include "../widgets/valnum.h"
#include "Normalize.h"
// Define keys, defaults, minimums, and maximums for the effect parameters
//
// Name Type Key Def Min Max Scale
Param( Level, double, wxTRANSLATE("Level"), 0.0, -145.0, 0.0, 1 );
Param( RemoveDC, bool, wxTRANSLATE("RemoveDcOffset"), true, false, true, 1 );
Param( ApplyGain, bool, wxTRANSLATE("ApplyGain"), true, false, true, 1 );
Param( StereoInd, bool, wxTRANSLATE("StereoIndependent"), false, false, true, 1 );
BEGIN_EVENT_TABLE(EffectNormalize, wxEvtHandler)
EVT_CHECKBOX(wxID_ANY, EffectNormalize::OnUpdateUI)
EVT_TEXT(wxID_ANY, EffectNormalize::OnUpdateUI)
END_EVENT_TABLE()
EffectNormalize::EffectNormalize()
{
Init();
mLevel = MIN_Level;
mDC = DEF_RemoveDC;
mGain = DEF_ApplyGain;
mStereoInd = DEF_StereoInd;
}
static double gFrameSum; //lda odd ... having this as member var crashed on exit
bool EffectNormalize::Init()
EffectNormalize::~EffectNormalize()
{
int boolProxy = gPrefs->Read(wxT("/Effects/Normalize/RemoveDcOffset"), 1);
mDC = (boolProxy == 1);
boolProxy = gPrefs->Read(wxT("/Effects/Normalize/Normalize"), 1);
mGain = (boolProxy == 1);
gPrefs->Read(wxT("/Effects/Normalize/Level"), &mLevel, -1.0);
if(mLevel > 0.0) // this should never happen
mLevel = -mLevel;
boolProxy = gPrefs->Read(wxT("/Effects/Normalize/StereoIndependent"), 0L);
mStereoInd = (boolProxy == 1);
}
// IdentInterface implementation
wxString EffectNormalize::GetSymbol()
{
return NORMALIZE_PLUGIN_SYMBOL;
}
wxString EffectNormalize::GetDescription()
{
return wxTRANSLATE("Sets the peak amplitude of a one or more tracks");
}
// EffectIdentInterface implementation
EffectType EffectNormalize::GetType()
{
return EffectTypeProcess;
}
// EffectClientInterface implementation
bool EffectNormalize::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.Write(KEY_Level, mLevel);
parms.Write(KEY_ApplyGain, mGain);
parms.Write(KEY_RemoveDC, mDC);
parms.Write(KEY_StereoInd, mStereoInd);
return true;
}
wxString EffectNormalize::GetEffectDescription() // useful only after parameter values have been set
bool EffectNormalize::SetAutomationParameters(EffectAutomationParameters & parms)
{
// Note: This is useful only after ratio has been set.
wxString strResult =
/* i18n-hint: First %s is the effect name, 2nd and 3rd are either true or
* false (translated below) if those options were selected */
wxString::Format(_("Applied effect: %s remove dc offset = %s, normalize amplitude = %s, stereo independent %s"),
this->GetEffectName().c_str(),
/* i18n-hint: true here means that the option was
* selected. Opposite false if not selected */
mDC ? _("true") : _("false"),
mGain ? _("true") : _("false"),
mStereoInd ? _("true") : _("false"));
if (mGain)
strResult += wxString::Format(_(", maximum amplitude = %.1f dB"), mLevel);
ReadAndVerifyDouble(Level);
ReadAndVerifyBool(ApplyGain);
ReadAndVerifyBool(RemoveDC);
ReadAndVerifyBool(StereoInd);
return strResult;
}
mLevel = Level;
mGain = ApplyGain;
mDC = RemoveDC;
mStereoInd = StereoInd;
bool EffectNormalize::TransferParameters( Shuttle & shuttle )
{
shuttle.TransferBool( wxT("ApplyGain"), mGain, true );
shuttle.TransferBool( wxT("RemoveDcOffset"), mDC, true );
shuttle.TransferDouble( wxT("Level"), mLevel, 0.0);
shuttle.TransferBool( wxT("StereoIndependent"), mStereoInd, false );
return true;
}
// Effect implementation
bool EffectNormalize::CheckWhetherSkipEffect()
{
bool rc = ((mGain == false) && (mDC == false));
return rc;
return ((mGain == false) && (mDC == false));
}
void EffectNormalize::End()
bool EffectNormalize::Startup()
{
bool bValidate;
gPrefs->Read(wxT("/Validate/Enabled"), &bValidate, false ); // this never get written! Why is this here? MJS
if( bValidate )
wxString base = wxT("/Effects/Normalize/");
// Migrate settings from 2.1.0 or before
// Already migrated, so bail
if (gPrefs->Exists(base + wxT("Migrated")))
{
int checkOffset = abs((int)(mOffset * 1000.0));
gPrefs->Write(wxT("/Validate/Norm_Offset"), checkOffset);
int checkMultiplier = abs((int)(mMult * 1000.0));
gPrefs->Write(wxT("/Validate/Norm_Multiplier"), checkMultiplier);
int checkFrameSum = (int)gFrameSum;
gPrefs->Write(wxT("/Validate/Norm_FrameSum"), checkFrameSum);
return true;
}
// Load the old "current" settings
if (gPrefs->Exists(base))
{
int boolProxy = gPrefs->Read(base + wxT("RemoveDcOffset"), 1);
mDC = (boolProxy == 1);
boolProxy = gPrefs->Read(base + wxT("Normalize"), 1);
mGain = (boolProxy == 1);
gPrefs->Read(base + wxT("Level"), &mLevel, -1.0);
if(mLevel > 0.0) // this should never happen
mLevel = -mLevel;
boolProxy = gPrefs->Read(base + wxT("StereoIndependent"), 0L);
mStereoInd = (boolProxy == 1);
SaveUserPreset(GetCurrentSettingsGroup());
// Do not migrate again
gPrefs->Write(base + wxT("Migrated"), true);
gPrefs->Flush();
}
}
bool EffectNormalize::PromptUser()
{
NormalizeDialog dlog(this, mParent);
dlog.mGain = mGain;
dlog.mDC = mDC;
dlog.mLevel = mLevel;
dlog.mStereoInd = mStereoInd;
dlog.TransferDataToWindow();
dlog.CentreOnParent();
dlog.ShowModal();
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
mGain = dlog.mGain;
mDC = dlog.mDC;
mLevel = dlog.mLevel;
mStereoInd = dlog.mStereoInd;
gPrefs->Write(wxT("/Effects/Normalize/RemoveDcOffset"), mDC);
gPrefs->Write(wxT("/Effects/Normalize/Normalize"), mGain);
gPrefs->Write(wxT("/Effects/Normalize/Level"), mLevel);
gPrefs->Write(wxT("/Effects/Normalize/StereoIndependent"), mStereoInd);
return gPrefs->Flush();
return true;
}
bool EffectNormalize::Process()
@ -150,8 +151,8 @@ bool EffectNormalize::Process()
float ratio;
if( mGain )
ratio = pow(10.0,TrapDouble(mLevel, // same value used for all tracks
NORMALIZE_DB_MIN,
NORMALIZE_DB_MAX)/20.0);
MIN_Level,
MAX_Level)/20.0);
else
ratio = 1.0;
@ -262,6 +263,76 @@ bool EffectNormalize::Process()
return bGoodResult;
}
void EffectNormalize::PopulateOrExchange(ShuttleGui & S)
{
mCreating = true;
S.StartVerticalLay(0);
{
S.StartMultiColumn(2, wxALIGN_CENTER);
{
S.StartVerticalLay(false);
{
mDCCheckBox = S.AddCheckBox(_("Remove DC offset (center on 0.0 vertically)"),
mDC ? wxT("true") : wxT("false"));
mDCCheckBox->SetValidator(wxGenericValidator(&mDC));
S.StartHorizontalLay(wxALIGN_CENTER, false);
{
mGainCheckBox = S.AddCheckBox(_("Normalize maximum amplitude to"),
mGain ? wxT("true") : wxT("false"));
mGainCheckBox->SetValidator(wxGenericValidator(&mGain));
FloatingPointValidator<double> vldLevel(1, &mLevel);
vldLevel.SetRange(MIN_Level, MAX_Level);
mLevelTextCtrl = S.AddTextBox(wxT(""), wxT(""), 10);
mLevelTextCtrl->SetName(_("Maximum amplitude dB"));
mLevelTextCtrl->SetValidator(vldLevel);
mLeveldB = S.AddVariableText(_("dB"), false,
wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
mWarning = S.AddVariableText( wxT(""), false,
wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
}
S.EndHorizontalLay();
mStereoIndCheckBox = S.AddCheckBox(_("Normalize stereo channels independently"),
mStereoInd ? wxT("true") : wxT("false"));
mStereoIndCheckBox->SetValidator(wxGenericValidator(&mStereoInd));
}
S.EndVerticalLay();
}
S.EndMultiColumn();
}
S.EndVerticalLay();
mCreating = false;
}
bool EffectNormalize::TransferDataToWindow()
{
if (!mUIParent->TransferDataToWindow())
{
return false;
}
UpdateUI();
return true;
}
bool EffectNormalize::TransferDataFromWindow()
{
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
return true;
}
// EffectNormalize implementation
void EffectNormalize::AnalyseTrack(WaveTrack * track, wxString msg)
{
if(mGain) {
@ -427,160 +498,29 @@ void EffectNormalize::ProcessData(float *buffer, sampleCount len)
for(i=0; i<len; i++) {
float adjFrame = (buffer[i] + mOffset) * mMult;
buffer[i] = adjFrame;
gFrameSum += fabs(adjFrame); //lda: validation.
}
}
//----------------------------------------------------------------------------
// NormalizeDialog
//----------------------------------------------------------------------------
#define ID_DC_REMOVE 10002
#define ID_NORMALIZE_AMPLITUDE 10003
#define ID_LEVEL_TEXT 10004
BEGIN_EVENT_TABLE(NormalizeDialog, EffectDialog)
EVT_CHECKBOX(ID_DC_REMOVE, NormalizeDialog::OnUpdateUI)
EVT_CHECKBOX(ID_NORMALIZE_AMPLITUDE, NormalizeDialog::OnUpdateUI)
EVT_BUTTON(ID_EFFECT_PREVIEW, NormalizeDialog::OnPreview)
EVT_TEXT(ID_LEVEL_TEXT, NormalizeDialog::OnUpdateUI)
END_EVENT_TABLE()
NormalizeDialog::NormalizeDialog(EffectNormalize *effect,
wxWindow * parent)
: EffectDialog(parent, _("Normalize"), PROCESS_EFFECT),
mEffect(effect)
void EffectNormalize::OnUpdateUI(wxCommandEvent & WXUNUSED(evt))
{
mDC = false;
mGain = false;
mLevel = 0;
mStereoInd = false;
Init();
UpdateUI();
}
void NormalizeDialog::PopulateOrExchange(ShuttleGui & S)
void EffectNormalize::UpdateUI()
{
wxTextValidator vld(wxFILTER_NUMERIC);
S.StartTwoColumn();
if (!mUIParent->TransferDataFromWindow())
{
S.StartVerticalLay(false);
{
mDCCheckBox =
S.Id(ID_DC_REMOVE).
AddCheckBox(_("Remove DC offset (center on 0.0 vertically)"),
mDC ? wxT("true") : wxT("false"));
S.StartHorizontalLay(wxALIGN_CENTER, false);
{
mGainCheckBox =
S.Id(ID_NORMALIZE_AMPLITUDE).
AddCheckBox(_("Normalize maximum amplitude to"),
mGain ? wxT("true") : wxT("false"));
mLevelTextCtrl = S.Id(ID_LEVEL_TEXT).AddTextBox(wxT(""), wxT(""), 10);
mLevelTextCtrl->SetValidator(vld);
mLevelTextCtrl->SetName(_("Maximum amplitude dB"));
mLeveldB = S.AddVariableText(_("dB"), false,
wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
mWarning = S.AddVariableText( wxT(""), false,
wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
}
S.EndHorizontalLay();
mStereoIndCheckBox = S.AddCheckBox(_("Normalize stereo channels independently"),
mStereoInd ? wxT("true") : wxT("false"));
}
S.EndVerticalLay();
mWarning->SetLabel(_(". Maximum 0dB."));
EnableApply(false);
return;
}
S.EndTwoColumn();
}
mWarning->SetLabel(wxT(""));
bool NormalizeDialog::TransferDataToWindow()
{
mGainCheckBox->SetValue(mGain);
mDCCheckBox->SetValue(mDC);
mLevelTextCtrl->SetValue(Internat::ToDisplayString(mLevel, 1));
mStereoIndCheckBox->SetValue(mStereoInd);
UpdateUI();
TransferDataFromWindow();
return true;
}
bool NormalizeDialog::TransferDataFromWindow()
{
mGain = mGainCheckBox->GetValue();
mDC = mDCCheckBox->GetValue();
mLevel = Internat::CompatibleToDouble(mLevelTextCtrl->GetValue());
mStereoInd = mStereoIndCheckBox->GetValue();
return true;
}
void NormalizeDialog::OnUpdateUI(wxCommandEvent& WXUNUSED(event))
{
UpdateUI();
}
void NormalizeDialog::UpdateUI()
{
// Disallow level stuff if not normalizing
bool enable = mGainCheckBox->GetValue();
mLevelTextCtrl->Enable(enable);
mLeveldB->Enable(enable);
mStereoIndCheckBox->Enable(enable);
mLevelTextCtrl->Enable(mGain);
mLeveldB->Enable(mGain);
mStereoIndCheckBox->Enable(mGain);
// Disallow OK/Preview if doing nothing
wxButton *ok = (wxButton *) FindWindow(wxID_OK);
wxButton *preview = (wxButton *) FindWindow(ID_EFFECT_PREVIEW);
bool dc = mDCCheckBox->GetValue();
if( !enable && !dc )
{
ok->Enable(false);
preview->Enable(false);
}
else
{
ok->Enable(true);
preview->Enable(true);
}
// Disallow OK/Preview if requested level is > 0
wxString val = mLevelTextCtrl->GetValue();
double r;
val.ToDouble(&r);
if(r > 0.0)
{
ok->Enable(false);
preview->Enable(false);
mWarning->SetLabel(_(". Maximum 0dB."));
}
else
mWarning->SetLabel(wxT(""));
}
void NormalizeDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
{
TransferDataFromWindow();
// Save & restore parameters around Preview, because we didn't do OK.
bool oldGain = mEffect->mGain;
bool oldDC = mEffect->mDC;
double oldLevel = mEffect->mLevel;
bool oldStereoInd = mEffect->mStereoInd;
mEffect->mGain = mGain;
mEffect->mDC = mDC;
mEffect->mLevel = mLevel;
mEffect->mStereoInd = mStereoInd;
mEffect->Preview();
mEffect->mGain = oldGain;
mEffect->mDC = oldDC;
mEffect->mLevel = oldLevel;
mEffect->mStereoInd = oldStereoInd;
EnableApply(mGain || mDC);
}

View File

@ -12,63 +12,64 @@
#ifndef __AUDACITY_EFFECT_NORMALIZE__
#define __AUDACITY_EFFECT_NORMALIZE__
#include "Effect.h"
#include <wx/checkbox.h>
#include <wx/event.h>
#include <wx/stattext.h>
#include <wx/string.h>
#include <wx/textctrl.h>
class wxString;
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
class WaveTrack;
#include "Effect.h"
class EffectNormalize: public Effect
#define NORMALIZE_PLUGIN_SYMBOL wxTRANSLATE("Normalize")
class EffectNormalize : public Effect
{
friend class NormalizeDialog;
public:
public:
EffectNormalize();
virtual ~EffectNormalize();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Normalize..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#UtilityPlugin"));
result.insert(wxT("http://lv2plug.in/ns/lv2core#AmplifierPlugin"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
// This is just used internally, users should not see it. Do not translate.
virtual wxString GetEffectIdentifier() {
return wxT("Normalize");
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Normalizing..."));
}
virtual EffectType GetType();
virtual wxString GetEffectDescription(); // useful only after parameter values have been set
// EffectClientInterface implementation
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
// Effect implementation
virtual bool Init();
virtual void End();
virtual bool CheckWhetherSkipEffect();
virtual bool Startup();
virtual bool Process();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
private:
// EffectNormalize implementation
private:
bool ProcessOne(WaveTrack * t, wxString msg);
virtual void AnalyseTrack(WaveTrack * track, wxString msg);
virtual void AnalyzeData(float *buffer, sampleCount len);
bool AnalyseDC(WaveTrack * track, wxString msg);
virtual void ProcessData(float *buffer, sampleCount len);
void OnUpdateUI(wxCommandEvent & evt);
void UpdateUI();
private:
double mLevel;
bool mGain;
bool mDC;
double mLevel;
bool mStereoInd;
int mCurTrackNum;
@ -80,32 +81,7 @@ class EffectNormalize: public Effect
float mMax;
double mSum;
sampleCount mCount;
};
//----------------------------------------------------------------------------
// NormalizeDialog
//----------------------------------------------------------------------------
class NormalizeDialog: public EffectDialog
{
public:
// constructors and destructors
NormalizeDialog(EffectNormalize *effect, wxWindow * parent);
// method declarations
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
private:
// handlers
void OnUpdateUI(wxCommandEvent& evt);
void OnPreview(wxCommandEvent &event);
void UpdateUI();
private:
EffectNormalize *mEffect;
wxCheckBox *mGainCheckBox;
wxCheckBox *mDCCheckBox;
wxTextCtrl *mLevelTextCtrl;
@ -113,13 +89,9 @@ class NormalizeDialog: public EffectDialog
wxStaticText *mWarning;
wxCheckBox *mStereoIndCheckBox;
DECLARE_EVENT_TABLE()
bool mCreating;
public:
bool mGain;
bool mDC;
double mLevel;
bool mStereoInd;
DECLARE_EVENT_TABLE();
};
#endif

View File

@ -1,87 +1,135 @@
/**********************************************************************
Audacity: A Digital Audio Editor
Audacity: A Digital Audio Editor
Paulstretch.cpp
Paulstretch.cpp
Nasca Octavian Paul (Paul Nasca)
Some GUI code was taken from the Echo effect
Nasca Octavian Paul (Paul Nasca)
Some GUI code was taken from the Echo effect
*******************************************************************/
*******************************************************************//**
/**
\class EffectPaulstretch
\brief An Extreme Time Stretch and Time Smear effect
\class EffectPaulstretch
\brief An Extreme Time Stretch and Time Smear effect
*//****************************************************************/
/**
\class PaulstretchDialog
\brief PaulstretchDialog used with EffectPaulstretch
*/
/*******************************************************************/
*//*******************************************************************/
#include "../Audacity.h"
#include <wx/defs.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/validate.h>
#include <wx/valtext.h>
#include <wx/generic/textdlgg.h>
#include <wx/intl.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
#include <wx/intl.h>
#include <wx/valgen.h>
#include "../FFT.h"
#include "../widgets/valnum.h"
#include "Paulstretch.h"
#include "../WaveTrack.h"
#include "../FFT.h"
// Define keys, defaults, minimums, and maximums for the effect parameters
EffectPaulstretch::EffectPaulstretch(){
amount=10.0;
time_resolution=0.25;
//
// Name Type Key Def Min Max Scale
Param( Amount, float, wxTRANSLATE("Stretch Factor"), 10.0, 1.0, FLT_MAX, 1 );
Param( Time, float, wxTRANSLATE("Time Resolution"), 0.25f, 0.001f, FLT_MAX, 1 );
class PaulStretch
{
public:
PaulStretch(float rap_,int in_bufsize_,float samplerate_);
//in_bufsize is also a half of a FFT buffer (in samples)
virtual ~PaulStretch();
void process(float *smps,int nsmps);
int in_bufsize;
int poolsize;//how many samples are inside the input_pool size (need to know how many samples to fill when seeking)
int out_bufsize;
float *out_buf;
int get_nsamples();//how many samples are required to be added in the pool next time
int get_nsamples_for_fill();//how many samples are required to be added for a complete buffer refill (at start of the song or after seek)
void set_rap(float newrap);//set the current stretch value
protected:
virtual void process_spectrum(float *WXUNUSED(freq)){};
float samplerate;
private:
float *in_pool;//de marimea in_bufsize
float rap;
float *old_out_smp_buf;
float *fft_smps,*fft_c,*fft_s,*fft_freq,*fft_tmp;
double remained_samples;//how many fraction of samples has remained (0..1)
};
wxString EffectPaulstretch::GetEffectDescription(){
// Note: This is useful only after values have been set.
return wxString::Format(_("Applied effect: %s stretch factor = %f times, time resolution = %f seconds"),
this->GetEffectName().c_str(), amount,time_resolution);
//
// EffectPaulstretch
//
};
BEGIN_EVENT_TABLE(EffectPaulstretch, wxEvtHandler)
EVT_TEXT(wxID_ANY, EffectPaulstretch::OnText)
END_EVENT_TABLE()
bool EffectPaulstretch::PromptUser(){
PaulstretchDialog dlog(this, mParent);
dlog.amount = amount;
dlog.time_resolution = time_resolution;
dlog.CentreOnParent();
dlog.ShowModal();
EffectPaulstretch::EffectPaulstretch()
{
amount = DEF_Amount;
time_resolution = DEF_Time;
}
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
EffectPaulstretch::~EffectPaulstretch()
{
}
amount = dlog.amount;
time_resolution = dlog.time_resolution;
// IdentInterface implementation
wxString EffectPaulstretch::GetSymbol()
{
return PAULSTRETCH_PLUGIN_SYMBOL;
}
wxString EffectPaulstretch::GetDescription()
{
return wxTRANSLATE("Use Paulstretch only for an extreme time-stretch or \"stasis\" effect");
}
// EffectIdentInterface implementation
EffectType EffectPaulstretch::GetType()
{
return EffectTypeProcess;
}
// EffectClientInterface implementation
bool EffectPaulstretch::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.WriteFloat(KEY_Amount, amount);
parms.WriteFloat(KEY_Time, time_resolution);
return true;
};
}
bool EffectPaulstretch::TransferParameters(Shuttle &shuttle){
shuttle.TransferFloat(wxT("Stretch Factor"),amount,10.0);
shuttle.TransferFloat(wxT("Time Resolution"),time_resolution,0.25);
bool EffectPaulstretch::SetAutomationParameters(EffectAutomationParameters & parms)
{
ReadAndVerifyFloat(Amount);
ReadAndVerifyFloat(Time);
amount = Amount;
time_resolution = Time;
return true;
};
}
// Effect implementation
bool EffectPaulstretch::Process(){
bool EffectPaulstretch::Process()
{
CopyInputTracks();
SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks);
WaveTrack *track = (WaveTrack *) iter.First();
@ -108,44 +156,57 @@ bool EffectPaulstretch::Process(){
return true;
}
class PaulStretch{
public:
PaulStretch(float rap_,int in_bufsize_,float samplerate_);
//in_bufsize is also a half of a FFT buffer (in samples)
virtual ~PaulStretch();
void EffectPaulstretch::PopulateOrExchange(ShuttleGui & S)
{
S.StartMultiColumn(2, wxALIGN_CENTER);
{
FloatingPointValidator<float> vldAmount(1, &amount);
vldAmount.SetMin(MIN_Amount);
void process(float *smps,int nsmps);
/* i18n-hint: This is how many times longer the sound will be, e.g. applying
* the effect to a 1-second sample, with the default Stretch Factor of 10.0
* will give an (approximately) 10 second sound
*/
S.AddTextBox(_("Stretch Factor:"), wxT(""), 10)->SetValidator(vldAmount);
int in_bufsize;
int poolsize;//how many samples are inside the input_pool size (need to know how many samples to fill when seeking)
int out_bufsize;
float *out_buf;
int get_nsamples();//how many samples are required to be added in the pool next time
int get_nsamples_for_fill();//how many samples are required to be added for a complete buffer refill (at start of the song or after seek)
void set_rap(float newrap);//set the current stretch value
protected:
virtual void process_spectrum(float *WXUNUSED(freq)){};
float samplerate;
private:
float *in_pool;//de marimea in_bufsize
float rap;
float *old_out_smp_buf;
float *fft_smps,*fft_c,*fft_s,*fft_freq,*fft_tmp;
double remained_samples;//how many fraction of samples has remained (0..1)
FloatingPointValidator<float> vldTime(1, &time_resolution);
vldTime.SetMin(MIN_Time);
S.AddTextBox(_("Time Resolution (seconds):"), wxT(""), 10)->SetValidator(vldTime);
}
S.EndMultiColumn();
};
bool EffectPaulstretch::TransferDataToWindow()
{
if (!mUIParent->TransferDataToWindow())
{
return false;
}
bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int count){
return true;
}
bool EffectPaulstretch::TransferDataFromWindow()
{
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
return true;
}
// EffectPaulstretch implementation
void EffectPaulstretch::OnText(wxCommandEvent & WXUNUSED(evt))
{
EnableApply(mUIParent->TransferDataFromWindow());
}
bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int count)
{
int stretch_buf_size;//must be power of 2 (because Audacity's fft requires it)
if (time_resolution<0.001) time_resolution=0.001f;
if (time_resolution<MIN_Time) time_resolution=MIN_Time;
{
float tmp=track->GetRate()*time_resolution*0.5;
tmp=log(tmp)/log(2.0);
@ -154,7 +215,7 @@ bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int coun
};
if (stretch_buf_size<128) stretch_buf_size=128;
double amount=this->amount;
if (amount<1.0) amount=1.0;
if (amount<MIN_Amount) amount=MIN_Amount;
sampleCount start = track->TimeToLongSamples(t0);
sampleCount end = track->TimeToLongSamples(t1);
@ -249,14 +310,11 @@ bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int coun
return !cancelled;
};
/*************************************************************/
PaulStretch::PaulStretch(float rap_,int in_bufsize_,float samplerate_){
PaulStretch::PaulStretch(float rap_,int in_bufsize_,float samplerate_)
{
samplerate=samplerate_;
rap=rap_;
in_bufsize=in_bufsize_;
@ -286,7 +344,8 @@ PaulStretch::PaulStretch(float rap_,int in_bufsize_,float samplerate_){
};
PaulStretch::~PaulStretch(){
PaulStretch::~PaulStretch()
{
delete [] out_buf;
delete [] old_out_smp_buf;
delete [] in_pool;
@ -297,12 +356,14 @@ PaulStretch::~PaulStretch(){
delete [] fft_tmp;
};
void PaulStretch::set_rap(float newrap){
void PaulStretch::set_rap(float newrap)
{
if (rap>=1.0) rap=newrap;
else rap=1.0;
};
void PaulStretch::process(float *smps,int nsmps){
void PaulStretch::process(float *smps,int nsmps)
{
//add new samples to the pool
if ((smps!=NULL)&&(nsmps!=0)){
if (nsmps>poolsize){
@ -373,8 +434,8 @@ void PaulStretch::process(float *smps,int nsmps){
};
int PaulStretch::get_nsamples(){
int PaulStretch::get_nsamples()
{
double r=out_bufsize/rap;
int ri=(int)floor(r);
double rf=r-floor(r);
@ -392,93 +453,7 @@ int PaulStretch::get_nsamples(){
return ri;
};
int PaulStretch::get_nsamples_for_fill(){
int PaulStretch::get_nsamples_for_fill()
{
return poolsize;
};
BEGIN_EVENT_TABLE(PaulstretchDialog, EffectDialog)
EVT_BUTTON(ID_EFFECT_PREVIEW, PaulstretchDialog::OnPreview)
END_EVENT_TABLE()
PaulstretchDialog::PaulstretchDialog(EffectPaulstretch *effect, wxWindow *parent):EffectDialog(parent,wxT("Paulstretch")){
m_bLoopDetect=false;
m_pEffect=effect;
m_pTextCtrl_Amount=NULL;
m_pTextCtrl_TimeResolution=NULL;
amount=10.0;
time_resolution=0.25;
Init();
};
void PaulstretchDialog::PopulateOrExchange(ShuttleGui & S)
{
S.StartMultiColumn(2, wxALIGN_CENTER);
{
/* i18n-hint: This is how many times longer the sound will be, e.g. applying
* the effect to a 1-second sample, with the default Stretch Factor of 10.0
* will give an (approximately) 10 second sound
*/
m_pTextCtrl_Amount = S.AddTextBox(_("Stretch Factor:"),wxT("10.0"),10);
m_pTextCtrl_Amount->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
m_pTextCtrl_TimeResolution= S.AddTextBox(_("Time Resolution (seconds):"), wxT("0.25"),10);
m_pTextCtrl_TimeResolution->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
}
S.EndMultiColumn();
};
bool PaulstretchDialog::TransferDataToWindow(){
m_bLoopDetect = true;
wxString str;
if (m_pTextCtrl_Amount) {
str.Printf(wxT("%g"), amount);
m_pTextCtrl_Amount->SetValue(str);
}
if (m_pTextCtrl_TimeResolution) {
str.Printf(wxT("%g"), time_resolution);
m_pTextCtrl_TimeResolution->SetValue(str);
}
m_bLoopDetect = false;
return true;
}
bool PaulstretchDialog::TransferDataFromWindow(){
double newValue;
wxString str;
if (m_pTextCtrl_Amount) {
str = m_pTextCtrl_Amount->GetValue();
str.ToDouble(&newValue);
amount = (float)(newValue);
}
if (m_pTextCtrl_TimeResolution) {
str = m_pTextCtrl_TimeResolution->GetValue();
str.ToDouble(&newValue);
time_resolution = (float)(newValue);
}
return true;
}
void PaulstretchDialog::OnPreview(wxCommandEvent & WXUNUSED(event)){
TransferDataFromWindow();
// Save & restore parameters around Preview, because we didn't do OK.
float oldAmount = m_pEffect->amount;
float oldTimeResolution = m_pEffect->time_resolution;
m_pEffect->amount = amount;
m_pEffect->time_resolution = time_resolution;
m_pEffect->Preview();
m_pEffect->amount = oldAmount;
m_pEffect->time_resolution = oldTimeResolution;
}

View File

@ -10,88 +10,56 @@
#ifndef __AUDACITY_EFFECT_PAULSTRETCH__
#define __AUDACITY_EFFECT_PAULSTRETCH__
#include "SimpleMono.h"
#include <wx/dialog.h>
#include <wx/intl.h>
#include <wx/string.h>
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
class WaveTrack;
#include "Effect.h"
class EffectPaulstretch:public Effect{
#define PAULSTRETCH_PLUGIN_SYMBOL wxTRANSLATE("Paulstretch")
public:
EffectPaulstretch();
class EffectPaulstretch : public Effect
{
public:
EffectPaulstretch();
virtual ~EffectPaulstretch();
virtual wxString GetEffectName() {
/* i18n-hint: This is the name of the effect, i.e. a proper noun, which
* wouldn't normally get translated. It's the combination of the author's
* name (Paul) with what it does (stretch sound)
*/
return wxString(wxTRANSLATE("Paulstretch..."));
}
// IdentInterface implementation
virtual wxString GetEffectAction() {
/* i18n-hint: This is the text that is shown whilst the effect is being
* processed. The effect stretches the input in time, making the sound
* much longer and spread out whilst at the same pitch. Paulstretch is the
* name of the effect (it's also translated on it's own).
*/
return wxString(_("Stretching with Paulstretch"));
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {return wxT("Paulstretch");}
// EffectIdentInterface implementation
// Useful only after PromptUser values have been set.
virtual wxString GetEffectDescription();
virtual EffectType GetType();
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual bool Process();
// EffectClientInterface implementation
protected:
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
bool ProcessOne(WaveTrack *track,double t0,double t1,int count);
float amount;
float time_resolution;//seconds
// Effect implementation
friend class PaulstretchDialog;
private:
double m_t1;
virtual bool Process();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
private:
// EffectPaulstretch implementation
void OnText(wxCommandEvent & evt);
bool ProcessOne(WaveTrack *track, double t0, double t1, int count);
private:
float amount;
float time_resolution; //seconds
double m_t1;
DECLARE_EVENT_TABLE();
};
//--------------------------------------------------------------------------
// PaulstretchDialog
//--------------------------------------------------------------------------
class PaulstretchDialog:public EffectDialog {
public:
PaulstretchDialog(EffectPaulstretch * effect, wxWindow * parent);
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
private:
// handlers
void OnPreview( wxCommandEvent &event );
private:
bool m_bLoopDetect;
EffectPaulstretch * m_pEffect;
// controls
wxTextCtrl * m_pTextCtrl_Amount;
wxTextCtrl * m_pTextCtrl_TimeResolution;
public:
// effect parameters
float amount;
float time_resolution;//seconds
private:
DECLARE_EVENT_TABLE()
};
#endif

View File

@ -14,560 +14,427 @@
*******************************************************************//**
\class EffectPhaser
\brief An EffectSimpleMono
*//****************************************************************//**
\class PhaserDialog
\brief Dialog for EffectPhaser
\brief An Effect
*//*******************************************************************/
#include "../Audacity.h"
#include <math.h>
#include <wx/intl.h>
#include "../widgets/valnum.h"
#include "Phaser.h"
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
#include "../FFT.h"
enum
{
ID_Stages = 10000,
ID_DryWet,
ID_Freq,
ID_Phase,
ID_Depth,
ID_Feedback
};
#include <wx/button.h>
#include <wx/textctrl.h>
#include <wx/sizer.h>
#include <wx/spinctrl.h>
#include <wx/stattext.h>
#include <wx/valtext.h>
// Name Type Key Def Min Max Scale
Param( Stages, int, wxTRANSLATE("Stages"), 2, 2, NUM_STAGES, 1 );
Param( DryWet, int, wxTRANSLATE("DryWet"), 128, 0, 255, 1 );
Param( Freq, double, wxTRANSLATE("Freq"), 0.4, 0.1, 4.0, 10 );
Param( Phase, double, wxTRANSLATE("Phase"), 0.0, 0.0, 359.0, 1 );
Param( Depth, int, wxTRANSLATE("Depth"), 100, 0, 255, 1 );
Param( Feedback, int, wxTRANSLATE("Feedback"), 0, -100, 100, 1 );
#include <math.h>
//
#define phaserlfoshape 4.0
// How many samples are processed before recomputing the lfo value again
#define lfoskipsamples 20
//
// EffectPhaser
//
#define phaserlfoshape 4.0
// How many samples are processed before compute the lfo value again
#define lfoskipsamples 20
BEGIN_EVENT_TABLE(EffectPhaser, wxEvtHandler)
EVT_SLIDER(ID_Stages, EffectPhaser::OnStagesSlider)
EVT_SLIDER(ID_DryWet, EffectPhaser::OnDryWetSlider)
EVT_SLIDER(ID_Freq, EffectPhaser::OnFreqSlider)
EVT_SLIDER(ID_Phase, EffectPhaser::OnPhaseSlider)
EVT_SLIDER(ID_Depth, EffectPhaser::OnDepthSlider)
EVT_SLIDER(ID_Feedback, EffectPhaser::OnFeedbackSlider)
EVT_TEXT(ID_Stages, EffectPhaser::OnStagesText)
EVT_TEXT(ID_DryWet, EffectPhaser::OnDryWetText)
EVT_TEXT(ID_Freq, EffectPhaser::OnFreqText)
EVT_TEXT(ID_Phase, EffectPhaser::OnPhaseText)
EVT_TEXT(ID_Depth, EffectPhaser::OnDepthText)
EVT_TEXT(ID_Feedback, EffectPhaser::OnFeedbackText)
END_EVENT_TABLE()
EffectPhaser::EffectPhaser()
{
freq = (float)0.4;
depth = 100;
startphase = float(0.0);
stages = 2;
drywet = 128;
fb = float(0.0);
mStages = DEF_Stages;
mDryWet = DEF_DryWet;
mFreq = DEF_Freq;
mPhase = DEF_Phase;
mDepth = DEF_Depth;
mFeedback = DEF_Feedback;
}
wxString EffectPhaser::GetEffectDescription() {
// Note: This is useful only after values have been set.
return wxString::Format(_("Applied effect: %s %d stages, %.0f%% wet, frequency = %.1f Hz, start phase = %.0f deg, depth = %d, feedback = %.0f%%"),
this->GetEffectName().c_str(),
stages,
float(drywet*100/255),
freq,
(startphase * 180 / M_PI),
depth,
fb);
}
bool EffectPhaser::PromptUser()
EffectPhaser::~EffectPhaser()
{
PhaserDialog dlog(this, mParent);
dlog.freq = freq;
dlog.startphase = startphase * 180 / M_PI;
dlog.fb = fb;
dlog.depth = depth;
dlog.stages = stages;
dlog.drywet = drywet;
dlog.TransferDataToWindow();
dlog.CentreOnParent();
dlog.ShowModal();
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
freq = dlog.freq;
startphase = dlog.startphase * M_PI / 180;
fb = dlog.fb;
depth = dlog.depth;
stages = dlog.stages;
drywet = dlog.drywet;
return true;
}
bool EffectPhaser::TransferParameters( Shuttle & shuttle )
// IdentInterface implementation
wxString EffectPhaser::GetSymbol()
{
shuttle.TransferInt(wxT("Stages"),stages,2);
shuttle.TransferInt(wxT("Wet"),drywet,128);
shuttle.TransferFloat(wxT("Freq"),freq,0.4f);
shuttle.TransferInt(wxT("Depth"),depth,100);
shuttle.TransferFloat(wxT("Feedback"),fb,0.0f);
return true;
return PHASER_PLUGIN_SYMBOL;
}
bool EffectPhaser::NewTrackSimpleMono()
wxString EffectPhaser::GetDescription()
{
for (int j = 0; j < stages; j++)
return wxTRANSLATE("Combines phase-shifted signals with the original signal");
}
// EffectIdentInterface implementation
EffectType EffectPhaser::GetType()
{
return EffectTypeProcess;
}
// EffectClientInterface implementation
int EffectPhaser::GetAudioInCount()
{
return 1;
}
int EffectPhaser::GetAudioOutCount()
{
return 1;
}
bool EffectPhaser::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames chanMap)
{
for (int j = 0; j < mStages; j++)
{
old[j] = 0;
}
skipcount = 0;
gain = 0;
fbout = 0;
lfoskip = freq * 2 * M_PI / mCurRate;
lfoskip = mFreq * 2 * M_PI / mSampleRate;
phase = startphase;
if (mCurChannel == Track::RightChannel)
phase += (float)M_PI;
return true;
}
bool EffectPhaser::ProcessSimpleMono(float *buffer, sampleCount len)
{
float m, tmp, in, out;
int i, j;
for (i = 0; i < len; i++) {
in = buffer[i];
m = in + fbout * fb / 100;
if (((skipcount++) % lfoskipsamples) == 0) {
//compute sine between 0 and 1
gain = (1 + cos(skipcount * lfoskip + phase)) / 2;
// change lfo shape
gain =
(exp(gain * phaserlfoshape) - 1) / (exp(phaserlfoshape)-1);
gain = 1 - gain / 255 * depth; // attenuate the lfo
}
// phasing routine
for (j = 0; j < stages; j++) {
tmp = old[j];
old[j] = gain * tmp + m;
m = tmp - gain * old[j];
}
fbout = m;
out = (m * drywet + in * (255 - drywet)) / 255;
buffer[i] = out;
phase = mPhase * M_PI / 180;
if (chanMap[0] == ChannelNameFrontRight)
{
phase += M_PI;
}
return true;
}
// WDR: class implementations
//----------------------------------------------------------------------------
// PhaserDialog
//----------------------------------------------------------------------------
#define FREQ_MIN 1
#define FREQ_MAX 40
#define PHASE_MIN 0
#define PHASE_MAX 359
#define DEPTH_MIN 0
#define DEPTH_MAX 255
#define STAGES_MIN 2
#define STAGES_MAX 24
#define DRYWET_MIN 0
#define DRYWET_MAX 255
#define FB_MIN -100
#define FB_MAX 100
// WDR: event table for PhaserDialog
BEGIN_EVENT_TABLE(PhaserDialog, EffectDialog)
EVT_TEXT(ID_PHASER_STAGESTEXT, PhaserDialog::OnStagesText)
EVT_TEXT(ID_PHASER_DRYWETTEXT, PhaserDialog::OnDryWetText)
EVT_TEXT(ID_PHASER_FREQTEXT, PhaserDialog::OnFreqText)
EVT_TEXT(ID_PHASER_PHASETEXT, PhaserDialog::OnPhaseText)
EVT_TEXT(ID_PHASER_DEPTHTEXT, PhaserDialog::OnDepthText)
EVT_TEXT(ID_PHASER_FEEDBACKTEXT, PhaserDialog::OnFeedbackText)
EVT_SLIDER(ID_PHASER_STAGESSLIDER, PhaserDialog::OnStagesSlider)
EVT_SLIDER(ID_PHASER_DRYWETSLIDER, PhaserDialog::OnDryWetSlider)
EVT_SLIDER(ID_PHASER_FREQSLIDER, PhaserDialog::OnFreqSlider)
EVT_SLIDER(ID_PHASER_PHASESLIDER, PhaserDialog::OnPhaseSlider)
EVT_SLIDER(ID_PHASER_DEPTHSLIDER, PhaserDialog::OnDepthSlider)
EVT_SLIDER(ID_PHASER_FEEDBACKSLIDER, PhaserDialog::OnFeedbackSlider)
EVT_BUTTON(ID_EFFECT_PREVIEW, PhaserDialog::OnPreview)
END_EVENT_TABLE()
PhaserDialog::PhaserDialog(EffectPhaser * effect, wxWindow * parent)
: EffectDialog(parent, _("Phaser"), PROCESS_EFFECT),
mEffect(effect)
sampleCount EffectPhaser::ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen)
{
Init();
float *ibuf = inBlock[0];
float *obuf = outBlock[0];
for (sampleCount i = 0; i < blockLen; i++)
{
double in = ibuf[i];
double m = in + fbout * mFeedback / 100;
if (((skipcount++) % lfoskipsamples) == 0)
{
//compute sine between 0 and 1
gain = (1.0 + cos(skipcount * lfoskip + phase)) / 2.0;
// change lfo shape
gain = (exp(gain * phaserlfoshape) - 1.0) / (exp(phaserlfoshape) - 1.0);
// attenuate the lfo
gain = 1.0 - gain / 255.0 * mDepth;
}
// phasing routine
for (int j = 0; j < mStages; j++)
{
double tmp = old[j];
old[j] = gain * tmp + m;
m = tmp - gain * old[j];
}
fbout = m;
obuf[i] = (float) ((m * mDryWet + in * (255 - mDryWet)) / 255);
}
return blockLen;
}
void PhaserDialog::PopulateOrExchange(ShuttleGui & S)
bool EffectPhaser::GetAutomationParameters(EffectAutomationParameters & parms)
{
wxTextValidator vld(wxFILTER_NUMERIC);
parms.Write(KEY_Stages, mStages);
parms.Write(KEY_DryWet, mDryWet);
parms.Write(KEY_Freq, mFreq);
parms.Write(KEY_Phase, mPhase);
parms.Write(KEY_Depth, mDepth);
parms.Write(KEY_Feedback, mFeedback);
return true;
}
bool EffectPhaser::SetAutomationParameters(EffectAutomationParameters & parms)
{
ReadAndVerifyInt(Stages);
ReadAndVerifyInt(DryWet);
ReadAndVerifyDouble(Freq);
ReadAndVerifyDouble(Phase);
ReadAndVerifyInt(Depth);
ReadAndVerifyInt(Feedback);
if (Stages & 1) // must be even, but don't complain about it
{
Stages &= ~1;
}
mFreq = Freq;
mFeedback = Feedback;
mStages = Stages;
mDryWet = DryWet;
mDepth = Depth;
mPhase = Phase;
return true;
}
// Effect implementation
void EffectPhaser::PopulateOrExchange(ShuttleGui & S)
{
S.SetBorder(5);
S.StartMultiColumn(3, wxEXPAND);
{
wxSlider *s;
wxTextCtrl * tempTC;
S.SetStretchyCol(1);
tempTC = S.Id(ID_PHASER_STAGESTEXT).AddTextBox(_("Stages:"), wxT(""), 12);
S.SetStretchyCol(2);
IntegerValidator<int> vldStages(&mStages);
vldStages.SetRange(MIN_Stages, MAX_Stages);
mStagesT = S.Id(ID_Stages).AddTextBox(_("Stages:"), wxT(""), 12);
mStagesT->SetValidator(vldStages);
S.SetStyle(wxSL_HORIZONTAL);
tempTC->SetValidator(vld);
s = S.Id(ID_PHASER_STAGESSLIDER).AddSlider(wxT(""), 2, STAGES_MAX, STAGES_MIN);
s->SetName(_("Stages"));
mStagesS = S.Id(ID_Stages).AddSlider(wxT(""), DEF_Stages * SCL_Stages, MAX_Stages * SCL_Stages, MIN_Stages * SCL_Stages);
mStagesS->SetName(_("Stages"));
mStagesS->SetLineSize(2);
#if defined(__WXGTK__)
s->SetMinSize(wxSize(100, -1));
mStagesS->SetMinSize(wxSize(100, -1));
#endif
tempTC = S.Id(ID_PHASER_DRYWETTEXT).AddTextBox(_("Dry/Wet:"), wxT(""), 12);
IntegerValidator<int> vldDryWet(&mDryWet);
vldDryWet.SetRange(MIN_DryWet, MAX_DryWet);
mDryWetT = S.Id(ID_DryWet).AddTextBox(_("Dry/Wet:"), wxT(""), 12);
mDryWetT->SetValidator(vldDryWet);
S.SetStyle(wxSL_HORIZONTAL);
tempTC->SetValidator(vld);
s = S.Id(ID_PHASER_DRYWETSLIDER).AddSlider(wxT(""), 0, DRYWET_MAX, DRYWET_MIN);
s->SetName(_("Dry Wet"));
mDryWetS = S.Id(ID_DryWet).AddSlider(wxT(""), DEF_DryWet * SCL_DryWet, MAX_DryWet * SCL_DryWet, MIN_DryWet * SCL_DryWet);
mDryWetS->SetName(_("Dry Wet"));
#if defined(__WXGTK__)
s->SetMinSize(wxSize(100, -1));
mDryWetS->SetMinSize(wxSize(100, -1));
#endif
tempTC = S.Id(ID_PHASER_FREQTEXT).AddTextBox(_("LFO Frequency (Hz):"), wxT(""), 12);
FloatingPointValidator<double> vldFreq(1, &mFreq);
vldFreq.SetRange(MIN_Freq, MAX_Freq);
mFreqT = S.Id(ID_Freq).AddTextBox(_("LFO Frequency (Hz):"), wxT(""), 12);
mFreqT->SetValidator(vldFreq);
S.SetStyle(wxSL_HORIZONTAL);
tempTC->SetValidator(vld);
s = S.Id(ID_PHASER_FREQSLIDER).AddSlider(wxT(""), 100, FREQ_MAX, FREQ_MIN);
s->SetName(_("LFO frequency in hertz"));
mFreqS = S.Id(ID_Freq).AddSlider(wxT(""), DEF_Freq * SCL_Freq, MAX_Freq * SCL_Freq, MIN_Freq * SCL_Freq);
mFreqS ->SetName(_("LFO frequency in hertz"));
#if defined(__WXGTK__)
s->SetMinSize(wxSize(100, -1));
mFreqS ->SetMinSize(wxSize(100, -1));
#endif
tempTC = S.Id(ID_PHASER_PHASETEXT).AddTextBox(_("LFO Start Phase (deg.):"), wxT(""), 12);
FloatingPointValidator<double> vldPhase(1, &mPhase);
vldPhase.SetRange(MIN_Phase, MAX_Phase);
mPhaseT = S.Id(ID_Phase).AddTextBox(_("LFO Start Phase (deg.):"), wxT(""), 12);
mPhaseT->SetValidator(vldPhase);
S.SetStyle(wxSL_HORIZONTAL);
tempTC->SetValidator(vld);
s = S.Id(ID_PHASER_PHASESLIDER).AddSlider(wxT(""), 0, PHASE_MAX, PHASE_MIN);
s->SetName(_("LFO start phase in degrees"));
s->SetLineSize(10);
mPhaseS = S.Id(ID_Phase).AddSlider(wxT(""), DEF_Phase * SCL_Phase, MAX_Phase * SCL_Phase, MIN_Phase * SCL_Phase);
mPhaseS->SetName(_("LFO start phase in degrees"));
mPhaseS->SetLineSize(10);
#if defined(__WXGTK__)
s->SetMinSize(wxSize(100, -1));
mPhaseS->SetMinSize(wxSize(100, -1));
#endif
tempTC = S.Id(ID_PHASER_DEPTHTEXT).AddTextBox(_("Depth:"), wxT(""), 12);
IntegerValidator<int> vldDepth(&mDepth);
vldDepth.SetRange(MIN_Depth, MAX_Depth);
mDepthT = S.Id(ID_Depth).AddTextBox(_("Depth:"), wxT(""), 12);
mDepthT->SetValidator(vldDepth);
S.SetStyle(wxSL_HORIZONTAL);
tempTC->SetValidator(vld);
s = S.Id(ID_PHASER_DEPTHSLIDER).AddSlider(wxT(""), 0, DEPTH_MAX, DEPTH_MIN);
s->SetName(_("Depth in percent"));
mDepthS = S.Id(ID_Depth).AddSlider(wxT(""), DEF_Depth * SCL_Depth, MAX_Depth * SCL_Depth, MIN_Depth * SCL_Depth);
mDepthS->SetName(_("Depth in percent"));
#if defined(__WXGTK__)
s->SetMinSize(wxSize(100, -1));
mDepthS->SetMinSize(wxSize(100, -1));
#endif
tempTC = S.Id(ID_PHASER_FEEDBACKTEXT).AddTextBox(_("Feedback (%):"), wxT(""), 12);
IntegerValidator<int> vldFeedback(&mFeedback);
vldFeedback.SetRange(MIN_Feedback, MAX_Feedback);
mFeedbackT = S.Id(ID_Feedback).AddTextBox(_("Feedback (%):"), wxT(""), 12);
mFeedbackT->SetValidator(vldFeedback);
S.SetStyle(wxSL_HORIZONTAL);
tempTC->SetValidator(vld);
s = S.Id(ID_PHASER_FEEDBACKSLIDER).AddSlider(wxT(""), 0, FB_MAX, FB_MIN);
s->SetName(_("Feedback in percent"));
s->SetLineSize(10);
mFeedbackS = S.Id(ID_Feedback).AddSlider(wxT(""), DEF_Feedback * SCL_Feedback, MAX_Feedback * SCL_Feedback, MIN_Feedback * SCL_Feedback);
mFeedbackS->SetName(_("Feedback in percent"));
mFeedbackS->SetLineSize(10);
#if defined(__WXGTK__)
s->SetMinSize(wxSize(100, -1));
mFeedbackS->SetMinSize(wxSize(100, -1));
#endif
}
S.EndMultiColumn();
}
bool PhaserDialog::TransferDataToWindow()
bool EffectPhaser::TransferDataToWindow()
{
wxSlider *slider;
slider = GetFreqSlider();
if (slider)
slider->SetValue((int)(freq * 10));
slider = GetPhaseSlider();
if (slider)
slider->SetValue((int)startphase);
slider = GetDepthSlider();
if (slider)
slider->SetValue((int)depth);
slider = GetFeedbackSlider();
if (slider)
slider->SetValue((int)fb);
slider = GetDryWetSlider();
if (slider)
slider->SetValue((int)drywet);
slider = GetStagesSlider();
if (slider)
slider->SetValue((int)stages);
wxTextCtrl *text;
text = GetStagesText();
if (text) {
wxString str;
str.Printf(wxT("%d"), stages);
text->SetValue(str);
if (!mUIParent->TransferDataToWindow())
{
return false;
}
text = GetDryWetText();
if (text) {
wxString str;
str.Printf(wxT("%d"), drywet);
text->SetValue(str);
}
text = GetFreqText();
if (text) {
wxString str;
str.Printf(wxT("%.1f"), freq);
text->SetValue(str);
}
text = GetPhaseText();
if (text) {
wxString str;
str.Printf(wxT("%d"), (int) startphase);
text->SetValue(str);
}
text = GetDepthText();
if (text) {
wxString str;
str.Printf(wxT("%d"), (int) depth);
text->SetValue(str);
}
text = GetFeedbackText();
if (text) {
wxString str;
str.Printf(wxT("%d"), (int) fb);
text->SetValue(str);
}
return TRUE;
return true;
}
bool PhaserDialog::TransferDataFromWindow()
bool EffectPhaser::TransferDataFromWindow()
{
wxTextCtrl *c;
long x;
c = GetFreqText();
if (c) {
double d;
c->GetValue().ToDouble(&d);
freq = TrapDouble(d * 10, FREQ_MIN, FREQ_MAX) / 10;
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
c = GetPhaseText();
if (c) {
c->GetValue().ToLong(&x);
startphase = TrapLong(x, PHASE_MIN, PHASE_MAX);
if (mStages & 1) // must be even
{
mStages &= ~1;
mUIParent->TransferDataToWindow();
}
c = GetDepthText();
if (c) {
c->GetValue().ToLong(&x);
depth = TrapLong(x, DEPTH_MIN, DEPTH_MAX);
return true;
}
// EffectPhaser implementation
void EffectPhaser::OnStagesSlider(wxCommandEvent & evt)
{
int val = evt.GetInt() & ~1; // must be even;
mPhaseS->SetValue(val);
mStages /= SCL_Stages;
mStagesT->GetValidator()->TransferToWindow();
EnableApply(mUIParent->Validate());
}
void EffectPhaser::OnDryWetSlider(wxCommandEvent & evt)
{
mDryWet = evt.GetInt() / SCL_DryWet;
mDryWetT->GetValidator()->TransferToWindow();
EnableApply(mUIParent->Validate());
}
void EffectPhaser::OnFreqSlider(wxCommandEvent & evt)
{
mFreq = (double) evt.GetInt() / SCL_Freq;
mFreqT->GetValidator()->TransferToWindow();
EnableApply(mUIParent->Validate());
}
void EffectPhaser::OnPhaseSlider(wxCommandEvent & evt)
{
int val = ((evt.GetInt() + 5) / 10) * 10; // round to nearest multiple of 10
val = val > MAX_Phase * SCL_Phase ? MAX_Phase * SCL_Phase : val;
mPhaseS->SetValue(val);
mPhase = (double) val / SCL_Phase;
mPhaseT->GetValidator()->TransferToWindow();
EnableApply(mUIParent->Validate());
}
void EffectPhaser::OnDepthSlider(wxCommandEvent & evt)
{
mDepth = evt.GetInt() / SCL_Depth;
mDepthT->GetValidator()->TransferToWindow();
EnableApply(mUIParent->Validate());
}
void EffectPhaser::OnFeedbackSlider(wxCommandEvent & evt)
{
int val = evt.GetInt();
val = ((val + (val > 0 ? 5 : -5)) / 10) * 10; // round to nearest multiple of 10
val = val > MAX_Feedback * SCL_Feedback ? MAX_Feedback * SCL_Feedback : val;
mFeedbackS->SetValue(val);
mFeedback = val / SCL_Feedback;
mFeedbackT->GetValidator()->TransferToWindow();
EnableApply(mUIParent->Validate());
}
void EffectPhaser::OnStagesText(wxCommandEvent & WXUNUSED(evt))
{
if (!EnableApply(mUIParent->TransferDataFromWindow()))
{
return;
}
c = GetFeedbackText();
if (c) {
c->GetValue().ToLong(&x);
fb = TrapLong(x, FB_MIN, FB_MAX);
mStagesS->SetValue((int) (mStages * SCL_Stages));
}
void EffectPhaser::OnDryWetText(wxCommandEvent & WXUNUSED(evt))
{
if (!EnableApply(mUIParent->TransferDataFromWindow()))
{
return;
}
c = GetStagesText();
if (c) {
c->GetValue().ToLong(&x);
stages = TrapLong(x, STAGES_MIN, STAGES_MAX);
if ((stages % 2) == 1) // must be even
stages = TrapLong(stages - 1, STAGES_MIN, STAGES_MAX);
mDryWetS->SetValue((int) (mDryWet * SCL_DryWet));
}
void EffectPhaser::OnFreqText(wxCommandEvent & WXUNUSED(evt))
{
if (!EnableApply(mUIParent->TransferDataFromWindow()))
{
return;
}
c = GetDryWetText();
if (c) {
c->GetValue().ToLong(&x);
drywet = TrapLong(x, DRYWET_MIN, DRYWET_MAX);
mFreqS->SetValue((int) (mFreq * SCL_Freq));
}
void EffectPhaser::OnPhaseText(wxCommandEvent & WXUNUSED(evt))
{
if (!EnableApply(mUIParent->TransferDataFromWindow()))
{
return;
}
return TRUE;
mPhaseS->SetValue((int) (mPhase * SCL_Phase));
}
// WDR: handler implementations for PhaserDialog
void PhaserDialog::OnStagesSlider(wxCommandEvent & WXUNUSED(event))
void EffectPhaser::OnDepthText(wxCommandEvent & WXUNUSED(evt))
{
wxString str;
long stage = GetStagesSlider()->GetValue();
str.Printf(wxT("%ld"), stage);
GetStagesText()->SetValue(str);
}
void PhaserDialog::OnDryWetSlider(wxCommandEvent & WXUNUSED(event))
{
wxString str;
long drywet = GetDryWetSlider()->GetValue();
str.Printf(wxT("%ld"), drywet);
GetDryWetText()->SetValue(str);
}
void PhaserDialog::OnFeedbackSlider(wxCommandEvent & WXUNUSED(event))
{
wxString str;
long fb = GetFeedbackSlider()->GetValue();
if (fb > 0) // round to nearest multiple of 10
fb = ((fb + 5) / 10) * 10;
else
fb = ((fb - 5) / 10) * 10;
str.Printf(wxT("%ld"), fb);
GetFeedbackText()->SetValue(str);
}
void PhaserDialog::OnDepthSlider(wxCommandEvent & WXUNUSED(event))
{
wxString str;
long depth = GetDepthSlider()->GetValue();
str.Printf(wxT("%ld"), depth);
GetDepthText()->SetValue(str);
}
void PhaserDialog::OnPhaseSlider(wxCommandEvent & WXUNUSED(event))
{
wxString str;
long phase = GetPhaseSlider()->GetValue();
phase = ((phase + 5) / 10) * 10; // round to nearest multiple of 10
str.Printf(wxT("%ld"), phase);
GetPhaseText()->SetValue(str);
}
void PhaserDialog::OnFreqSlider(wxCommandEvent & WXUNUSED(event))
{
wxString str;
long freq = GetFreqSlider()->GetValue();
str.Printf(wxT("%.1f"), freq / 10.0);
GetFreqText()->SetValue(str);
}
void PhaserDialog::OnStagesText(wxCommandEvent & WXUNUSED(event))
{
wxTextCtrl *c = GetStagesText();
if (c) {
long stage;
c->GetValue().ToLong(&stage);
stage = TrapLong(stage, STAGES_MIN, STAGES_MAX);
wxSlider *slider = GetStagesSlider();
if (slider)
slider->SetValue(stage);
if (!EnableApply(mUIParent->TransferDataFromWindow()))
{
return;
}
mDepthS->SetValue((int) (mDepth * SCL_Depth));
}
void PhaserDialog::OnDryWetText(wxCommandEvent & WXUNUSED(event))
void EffectPhaser::OnFeedbackText(wxCommandEvent & WXUNUSED(evt))
{
wxTextCtrl *c = GetDryWetText();
if (c) {
long drywet;
c->GetValue().ToLong(&drywet);
drywet = TrapLong(drywet, DRYWET_MIN, DRYWET_MAX);
wxSlider *slider = GetDryWetSlider();
if (slider)
slider->SetValue(drywet);
if (!EnableApply(mUIParent->TransferDataFromWindow()))
{
return;
}
}
void PhaserDialog::OnFeedbackText(wxCommandEvent & WXUNUSED(event))
{
wxTextCtrl *c = GetFeedbackText();
if (c) {
long fb;
c->GetValue().ToLong(&fb);
fb = TrapLong(fb, FB_MIN, FB_MAX);
wxSlider *slider = GetFeedbackSlider();
if (slider)
slider->SetValue(fb);
}
}
void PhaserDialog::OnDepthText(wxCommandEvent & WXUNUSED(event))
{
wxTextCtrl *c = GetDepthText();
if (c) {
long depth;
c->GetValue().ToLong(&depth);
depth = TrapLong(depth, DEPTH_MIN, DEPTH_MAX);
wxSlider *slider = GetDepthSlider();
if (slider)
slider->SetValue(depth);
}
}
void PhaserDialog::OnPhaseText(wxCommandEvent & WXUNUSED(event))
{
wxTextCtrl *c = GetPhaseText();
if (c) {
long phase;
c->GetValue().ToLong(&phase);
phase = TrapLong(phase, PHASE_MIN, PHASE_MAX);
wxSlider *slider = GetPhaseSlider();
if (slider)
slider->SetValue(phase);
}
}
void PhaserDialog::OnFreqText(wxCommandEvent & WXUNUSED(event))
{
wxTextCtrl *c = GetFreqText();
if (c) {
double freq;
c->GetValue().ToDouble(&freq);
freq = TrapDouble(freq * 10, FREQ_MIN, FREQ_MAX);
wxSlider *slider = GetFreqSlider();
if (slider)
slider->SetValue((int)freq);
}
}
void PhaserDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
{
TransferDataFromWindow();
// Save & restore parameters around Preview, because we didn't do OK.
float old_freq = mEffect->freq;
float old_startphase = mEffect->startphase;
float old_fb = mEffect->fb;
int old_depth = mEffect->depth;
int old_stages = mEffect->stages;
int old_drywet = mEffect->drywet;
mEffect->freq = freq;
mEffect->startphase = startphase * M_PI / 180;
mEffect->fb = fb;
mEffect->depth = depth;
mEffect->stages = stages;
mEffect->drywet = drywet;
mEffect->Preview();
mEffect->freq = old_freq;
mEffect->startphase = old_startphase;
mEffect->fb = old_fb;
mEffect->depth = old_depth;
mEffect->stages = old_stages;
mEffect->drywet = old_drywet;
mFeedbackS->SetValue((int) (mFeedback * SCL_Feedback));
}

View File

@ -16,188 +16,108 @@
#ifndef __AUDACITY_EFFECT_PHASER__
#define __AUDACITY_EFFECT_PHASER__
// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/window.h>
#endif
#include <wx/dialog.h>
#include <wx/intl.h>
#include <wx/event.h>
#include <wx/slider.h>
#include <wx/string.h>
#include <wx/textctrl.h>
class wxString;
class wxTextCtrl;
class wxSizer;
class wxSpinCtrl;
#include "../ShuttleGui.h"
#include "SimpleMono.h"
#include "Effect.h"
class WaveTrack;
#define NUM_STAGES 24
class EffectPhaser:public EffectSimpleMono {
#define PHASER_PLUGIN_SYMBOL wxTRANSLATE("Phaser")
public:
class EffectPhaser : public Effect
{
public:
EffectPhaser();
virtual ~EffectPhaser();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Phaser..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#PhaserPlugin"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Phaser"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Applying Phaser"));
}
virtual EffectType GetType();
// Useful only after PromptUser values have been set.
virtual wxString GetEffectDescription();
// EffectClientInterface implementation
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual int GetAudioInCount();
virtual int GetAudioOutCount();
virtual bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap = NULL);
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen);
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
protected:
virtual bool NewTrackSimpleMono();
virtual bool ProcessSimpleMono(float *buffer, sampleCount len);
/*
Phaser Parameters
freq - Phaser's LFO frequency
startphase - Phaser's LFO startphase (radians), needed for stereo Phasers
depth - Phaser depth (0 - no depth, 255 - max depth)
stages - Phaser stages (recomanded from 2 to 16-24, and EVEN NUMBER)
drywet - Dry/wet mix, (0 - dry, 128 - dry=wet, 255 - wet)
fb - Phaser FeedBack (0 - no feedback, 100 = 100% Feedback,
-100 = -100% FeedBack)
*/
private:
// parameters
float freq;
float startphase;
float fb;
int depth;
int stages;
int drywet;
// state variables
unsigned long skipcount;
float old[24]; // must be as large as MAX_STAGES
float gain;
float fbout;
float lfoskip;
float phase;
friend class PhaserDialog;
};
// Declare window functions
#define ID_PHASER_STAGESTEXT 12001
#define ID_PHASER_STAGESSLIDER 12002
#define ID_PHASER_DRYWETTEXT 12003
#define ID_PHASER_DRYWETSLIDER 12004
#define ID_PHASER_FREQTEXT 12005
#define ID_PHASER_FREQSLIDER 12006
#define ID_PHASER_PHASETEXT 12007
#define ID_PHASER_PHASESLIDER 12008
#define ID_PHASER_DEPTHTEXT 12009
#define ID_PHASER_DEPTHSLIDER 12010
#define ID_PHASER_FEEDBACKTEXT 12011
#define ID_PHASER_FEEDBACKSLIDER 12012
//----------------------------------------------------------------------------
// PhaserDialog
//----------------------------------------------------------------------------
class PhaserDialog:public EffectDialog {
public:
// constructors and destructors
PhaserDialog(EffectPhaser * effect, wxWindow * parent);
// Effect implementation
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
wxSlider *GetStagesSlider() {
return (wxSlider *) FindWindow(ID_PHASER_STAGESSLIDER);
}
wxSlider *GetDryWetSlider() {
return (wxSlider *) FindWindow(ID_PHASER_DRYWETSLIDER);
}
wxSlider *GetFeedbackSlider() {
return (wxSlider *) FindWindow(ID_PHASER_FEEDBACKSLIDER);
}
wxSlider *GetDepthSlider() {
return (wxSlider *) FindWindow(ID_PHASER_DEPTHSLIDER);
}
wxSlider *GetPhaseSlider() {
return (wxSlider *) FindWindow(ID_PHASER_PHASESLIDER);
}
wxSlider *GetFreqSlider() {
return (wxSlider *) FindWindow(ID_PHASER_FREQSLIDER);
}
wxTextCtrl *GetStagesText() {
return (wxTextCtrl *) FindWindow(ID_PHASER_STAGESTEXT);
}
wxTextCtrl *GetDryWetText() {
return (wxTextCtrl *) FindWindow(ID_PHASER_DRYWETTEXT);
}
wxTextCtrl *GetFeedbackText() {
return (wxTextCtrl *) FindWindow(ID_PHASER_FEEDBACKTEXT);
}
wxTextCtrl *GetDepthText() {
return (wxTextCtrl *) FindWindow(ID_PHASER_DEPTHTEXT);
}
wxTextCtrl *GetPhaseText() {
return (wxTextCtrl *) FindWindow(ID_PHASER_PHASETEXT);
}
wxTextCtrl *GetFreqText() {
return (wxTextCtrl *) FindWindow(ID_PHASER_FREQTEXT);
}
protected:
// EffectPhaser implementation
private:
// WDR: handler declarations for PhaserDialog
void OnStagesSlider(wxCommandEvent & event);
void OnDryWetSlider(wxCommandEvent & event);
void OnFeedbackSlider(wxCommandEvent & event);
void OnDepthSlider(wxCommandEvent & event);
void OnPhaseSlider(wxCommandEvent & event);
void OnFreqSlider(wxCommandEvent & event);
void OnStagesText(wxCommandEvent & event);
void OnDryWetText(wxCommandEvent & event);
void OnFeedbackText(wxCommandEvent & event);
void OnDepthText(wxCommandEvent & event);
void OnPhaseText(wxCommandEvent & event);
void OnFreqText(wxCommandEvent & event);
void OnPreview(wxCommandEvent &event);
void OnStagesSlider(wxCommandEvent & evt);
void OnDryWetSlider(wxCommandEvent & evt);
void OnFeedbackSlider(wxCommandEvent & evt);
void OnDepthSlider(wxCommandEvent & evt);
void OnPhaseSlider(wxCommandEvent & evt);
void OnFreqSlider(wxCommandEvent & evt);
void OnStagesText(wxCommandEvent & evt);
void OnDryWetText(wxCommandEvent & evt);
void OnFeedbackText(wxCommandEvent & evt);
void OnDepthText(wxCommandEvent & evt);
void OnPhaseText(wxCommandEvent & evt);
void OnFreqText(wxCommandEvent & evt);
/*
Phaser Parameters
private:
EffectPhaser * mEffect;
mFreq - Phaser's LFO frequency
mPhase - Phaser's LFO startphase (radians), needed for stereo Phasers
mDepth - Phaser depth (0 - no depth, 255 - max depth)
mStages - Phaser stages (recomanded from 2 to 16-24, and EVEN NUMBER)
mDryWet - Dry/wet mix, (0 - dry, 128 - dry=wet, 255 - wet)
mFeedback - Phaser FeedBack (0 - no feedback, 100 = 100% Feedback,
-100 = -100% FeedBack)
*/
public:
float freq;
float startphase;
float fb;
private:
// state variables
sampleCount skipcount;
double old[NUM_STAGES]; // must be as large as MAX_STAGES
double gain;
double fbout;
double lfoskip;
double phase;
int depth;
int stages;
int drywet;
// parameters
int mStages;
int mDryWet;
double mFreq;
double mPhase;
int mDepth;
int mFeedback;
private:
DECLARE_EVENT_TABLE()
wxTextCtrl *mStagesT;
wxTextCtrl *mDryWetT;
wxTextCtrl *mFreqT;
wxTextCtrl *mPhaseT;
wxTextCtrl *mDepthT;
wxTextCtrl *mFeedbackT;
wxSlider *mStagesS;
wxSlider *mDryWetS;
wxSlider *mFreqS;
wxSlider *mPhaseS;
wxSlider *mDepthS;
wxSlider *mFeedbackS;
DECLARE_EVENT_TABLE();
};
#endif

View File

@ -25,12 +25,13 @@ the audio, rather than actually finding the clicks.
#include <math.h>
#include <wx/msgdlg.h>
#include <wx/intl.h>
#include <wx/msgdlg.h>
#include "../InterpolateAudio.h"
#include "../WaveTrack.h"
#include "Repair.h"
#include "../WaveTrack.h"
#include "../InterpolateAudio.h"
EffectRepair::EffectRepair()
{
@ -40,18 +41,32 @@ EffectRepair::~EffectRepair()
{
}
bool EffectRepair::PromptUser()
// IdentInterface implementation
wxString EffectRepair::GetSymbol()
{
return true;
return REPAIR_PLUGIN_SYMBOL;
}
bool EffectRepair::TransferParameters( Shuttle & WXUNUSED(shuttle) )
wxString EffectRepair::GetDescription()
{
//TODO: pop-click values.
// shuttle.TransferInt("",,0);
return true;
return wxTRANSLATE("Sets the peak amplitude of a one or more tracks");
}
// EffectIdentInterface implementation
EffectType EffectRepair::GetType()
{
return EffectTypeProcess;
}
bool EffectRepair::IsInteractive()
{
return false;
}
// Effect implementation
bool EffectRepair::Process()
{
//v This may be too much copying for EffectRepair. To support Cancel, may be able to copy much less.

View File

@ -11,44 +11,37 @@
#ifndef __AUDACITY_EFFECT_REPAIR__
#define __AUDACITY_EFFECT_REPAIR__
#include <wx/intl.h>
#include <wx/string.h>
#include "SimpleMono.h"
#include "Effect.h"
#define REPAIR_PLUGIN_SYMBOL wxTRANSLATE("Repair")
class WaveTrack;
class EffectRepair: public Effect {
class EffectRepair : public Effect
{
public:
EffectRepair();
virtual ~EffectRepair();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Repair"));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://audacityteam.org/namespace#NoiseRemoval"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Repair"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Repairing damaged audio"));
}
virtual EffectType GetType();
virtual bool IsInteractive();
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
// Effect implementation
virtual bool Process();
private:
// EffectRepair implementaion
bool ProcessOne(int count, WaveTrack * track,
sampleCount start,
sampleCount len,

View File

@ -22,104 +22,83 @@
#include "../Audacity.h"
#include "Repeat.h"
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
#include "../LabelTrack.h"
#include "../widgets/NumericTextCtrl.h"
#include "../Project.h"
#include <wx/button.h>
#include <wx/defs.h>
#include <wx/intl.h>
#include <wx/msgdlg.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/validate.h>
#include <wx/valtext.h>
#include <math.h>
#include <wx/intl.h>
#include "../LabelTrack.h"
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
#include "../widgets/NumericTextCtrl.h"
#include "../widgets/valnum.h"
#include "Repeat.h"
BEGIN_EVENT_TABLE(EffectRepeat, wxEvtHandler)
EVT_TEXT(wxID_ANY, EffectRepeat::OnRepeatTextChange)
END_EVENT_TABLE()
EffectRepeat::EffectRepeat()
{
repeatCount = 10;
}
wxString EffectRepeat::GetEffectDescription() {
// Note: This is useful only after values have been set.
return wxString::Format(_("Repeated %d times"), repeatCount);
EffectRepeat::~EffectRepeat()
{
}
bool EffectRepeat::PromptUser()
// IdentInterface implementation
wxString EffectRepeat::GetSymbol()
{
//
// Figure out the maximum number of times the selection
// could be repeated without overflowing any track
//
int maxCount = -1;
TrackListOfKindIterator iter(Track::Wave, mTracks);
WaveTrack *track = (WaveTrack *) iter.First();
while (track) {
sampleCount trackLen =
(sampleCount)((track->GetEndTime() - track->GetStartTime()) *
track->GetRate());
sampleCount selectionLen = (sampleCount)((mT1 - mT0) * track->GetRate());
if (selectionLen == 0) {
wxMessageBox(_("Selection is too short to repeat."),
_("Repeat"), wxOK | wxCENTRE, mParent);
return false;
}
int availSamples = 2147483647 - trackLen;
int count = availSamples / selectionLen;
if (maxCount == -1 || count < maxCount)
maxCount = count;
return REPEAT_PLUGIN_SYMBOL;
}
track = (WaveTrack *) iter.Next();
}
wxString EffectRepeat::GetDescription()
{
return wxTRANSLATE("Repeats the selection the specified number of times");
}
if (maxCount <= 1) {
// TO DO: Not really true now that SampleCount is 64-bit int, but while bug 416
// is open, do we want to encourage repeating hugely long tracks?
wxMessageBox(_("Tracks are too long to repeat the selection."),
_("Repeat"), wxOK | wxCENTRE, mParent);
return false;
}
// EffectIdentInterface implementation
RepeatDialog dlog(this, mParent);
dlog.repeatCount = repeatCount;
dlog.selectionTimeSecs = mT1 - mT0;
dlog.maxCount = maxCount;
dlog.TransferDataToWindow();
EffectType EffectRepeat::GetType()
{
return EffectTypeProcess;
}
dlog.CentreOnParent();
// EffectClientInterface implementation
dlog.ShowModal();
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
repeatCount = dlog.repeatCount;
if (repeatCount > maxCount)
repeatCount = maxCount;
if (repeatCount < 1)
repeatCount = 1;
bool EffectRepeat::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.Write(wxT("Count"), repeatCount);
return true;
}
bool EffectRepeat::TransferParameters( Shuttle & shuttle )
bool EffectRepeat::SetAutomationParameters(EffectAutomationParameters & parms)
{
shuttle.TransferInt(wxT("Count"),repeatCount,1);
int count;
parms.Read(wxT("Count"), &count, 10);
if (count < 0 || count > 2147483647 / mProjectRate)
{
return false;
}
repeatCount = count;
return true;
}
// Effect implementation
bool EffectRepeat::Process()
{
// Set up mOutputTracks.
// This effect needs Track::All for sync-lock grouping.
this->CopyInputTracks(Track::All);
CopyInputTracks(Track::All);
int nTrack = 0;
bool bGoodResult = true;
@ -127,7 +106,8 @@ bool EffectRepeat::Process()
TrackListIterator iter(mOutputTracks);
for (Track *t = iter.First(); t && bGoodResult; t = iter.Next()) {
for (Track *t = iter.First(); t && bGoodResult; t = iter.Next())
{
if (t->GetKind() == Track::Label)
{
if (t->GetSelected() || t->IsSyncLockSelected())
@ -152,7 +132,9 @@ bool EffectRepeat::Process()
double tc = mT0 + tLen;
if (len <= 0)
{
continue;
}
Track *dest;
track->Copy(mT0, mT1, &dest);
@ -183,57 +165,29 @@ bool EffectRepeat::Process()
mT1 = maxDestLen;
}
this->ReplaceProcessedTracks(bGoodResult);
ReplaceProcessedTracks(bGoodResult);
return bGoodResult;
}
//----------------------------------------------------------------------------
// RepeatDialog
//----------------------------------------------------------------------------
const static wxChar *numbers[] =
void EffectRepeat::PopulateOrExchange(ShuttleGui & S)
{
wxT("0"), wxT("1"), wxT("2"), wxT("3"), wxT("4"),
wxT("5"), wxT("6"), wxT("7"), wxT("8"), wxT("9")
};
#define ID_REPEAT_TEXT 7000
BEGIN_EVENT_TABLE(RepeatDialog, EffectDialog)
EVT_TEXT(ID_REPEAT_TEXT, RepeatDialog::OnRepeatTextChange)
EVT_BUTTON(ID_EFFECT_PREVIEW, RepeatDialog::OnPreview)
END_EVENT_TABLE()
RepeatDialog::RepeatDialog(EffectRepeat *effect,
wxWindow * parent)
: EffectDialog(parent, _("Repeat"), PROCESS_EFFECT),
mEffect(effect)
{
Init();
}
void RepeatDialog::PopulateOrExchange(ShuttleGui & S)
{
wxTextValidator vld(wxFILTER_INCLUDE_CHAR_LIST);
vld.SetIncludes(wxArrayString(10, numbers));
S.StartHorizontalLay(wxCENTER, false);
{
mRepeatCount = S.Id(ID_REPEAT_TEXT).AddTextBox(_("Number of times to repeat:"),
wxT(""),
12);
mRepeatCount->SetValidator(vld);
IntegerValidator<int> vldRepeatCount(&repeatCount);
vldRepeatCount.SetRange(1, 2147483647 / mProjectRate);
mRepeatCount = S.AddTextBox(_("Number of times to repeat:"), wxT(""), 12);
mRepeatCount->SetValidator(vldRepeatCount);
}
S.EndHorizontalLay();
S.StartHorizontalLay(wxCENTER, true);
{
mTotalTime = S.AddVariableText(_("New selection length: hh:mm:ss"));
mTotalTime = S.AddVariableText(_("New selection length: dd:hh:mm:ss"));
}
S.EndHorizontalLay();
}
bool RepeatDialog::TransferDataToWindow()
bool EffectRepeat::TransferDataToWindow()
{
mRepeatCount->ChangeValue(wxString::Format(wxT("%d"), repeatCount));
@ -242,57 +196,38 @@ bool RepeatDialog::TransferDataToWindow()
return true;
}
bool RepeatDialog::TransferDataFromWindow()
bool EffectRepeat::TransferDataFromWindow()
{
if (!mUIParent->Validate())
{
return false;
}
long l;
mRepeatCount->GetValue().ToLong(&l);
repeatCount = l;
if (repeatCount < 1)
repeatCount = 1;
if (repeatCount > maxCount)
repeatCount = maxCount;
repeatCount = (int) l;
return true;
}
void RepeatDialog::DisplayNewTime()
void EffectRepeat::DisplayNewTime()
{
wxString str;
TransferDataFromWindow();
str = _("New selection length: ");
NumericTextCtrl tt(NumericTextCtrl::TIME, this,
wxID_ANY,
wxT(""),
selectionTimeSecs * (repeatCount + 1),
mEffect->mProjectRate,
wxPoint(10000, 10000), // create offscreen
wxDefaultSize,
true);
tt.SetFormatString(tt.GetBuiltinFormat(_("hh:mm:ss")));
str += tt.GetString();
NumericConverter nc(NumericConverter::TIME,
_("hh:mm:ss"),
(mT1 - mT0) * (repeatCount + 1),
mProjectRate);
wxString str = _("New selection length: ") + nc.GetString();
mTotalTime->SetLabel(str);
mTotalTime->SetName(str); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
}
void RepeatDialog::OnRepeatTextChange(wxCommandEvent & WXUNUSED(event))
void EffectRepeat::OnRepeatTextChange(wxCommandEvent & WXUNUSED(evt))
{
TransferDataFromWindow();
DisplayNewTime();
}
void RepeatDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
{
TransferDataFromWindow();
int oldRepeatCount = mEffect->repeatCount;
mEffect->repeatCount = repeatCount;
// LL: Preview doesn't work...Effect::Preview needs to allow new length
mEffect->Preview();
mEffect->repeatCount = oldRepeatCount;
}

View File

@ -11,82 +11,57 @@
#ifndef __AUDACITY_EFFECT_REPEAT__
#define __AUDACITY_EFFECT_REPEAT__
#include <wx/event.h>
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include "../ShuttleGui.h"
#include "Effect.h"
#include <wx/intl.h>
#include <wx/dialog.h>
#define REPEAT_PLUGIN_SYMBOL wxTRANSLATE("Repeat")
class wxString;
class wxStaticText;
class wxTextCtrl;
class WaveTrack;
class EffectRepeat:public Effect
class EffectRepeat : public Effect
{
friend class RepeatDialog;
public:
public:
EffectRepeat();
virtual ~EffectRepeat();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Repeat..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://audacityteam.org/namespace#TimelineChanger"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Repeat"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Performing Repeat"));
}
virtual EffectType GetType();
// Useful only after PromptUser values have been set.
virtual wxString GetEffectDescription();
// EffectClientInterface implementation
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
// Effect implementation
virtual bool Process();
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
private:
int repeatCount;
};
class RepeatDialog:public EffectDialog {
public:
// constructors and destructors
RepeatDialog(EffectRepeat *effect, wxWindow * parent);
// method declarations
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
private:
// handlers
void OnRepeatTextChange(wxCommandEvent & event);
void OnPreview( wxCommandEvent &event );
private:
// EffectRepeat implementation
void OnRepeatTextChange(wxCommandEvent & evt);
void DisplayNewTime();
private:
EffectRepeat *mEffect;
private:
int repeatCount;
wxTextCtrl *mRepeatCount;
wxStaticText *mTotalTime;
DECLARE_EVENT_TABLE()
public:
int repeatCount;
int maxCount;
double selectionTimeSecs;
DECLARE_EVENT_TABLE();
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -13,14 +13,16 @@
#define __AUDACITY_EFFECT_REVERB__
#include <wx/checkbox.h>
#include <wx/dialog.h>
#include <wx/intl.h>
#include <wx/event.h>
#include <wx/slider.h>
#include <wx/spinctrl.h>
#include <wx/string.h>
#include "../ShuttleGui.h"
#include "Effect.h"
class wxSpinCtrl;
class WaveTrack;
#define REVERB_PLUGIN_SYMBOL wxTRANSLATE("Reverb")
struct Reverb_priv_t;
@ -28,34 +30,12 @@ class EffectReverb : public Effect
{
public:
EffectReverb();
virtual ~EffectReverb() {};
virtual ~EffectReverb();
// Implemented from the base class 'Effect':
virtual wxString GetEffectName() {return wxTRANSLATE("Reverb...");}
virtual wxString GetEffectAction() {return _("Applying Reverb");}
virtual wxString GetEffectIdentifier() {return wxT("Reverb");}
virtual wxString GetEffectDescription(); // Useful only after PromptUser values have been set.
virtual bool TransferParameters(Shuttle & shuttle);
protected:
bool PromptUser();
bool Process();
// Processing:
void Create(double rate, bool isStereo);
bool ProcessOneBlock(sampleCount len, float * const * chans);
bool ProcessOneTrack(size_t n, WaveTrack * track, WaveTrack * track2, wxString const & msg);
void Delete();
double mCurT0, mCurT1;
Reverb_priv_t * mP;
// Settings:
wxString SettingsPath(int settingsNumber) const;
wxString SettingsName(int settingsNumber) const;
struct Params {
struct Params
{
double mRoomSize;
double mDelay;
double mPreDelay;
double mReverberance;
double mHfDamping;
double mToneLow;
@ -65,89 +45,83 @@ public:
double mStereoWidth;
bool mWetOnly;
};
void LoadSettings(int settingsNumber, Params & params);
void SaveSettings(int settingsNumber, Params const * params, wxString const * name = 0) const;
Params mParams;
// IdentInterface implementation
friend class ReverbDialogue;
};
virtual wxString GetSymbol();
virtual wxString GetDescription();
//----------------------------------------------------------------------------
// ReverbDialogue
//----------------------------------------------------------------------------
class ReverbDialogue : public EffectDialog
{
public:
ReverbDialogue(EffectReverb * effect, wxWindow * parent);
virtual ~ReverbDialogue() {};
// EffectIdentInterface implementation
private:
void SetTitle(wxString const & name = wxT(""));
void PopulateOrExchange(ShuttleGui &);
virtual EffectType GetType();
// EffectClientInterface implementation
virtual int GetAudioInCount();
virtual int GetAudioOutCount();
virtual bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap = NULL);
virtual bool ProcessFinalize();
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen);
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
virtual wxArrayString GetFactoryPresets();
virtual bool LoadFactoryPreset(int id);
// Effect implementation
bool Startup();
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
void LoadPreset(wxCommandEvent & WXUNUSED(event));
int ChooseSettings(wxString const & message);
void LoadSettings(wxCommandEvent & WXUNUSED(event));
void RenameSettings(wxCommandEvent & WXUNUSED(event));
void SaveSettings(wxCommandEvent & WXUNUSED(event));
void OnPreview(wxCommandEvent & event);
private:
// EffectReverb implementation
// event handlers and member vars
void OnRoomSizeWidget(wxCommandEvent & event);
void OnRoomSizeText(wxCommandEvent & event);
wxSlider * mRoomSizeWidget;
wxSpinCtrl * mRoomSizeText;
void SetTitle(const wxString & name = wxT(""));
void OnDelayWidget(wxCommandEvent & event);
void OnDelayText(wxCommandEvent & event);
wxSlider * mDelayWidget;
wxSpinCtrl * mDelayText;
#define SpinSliderHandlers(n) \
void On ## n ## Slider(wxCommandEvent & evt); \
void On ## n ## Text(wxCommandEvent & evt);
void OnReverberanceWidget(wxCommandEvent & event);
void OnReverberanceText(wxCommandEvent & event);
wxSlider * mReverberanceWidget;
wxSpinCtrl * mReverberanceText;
SpinSliderHandlers(RoomSize);
SpinSliderHandlers(PreDelay);
SpinSliderHandlers(Reverberance);
SpinSliderHandlers(HfDamping);
SpinSliderHandlers(ToneLow);
SpinSliderHandlers(ToneHigh);
SpinSliderHandlers(WetGain);
SpinSliderHandlers(DryGain);
SpinSliderHandlers(StereoWidth);
void OnHfDampingWidget(wxCommandEvent & event);
void OnHfDampingText(wxCommandEvent & event);
wxSlider * mHfDampingWidget;
wxSpinCtrl * mHfDampingText;
#undef SpinSliderHandlers
void OnToneLowWidget(wxCommandEvent & event);
void OnToneLowText(wxCommandEvent & event);
wxSlider * mToneLowWidget;
wxSpinCtrl * mToneLowText;
private:
int mNumChans;
Reverb_priv_t *mP;
void OnToneHighWidget(wxCommandEvent & event);
void OnToneHighText(wxCommandEvent & event);
wxSlider * mToneHighWidget;
wxSpinCtrl * mToneHighText;
Params mParams;
void OnWetGainWidget(wxCommandEvent & event);
void OnWetGainText(wxCommandEvent & event);
wxSlider * mWetGainWidget;
wxSpinCtrl * mWetGainText;
bool mProcessingEvent;
void OnDryGainWidget(wxCommandEvent & event);
void OnDryGainText(wxCommandEvent & event);
wxSlider * mDryGainWidget;
wxSpinCtrl * mDryGainText;
#define SpinSlider(n) \
wxSpinCtrl *m ## n ## T; \
wxSlider *m ## n ## S;
void OnStereoWidthWidget(wxCommandEvent & event);
void OnStereoWidthText(wxCommandEvent & event);
wxSlider * mStereoWidthWidget;
wxSpinCtrl * mStereoWidthText;
SpinSlider(RoomSize);
SpinSlider(PreDelay);
SpinSlider(Reverberance);
SpinSlider(HfDamping);
SpinSlider(ToneLow);
SpinSlider(ToneHigh);
SpinSlider(WetGain);
SpinSlider(DryGain);
SpinSlider(StereoWidth);
wxCheckBox * mWetOnlyWidget;
#undef SpinSlider
wxCheckBox *mWetOnlyC;
EffectReverb & mEffect;
EffectReverb::Params & mParams;
DECLARE_EVENT_TABLE()
DECLARE_EVENT_TABLE();
};
#endif

View File

@ -18,11 +18,12 @@
#include <math.h>
#include "Reverse.h"
#include "../Project.h"
#include "../WaveTrack.h"
#include <wx/intl.h>
#include "../LabelTrack.h"
#include "Reverse.h"
//
// EffectReverse
//
@ -31,6 +32,36 @@ EffectReverse::EffectReverse()
{
}
EffectReverse::~EffectReverse()
{
}
// IdentInterface implementation
wxString EffectReverse::GetSymbol()
{
return REVERSE_PLUGIN_SYMBOL;
}
wxString EffectReverse::GetDescription()
{
return wxTRANSLATE("Reverses the selected audio");
}
// EffectIdentInterface implementation
EffectType EffectReverse::GetType()
{
return EffectTypeProcess;
}
bool EffectReverse::IsInteractive()
{
return false;
}
// Effect implementation
bool EffectReverse::Process()
{
//Track::All is needed because Reverse should move the labels too
@ -234,4 +265,3 @@ bool EffectReverse::ProcessOneClip(int count, WaveTrack *track,
return rc;
}

View File

@ -13,44 +13,37 @@
#ifndef __AUDACITY_EFFECT_REVERSE__
#define __AUDACITY_EFFECT_REVERSE__
#include <wx/intl.h>
#include <wx/string.h>
#include "../WaveTrack.h"
#include "Effect.h"
#define __UNINITIALIZED__ (-1)
#define REVERSE_PLUGIN_SYMBOL wxTRANSLATE("Reverse")
class WaveTrack;
class EffectReverse:public Effect {
public:
class EffectReverse : public Effect
{
public:
EffectReverse();
virtual ~EffectReverse();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Reverse"));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://audacityteam.org/namespace#TimelineChanger"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Reverse"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Reversing"));
}
virtual EffectType GetType();
virtual bool IsInteractive();
virtual bool PromptUser() {
return true;
}
// Effect implementation
virtual bool Process();
private:
private:
// EffectReverse implementation
bool ProcessOneClip(int count, WaveTrack* track,
sampleCount start, sampleCount len, sampleCount originalStart, sampleCount originalEnd);
bool ProcessOneWave(int count, WaveTrack* track, sampleCount start, sampleCount len);

View File

@ -21,14 +21,15 @@
#include "sbsms.h"
using namespace _sbsms_;
class EffectSBSMS : public Effect {
public:
class EffectSBSMS : public Effect
{
public:
virtual bool Process();
void setParameters(double rateStart, double rateEnd, double pitchStart, double pitchEnd,
SlideType rateSlideType, SlideType pitchSlideType,
bool bLinkRatePitch, bool bRateReferenceInput, bool bPitchReferenceInput);
private:
private:
bool ProcessLabelTrack(Track *track);
double rateStart, rateEnd, pitchStart, pitchEnd;
bool bLinkRatePitch, bRateReferenceInput, bPitchReferenceInput;

File diff suppressed because it is too large Load Diff

View File

@ -13,247 +13,160 @@ Vaughan Johnson (Preview)
#ifndef __AUDACITY_EFFECT_SCIENFILTER__
#define __AUDACITY_EFFECT_SCIENFILTER__
#define MAX_FILTER_ORDER 10
#include <wx/button.h>
#include <wx/panel.h>
#include <wx/dialog.h>
#include <wx/dynarray.h>
#include <wx/intl.h>
#include <wx/stattext.h>
#include <wx/slider.h>
#include <wx/sizer.h>
#include <wx/string.h>
#include <wx/arrstr.h>
#include <wx/bitmap.h>
#include <wx/choice.h>
#include <wx/checkbox.h>
#include <wx/event.h>
#include <wx/panel.h>
#include <wx/slider.h>
#include <wx/stattext.h>
#include <wx/string.h>
#include <wx/window.h>
#if wxUSE_ACCESSIBILITY
#include <wx/access.h>
#endif
#include "Effect.h"
#include "../WaveTrack.h"
#include "../ShuttleGui.h"
#include "../widgets/Ruler.h"
#include "Biquad.h"
class ScienFilterDialog;
#include "Effect.h"
#define CLASSICFILTERS_PLUGIN_SYMBOL wxTRANSLATE("Classic Filters")
class EffectScienFilter: public Effect {
class EffectScienFilterPanel;
class EffectScienFilter : public Effect
{
public:
EffectScienFilter();
virtual ~EffectScienFilter();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Classic Filters..."));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#EQPlugin"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Classic Filters"));
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Performing Classic Filtering"));
}
virtual EffectType GetType();
// EffectClientInterface implementation
virtual int GetAudioInCount();
virtual int GetAudioOutCount();
virtual bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap = NULL);
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen);
virtual bool GetAutomationParameters(EffectAutomationParameters & parms);
virtual bool SetAutomationParameters(EffectAutomationParameters & parms);
// Effect implementation
virtual bool Startup();
virtual bool Init();
virtual bool PromptUser();
virtual bool DontPromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
bool CalcFilterCoeffs (void);
virtual bool Process();
// Lowest frequency to display in response graph
enum {loFreqI=20};
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
private:
bool ProcessOne(int count, WaveTrack * t,
sampleCount start, sampleCount len);
// EffectScienFilter implementation
void Filter(sampleCount len,
float *buffer);
void ReadPrefs();
virtual bool TransferGraphLimitsFromWindow();
virtual bool CalcFilter();
double ChebyPoly (int Order, double NormFreq);
float FilterMagnAtFreq(float Freq);
//int mM;
bool CalcFilterCoeffs (void);
void EnableDisableRippleCtl (int FilterType);
void OnSize( wxSizeEvent & evt );
void OnSlider( wxCommandEvent & evt );
void OnOrder( wxCommandEvent & evt );
void OnCutoff( wxCommandEvent & evt );
void OnRipple( wxCommandEvent & evt );
void OnStopbandRipple( wxCommandEvent & evt );
void OnFilterType( wxCommandEvent & evt );
void OnFilterSubtype( wxCommandEvent & evt );
void OnSliderDBMAX( wxCommandEvent & evt );
void OnSliderDBMIN( wxCommandEvent & evt );
private:
float mCutoff;
int mOrder;
float mRipple;
float mStopbandRipple;
int mFilterType; // Butterworth etc.
int mFilterSubtype; // lowpass, highpass
BiquadStruct* mpBiquad[5]; // MAX_ORDER/2
int mOrder;
int mOrderIndex;
BiquadStruct *mpBiquad;
double mdBMax;
double mdBMin;
bool mPrompting;
bool mEditingBatchParams;
public:
friend class ScienFilterDialog;
friend class ScienFilterPanel;
};
class ScienFilterPanel: public wxPanel
{
public:
ScienFilterPanel( double loFreq, double hiFreq,
ScienFilterDialog *parent,
wxWindowID id,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize);
~ScienFilterPanel();
#if 0
Needed only if user can draw in the graph
void OnMouseEvent(wxMouseEvent & event);
void OnCaptureLost(wxMouseCaptureLostEvent & event);
#endif
void OnPaint(wxPaintEvent & event);
void OnSize (wxSizeEvent & event);
// We don't need or want to accept focus.
bool AcceptsFocus() const { return false; }
float dBMax;
float dBMin;
private:
wxBitmap *mBitmap;
wxRect mEnvRect;
ScienFilterDialog *mParent;
int mWidth;
int mHeight;
double mLoFreq;
double mHiFreq;
DECLARE_EVENT_TABLE()
};
// WDR: class declarations
//----------------------------------------------------------------------------
// ScienFilterDialog
//----------------------------------------------------------------------------
class ScienFilterDialog: public wxDialog //, public XMLTagHandler
{
public:
// constructors and destructors
ScienFilterDialog(EffectScienFilter * effect,
double loFreq, double hiFreq,
wxWindow *parent, wxWindowID id,
const wxString &title,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_DIALOG_STYLE );
~ScienFilterDialog();
// WDR: method declarations for ScienFilterDialog
virtual bool Validate();
virtual bool TransferDataToWindow();
virtual bool TransferGraphLimitsFromWindow();
virtual bool CalcFilter(EffectScienFilter* effect);
float FilterMagnAtFreq (float Freq);
wxChoice* mFilterTypeCtl;
wxChoice* mFilterSubTypeCtl;
wxChoice* mFilterOrderCtl;
float Cutoff;
int Order;
float Ripple;
float StopbandRipple;
int FilterType; // Butterworth etc.
int FilterSubtype; // lowpass, highpass
float dBMin;
float dBMax;
int interp;
RulerPanel *dBRuler;
RulerPanel *freqRuler;
private:
void MakeScienFilterDialog();
void Finish(bool ok);
private:
// WDR: member variable declarations for ScienFilterDialog
enum
{
ID_FILTERPANEL = 10000,
ID_DBMAX,
ID_DBMIN,
ID_FILTER_TYPE,
ID_FILTER_SUBTYPE,
ID_FILTER_ORDER,
ID_RIPPLE,
ID_CUTOFF,
ID_STOPBAND_RIPPLE
};
private:
// WDR: handler declarations for ScienFilterDialog
void OnPaint( wxPaintEvent &event );
void OnSize( wxSizeEvent &event );
void OnErase( wxEraseEvent &event );
void OnSlider( wxCommandEvent &event );
void OnOrder( wxCommandEvent &event );
void OnCutoff( wxCommandEvent &event );
void OnRipple( wxCommandEvent &event );
void OnStopbandRipple( wxCommandEvent &event );
void OnFilterType( wxCommandEvent &event );
void OnFilterSubtype( wxCommandEvent &event );
void OnSliderDBMAX( wxCommandEvent &event );
void OnSliderDBMIN( wxCommandEvent &event );
void OnPreview(wxCommandEvent &event);
void OnOk( wxCommandEvent &event );
void OnCancel( wxCommandEvent &event );
void EnableDisableRippleCtl (int FilterType);
private:
EffectScienFilter * m_pEffect;
double mLoFreq;
double mNyquist;
ScienFilterPanel *mPanel;
wxSlider *dBMinSlider;
wxSlider *dBMaxSlider;
wxBoxSizer *szrV;
wxFlexGridSizer *szr3;
wxBoxSizer *szr4;
wxBoxSizer *szr2;
wxFlexGridSizer *szr1;
wxSize size;
wxTextCtrl* mRippleCtl;
wxTextCtrl* mStopbandRippleCtl;
wxTextCtrl* mCutoffCtl;
EffectScienFilterPanel *mPanel;
wxSlider *mdBMinSlider;
wxSlider *mdBMaxSlider;
// sizers for pass and stop-band attenuations
wxBoxSizer *szrPass;
wxBoxSizer *szrStop;
wxStaticText *mRippleCtlP;
wxTextCtrl *mRippleCtl;
wxStaticText *mRippleCtlU;
wxTextCtrl *mCutoffCtl;
wxStaticText *mStopbandRippleCtlP;
wxTextCtrl *mStopbandRippleCtl;
wxStaticText *mStopbandRippleCtlU;
wxChoice *mFilterTypeCtl;
wxChoice *mFilterSubTypeCtl;
wxChoice *mFilterOrderCtl;
RulerPanel *mdBRuler;
RulerPanel *mfreqRuler;
DECLARE_EVENT_TABLE();
friend class EffectScienFilterPanel;
};
class EffectScienFilterPanel : public wxPanel
{
public:
EffectScienFilterPanel(EffectScienFilter *effect, wxWindow *parent);
virtual ~EffectScienFilterPanel();
// We don't need or want to accept focus.
bool AcceptsFocus() const;
void SetFreqRange(double lo, double hi);
void SetDbRange(double min, double max);
private:
DECLARE_EVENT_TABLE()
void OnPaint(wxPaintEvent & evt);
void OnSize(wxSizeEvent & evt);
private:
EffectScienFilter *mEffect;
wxWindow *mParent;
double mLoFreq;
double mHiFreq;
double mDbMin;
double mDbMax;
wxBitmap *mBitmap;
wxRect mEnvRect;
int mWidth;
int mHeight;
friend class EffectScienFilter;
DECLARE_EVENT_TABLE();
};
#if wxUSE_ACCESSIBILITY

View File

@ -96,7 +96,7 @@ ScoreAlignDialog::ScoreAlignDialog(wxWindow *parent, ScoreAlignParams &params)
S.StartMultiColumn(3, wxEXPAND | wxALIGN_CENTER_VERTICAL);
S.SetStretchyCol(1);
mFramePeriodLabel = S.AddVariableText(_("Frame Period")+wxString(wxT(":")), true,
mFramePeriodLabel = S.AddVariableText(_("Frame Period:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mFramePeriodSlider = S.Id(ID_FRAMEPERIOD).AddSlider(wxT(""),
@ -106,7 +106,7 @@ ScoreAlignDialog::ScoreAlignDialog(wxWindow *parent, ScoreAlignParams &params)
mFramePeriodText = S.AddVariableText(SA_DFT_FRAME_PERIOD_TEXT, true,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
mWindowSizeLabel = S.AddVariableText(_("Window Size")+wxString(wxT(":")), true,
mWindowSizeLabel = S.AddVariableText(_("Window Size":), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mWindowSizeSlider = S.Id(ID_WINDOWSIZE).AddSlider(wxT(""),
@ -140,7 +140,7 @@ ScoreAlignDialog::ScoreAlignDialog(wxWindow *parent, ScoreAlignParams &params)
This is a new experimental effect, and until we have it documented in the user
manual we don't have a clear description of what this parameter does.
It is OK to leave it in English. */
mPresmoothLabel = S.AddVariableText(_("Presmooth Time")+wxString(wxT(":")), true,
mPresmoothLabel = S.AddVariableText(_("Presmooth Time:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mPresmoothSlider = S.Id(ID_PRESMOOTH).AddSlider(wxT(""),
@ -153,7 +153,7 @@ ScoreAlignDialog::ScoreAlignDialog(wxWindow *parent, ScoreAlignParams &params)
This is a new experimental effect, and until we have it documented in the user
manual we don't have a clear description of what this parameter does.
It is OK to leave it in English. */
mLineTimeLabel = S.AddVariableText(_("Line Time")+wxString(wxT(":")), true,
mLineTimeLabel = S.AddVariableText(_("Line Time:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mLineTimeSlider = S.Id(ID_LINETIME).AddSlider(wxT(""),
@ -166,7 +166,7 @@ ScoreAlignDialog::ScoreAlignDialog(wxWindow *parent, ScoreAlignParams &params)
This is a new experimental effect, and until we have it documented in the user
manual we don't have a clear description of what this parameter does.
It is OK to leave it in English. */
mSmoothTimeLabel = S.AddVariableText(_("Smooth Time")+wxString(wxT(":")), true,
mSmoothTimeLabel = S.AddVariableText(_("Smooth Time:"), true,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
S.SetStyle(wxSL_HORIZONTAL);
mSmoothTimeSlider = S.Id(ID_SMOOTHTIME).AddSlider(wxT(""),

View File

@ -9,54 +9,87 @@
*******************************************************************//**
\class EffectSilence
\brief An Effect for the "Generator" menu to add silence.
\brief An effect to add silence.
*//*******************************************************************/
#include "../Audacity.h"
#include <wx/defs.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/intl.h>
#include "Silence.h"
#include "../WaveTrack.h"
#include "../TimeDialog.h"
#include "../Prefs.h"
bool EffectSilence::PromptUser()
EffectSilence::EffectSilence()
{
wxString fmt;
mDuration = GetDuration();
}
if (mT1 > mT0) {
// there is a selection: let's fit in there...
mDuration = mT1 - mT0;
fmt = _("hh:mm:ss + samples");
} else {
// Retrieve last used values
gPrefs->Read(wxT("/Effects/SilenceGen/Duration"), &mDuration, 30L);
fmt = _("hh:mm:ss + milliseconds");
}
EffectSilence::~EffectSilence()
{
}
TimeDialog dlog(mParent, _("Silence Generator"), fmt, mProjectRate,
mDuration );
// IdentInterface implementation
if (dlog.ShowModal() == wxID_CANCEL)
return false;
wxString EffectSilence::GetSymbol()
{
return SILENCE_PLUGIN_SYMBOL;
}
mDuration = dlog.GetTimeValue();
/* Save last used values.
Save duration unless value was got from selection, so we save only
when user explicitly set up a value */
if (mT1 == mT0)
wxString EffectSilence::GetDescription()
{
return wxTRANSLATE("Creates audio of zero amplitude");
}
// EffectIdentInterface implementation
EffectType EffectSilence::GetType()
{
return EffectTypeGenerate;
}
// Effect implementation
void EffectSilence::PopulateOrExchange(ShuttleGui & S)
{
S.StartVerticalLay();
{
gPrefs->Write(wxT("/Effects/SilenceGen/Duration"), mDuration);
gPrefs->Flush();
S.StartHorizontalLay();
{
S.AddPrompt(_("Duration:"));
if (S.GetMode() == eIsCreating)
{
mDurationT = new
NumericTextCtrl(NumericConverter::TIME,
S.GetParent(),
wxID_ANY,
(mT1 > mT0) ? _("hh:mm:ss + samples") : _("hh:mm:ss + milliseconds"),
mDuration,
mProjectRate,
wxDefaultPosition,
wxDefaultSize,
true);
mDurationT->SetName(_("Duration"));
mDurationT->EnableMenu();
}
S.AddWindow(mDurationT, wxALIGN_CENTER | wxALL);
}
S.EndHorizontalLay();
}
S.EndVerticalLay();
return;
}
bool EffectSilence::TransferDataToWindow()
{
mDurationT->SetValue(mDuration);
return true;
}
bool EffectSilence::TransferDataFromWindow()
{
mDuration = mDurationT->GetValue();
return true;
}
@ -65,7 +98,7 @@ bool EffectSilence::GenerateTrack(WaveTrack *tmp,
const WaveTrack & WXUNUSED(track),
int WXUNUSED(ntrack))
{
const bool bResult = tmp->InsertSilence(0.0, mDuration);
bool bResult = tmp->InsertSilence(0.0, mDuration);
wxASSERT(bResult);
return bResult;
}

View File

@ -6,60 +6,50 @@
Dominic Mazzoni
An effect for the "Generator" menu to add silence.
An effect to add silence.
**********************************************************************/
#ifndef __AUDACITY_EFFECT_SILENCE__
#define __AUDACITY_EFFECT_SILENCE__
#include <wx/defs.h>
#include <wx/dialog.h>
#include <wx/intl.h>
#include <wx/string.h>
#include "../WaveTrack.h"
#include "../widgets/NumericTextCtrl.h"
#include "Generator.h"
class wxSizer;
class wxTextCtrl;
#define SILENCE_PLUGIN_SYMBOL wxTRANSLATE("Silence")
class EffectSilence : public Generator {
class EffectSilence : public Generator
{
public:
EffectSilence();
virtual ~EffectSilence();
public:
EffectSilence() {
SetEffectFlags(BUILTIN_EFFECT | INSERT_EFFECT);
}
// IdentInterface implementation
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Silence..."));
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#GeneratorPlugin"));
return result;
}
// EffectIdentInterface implementation
virtual wxString GetEffectIdentifier() {
return wxString(wxT("Silence"));
}
virtual EffectType GetType();
virtual wxString GetEffectAction() {
return wxString(_("Generating Silence"));
}
// Effect implementation
// Return true if the effect supports processing via batch chains.
virtual bool SupportsChains() {
return false;
}
virtual void PopulateOrExchange(ShuttleGui & S);
virtual bool TransferDataToWindow();
virtual bool TransferDataFromWindow();
// Useful only after PromptUser values have been set.
virtual wxString GetEffectDescription() {
return wxString::Format(_("Applied effect: Generate Silence, %.6lf seconds"), mDuration);
}
protected:
// Generator implementation
virtual bool PromptUser();
protected:
bool GenerateTrack(WaveTrack *tmp, const WaveTrack &track, int ntrack);
private:
NumericTextCtrl *mDurationT;
};
#endif

View File

@ -21,15 +21,12 @@
class WaveTrack;
class EffectSimpleMono:public Effect {
public:
class EffectSimpleMono : public Effect
{
public:
virtual bool Process();
private:
bool ProcessOne(WaveTrack * t, sampleCount start, sampleCount end);
protected:
protected:
// Override this method if you need to do things
// before every track (including the first one)
@ -38,6 +35,7 @@ class EffectSimpleMono:public Effect {
// Override this method to actually process audio
virtual bool ProcessSimpleMono(float *buffer, sampleCount len) = 0;
protected:
// Other useful information
int mCurTrackNum;
double mCurRate;
@ -45,6 +43,8 @@ class EffectSimpleMono:public Effect {
double mCurT1;
int mCurChannel;
private:
bool ProcessOne(WaveTrack * t, sampleCount start, sampleCount end);
};
#endif

View File

@ -34,21 +34,27 @@ using namespace soundtouch;
class WaveTrack;
class EffectSoundTouch:public Effect {
class EffectSoundTouch : public Effect
{
public:
// Effect implementation
public:
virtual bool Process();
// EffectSoundTouch implementation
#ifdef USE_MIDI
double mSemitones; // pitch change for NoteTracks
EffectSoundTouch() { mSemitones = 0; }
#endif
protected:
protected:
SoundTouch *mSoundTouch;
double mCurT0;
double mCurT1;
private:
private:
bool ProcessLabelTrack(Track *track);
#ifdef USE_MIDI
bool ProcessNoteTrack(Track *track);

View File

@ -13,160 +13,75 @@
*//*******************************************************************/
#include "../Audacity.h"
// For compilers that support precompilation, includes "wx.h".
#include <wx/wxprec.h>
#include <wx/intl.h>
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
// Include your minimal set of headers here, or wx.h
#include <wx/wx.h>
#endif
#include <math.h>
#include "StereoToMono.h"
#include "../Project.h"
EffectStereoToMono::EffectStereoToMono()
{
Init();
}
bool EffectStereoToMono::Init()
{
return true;
}
void EffectStereoToMono::End()
EffectStereoToMono::~EffectStereoToMono()
{
}
//TODO: There are a lot of places where a track is being checked
// to see if it is stereo. Consolidate these
bool EffectStereoToMono::CheckWhetherSkipEffect()
{
TrackListOfKindIterator iter(Track::Wave, mTracks);
WaveTrack *t = (WaveTrack*)iter.First();
while (t) {
if (t->GetLinked()) {
return false;
}
t = (WaveTrack *)iter.Next();
}
// IdentInterface implementation
return true;
wxString EffectStereoToMono::GetSymbol()
{
return STEREOTOMONO_PLUGIN_SYMBOL;
}
bool EffectStereoToMono::ProcessOne(int count)
wxString EffectStereoToMono::GetDescription()
{
float curLeftFrame;
float curRightFrame;
float curMonoFrame;
sampleCount idealBlockLen = mLeftTrack->GetMaxBlockSize() * 2;
sampleCount index = mStart;
float *leftBuffer = new float[idealBlockLen];
float *rightBuffer = new float[idealBlockLen];
bool bResult = true;
while (index < mEnd) {
bResult &= mLeftTrack->Get((samplePtr)leftBuffer, floatSample, index, idealBlockLen);
bResult &= mRightTrack->Get((samplePtr)rightBuffer, floatSample, index, idealBlockLen);
sampleCount limit = idealBlockLen;
if ((index + idealBlockLen) > mEnd) {
limit = mEnd - index;
}
for (sampleCount i = 0; i < limit; ++i) {
index++;
curLeftFrame = leftBuffer[i];
curRightFrame = rightBuffer[i];
curMonoFrame = (curLeftFrame + curRightFrame) / 2.0;
leftBuffer[i] = curMonoFrame;
}
bResult &= mOutTrack->Append((samplePtr)leftBuffer, floatSample, limit);
if (TrackProgress(count, 2.*((double)index / (double)(mEnd - mStart))))
return false;
}
double minStart = wxMin(mLeftTrack->GetStartTime(), mRightTrack->GetStartTime());
bResult &= mLeftTrack->Clear(mLeftTrack->GetStartTime(), mLeftTrack->GetEndTime());
bResult &= mOutTrack->Flush();
bResult &= mLeftTrack->Paste(minStart, mOutTrack);
mLeftTrack->SetLinked(false);
mRightTrack->SetLinked(false);
mLeftTrack->SetChannel(Track::MonoChannel);
mOutputTracks->Remove(mRightTrack);
delete mRightTrack;
delete [] leftBuffer;
delete [] rightBuffer;
return bResult;
return wxTRANSLATE("Converts stereo tracks to mono");
}
bool EffectStereoToMono::Process()
// EffectIdentInterface implementation
EffectType EffectStereoToMono::GetType()
{
// Do not use mWaveTracks here. We will possibly delete tracks,
// so we must use the "real" tracklist.
this->CopyInputTracks(); // Set up mOutputTracks.
bool bGoodResult = true;
// Really EffectTypeProcess, but this prevents it from showing in the Effect Menu
return EffectTypeNone;
}
SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks);
mLeftTrack = (WaveTrack *)iter.First();
bool refreshIter = false;
bool EffectStereoToMono::IsInteractive()
{
return false;
}
if(mLeftTrack)
// EffectClientInterface implementation
int EffectStereoToMono::GetAudioInCount()
{
return 2;
}
int EffectStereoToMono::GetAudioOutCount()
{
return 1;
}
sampleCount EffectStereoToMono::ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen)
{
float *left = inBlock[0];
float *right = inBlock[1];
float *mono = outBlock[0];
for (sampleCount i = 0; i < blockLen; i++)
{
// create a new WaveTrack to hold all of the output
AudacityProject *p = GetActiveProject();
mOutTrack = p->GetTrackFactory()->NewWaveTrack(floatSample, mLeftTrack->GetRate());
mono[i] = (left[i] + right[i]) / 2.0;
}
int count = 0;
while (mLeftTrack) {
if (mLeftTrack->GetKind() == Track::Wave &&
mLeftTrack->GetSelected() &&
mLeftTrack->GetLinked()) {
mRightTrack = (WaveTrack *)iter.Next();
if ((mLeftTrack->GetRate() == mRightTrack->GetRate())) {
sampleCount leftTrackStart = mLeftTrack->TimeToLongSamples(mLeftTrack->GetStartTime());
sampleCount rightTrackStart = mRightTrack->TimeToLongSamples(mRightTrack->GetStartTime());
mStart = wxMin(leftTrackStart, rightTrackStart);
sampleCount leftTrackEnd = mLeftTrack->TimeToLongSamples(mLeftTrack->GetEndTime());
sampleCount rightTrackEnd = mRightTrack->TimeToLongSamples(mRightTrack->GetEndTime());
mEnd = wxMax(leftTrackEnd, rightTrackEnd);
bGoodResult = ProcessOne(count);
if (!bGoodResult)
break;
mOutTrack->Clear(mOutTrack->GetStartTime(), mOutTrack->GetEndTime());
// The right channel has been deleted, so we must restart from the beginning
refreshIter = true;
}
}
if (refreshIter) {
mLeftTrack = (WaveTrack *)iter.First();
refreshIter = false;
}
else {
mLeftTrack = (WaveTrack *)iter.Next();
}
count++;
}
if(mOutTrack)
delete mOutTrack;
this->ReplaceProcessedTracks(bGoodResult);
return bGoodResult;
return blockLen;
}
// Effect implementatino
bool EffectStereoToMono::IsHidden()
{
return true;
}

View File

@ -11,52 +11,37 @@
#ifndef __AUDACITY_EFFECT_STEREO_TO_MONO__
#define __AUDACITY_EFFECT_STEREO_TO_MONO__
#include <wx/string.h>
#include "Effect.h"
class EffectStereoToMono: public Effect {
#define STEREOTOMONO_PLUGIN_SYMBOL wxTRANSLATE("Stereo To Mono")
class EffectStereoToMono : public Effect
{
public:
EffectStereoToMono();
virtual ~EffectStereoToMono();
virtual wxString GetEffectName() {
return wxString(wxTRANSLATE("Stereo to Mono"));
}
// IdentInterface implementation
virtual std::set<wxString> GetEffectCategories() {
std::set<wxString> result;
result.insert(wxT("http://lv2plug.in/ns/lv2core#MixerPlugin"));
return result;
}
virtual wxString GetSymbol();
virtual wxString GetDescription();
// Used internally, users will not see this. Do not translate.
virtual wxString GetEffectIdentifier() {
return wxT("Stereo To Mono");
}
// EffectIdentInterface implementation
virtual wxString GetEffectAction() {
return wxString(_("Applying Stereo to Mono"));
}
virtual bool Init();
virtual void End();
virtual bool CheckWhetherSkipEffect();
virtual EffectType GetType();
virtual bool IsInteractive();
virtual bool PromptUser() {
return true;
}
// EffectClientInterface implementation
protected:
virtual bool Process();
virtual int GetAudioInCount();
virtual int GetAudioOutCount();
virtual sampleCount ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen);
private:
bool ProcessOne(int);
sampleCount mStart;
sampleCount mEnd;
WaveTrack *mLeftTrack;
WaveTrack *mRightTrack;
WaveTrack *mOutTrack;
// Effect implementation
bool IsHidden();
};
#endif

Some files were not shown because too many files have changed in this diff Show More