2010-01-23 19:44:49 +00:00
|
|
|
/**********************************************************************
|
|
|
|
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
|
|
|
|
Noise.cpp
|
|
|
|
|
|
|
|
Dominic Mazzoni
|
|
|
|
|
|
|
|
*******************************************************************//**
|
|
|
|
|
|
|
|
\class EffectNoise
|
|
|
|
\brief An Effect for the "Generator" menu to add white noise.
|
|
|
|
|
|
|
|
*//*******************************************************************/
|
|
|
|
|
|
|
|
#include "../Audacity.h"
|
|
|
|
#include "../Project.h"
|
|
|
|
#include "../Prefs.h"
|
|
|
|
#include "../ShuttleGui.h"
|
|
|
|
#include "../WaveTrack.h"
|
2014-11-08 15:18:43 +00:00
|
|
|
#include "../widgets/NumericTextCtrl.h"
|
2014-11-11 15:47:48 +00:00
|
|
|
#include "Noise.h"
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2013-02-14 01:10:59 +00:00
|
|
|
#include <math.h>
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
#ifndef M_PI
|
|
|
|
#define M_PI 3.14159265358979323846 /* pi */
|
|
|
|
#endif
|
|
|
|
#define AMP_MIN 0
|
|
|
|
#define AMP_MAX 1
|
|
|
|
|
|
|
|
//
|
|
|
|
// EffectNoise
|
|
|
|
//
|
|
|
|
|
|
|
|
bool EffectNoise::Init()
|
|
|
|
{
|
2011-06-14 23:48:58 +00:00
|
|
|
gPrefs->Read(wxT("/Effects/Noise/Duration"), &mDuration, 1L);
|
2010-01-23 19:44:49 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EffectNoise::PromptUser()
|
|
|
|
{
|
|
|
|
wxArrayString noiseTypeList;
|
|
|
|
|
|
|
|
noiseTypeList.Add(_("White"));
|
|
|
|
noiseTypeList.Add(_("Pink"));
|
2013-02-14 01:10:59 +00:00
|
|
|
noiseTypeList.Add(_("Brownian"));
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
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
|
2014-06-03 20:30:19 +00:00
|
|
|
// If there is a selection, use that duration, otherwise use
|
|
|
|
// value from saved config: this is useful is user wants to
|
2010-01-23 19:44:49 +00:00
|
|
|
// replace selection with noise
|
|
|
|
//
|
|
|
|
if (mT1 > mT0) {
|
|
|
|
mDuration = mT1 - mT0;
|
|
|
|
dlog.nIsSelection = true;
|
|
|
|
} else {
|
2012-12-17 22:29:01 +00:00
|
|
|
gPrefs->Read(wxT("/Effects/Noise/Duration"), &mDuration, 30L);
|
2010-01-23 19:44:49 +00:00
|
|
|
dlog.nIsSelection = false;
|
|
|
|
}
|
|
|
|
|
2011-06-14 23:48:58 +00:00
|
|
|
gPrefs->Read(wxT("/Effects/Noise/Type"), &noiseType, 0L);
|
|
|
|
gPrefs->Read(wxT("/Effects/Noise/Amplitude"), &noiseAmplitude, 0.8f);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
bool EffectNoise::TransferParameters( Shuttle & WXUNUSED(shuttle) )
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EffectNoise::MakeNoise(float *buffer, sampleCount len, float fs, float amplitude)
|
|
|
|
{
|
2013-02-14 01:10:59 +00:00
|
|
|
float white;
|
2010-01-23 19:44:49 +00:00
|
|
|
sampleCount i;
|
|
|
|
float div = ((float)RAND_MAX) / 2.0f;
|
|
|
|
|
|
|
|
switch (noiseType) {
|
|
|
|
default:
|
|
|
|
case 0: // white
|
|
|
|
for(i=0; i<len; i++)
|
|
|
|
buffer[i] = amplitude * ((rand() / div) - 1.0f);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: // pink
|
2013-02-14 01:10:59 +00:00
|
|
|
// 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;
|
2014-06-03 20:30:19 +00:00
|
|
|
buffer[i] = amplitude *
|
2013-02-14 01:10:59 +00:00
|
|
|
(buf0 + buf1 + buf2 + buf3 + buf4 + buf5 + buf6 + white * 0.5362);
|
2014-06-03 20:30:19 +00:00
|
|
|
buf6 = white * 0.115926;
|
2013-02-14 01:10:59 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2013-02-14 01:10:59 +00:00
|
|
|
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;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
for(i=0; i<len; i++){
|
|
|
|
white=(rand() / div) - 1.0f;
|
2013-02-14 01:10:59 +00:00
|
|
|
z = leakage * y + white * scaling;
|
|
|
|
y = (fabs(z) > 1.0) ? (leakage * y - white * scaling) : z;
|
2010-01-23 19:44:49 +00:00
|
|
|
buffer[i] = amplitude * y;
|
2013-02-14 01:10:59 +00:00
|
|
|
}
|
2010-01-23 19:44:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EffectNoise::GenerateBlock(float *data,
|
|
|
|
const WaveTrack &track,
|
|
|
|
sampleCount block)
|
|
|
|
{
|
|
|
|
MakeNoise(data, block, track.GetRate(), noiseAmplitude);
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2011-06-14 23:48:58 +00:00
|
|
|
gPrefs->Write(wxT("/Effects/Noise/Duration"), mDuration);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2011-06-14 23:48:58 +00:00
|
|
|
gPrefs->Write(wxT("/Effects/Noise/Type"), noiseType);
|
|
|
|
gPrefs->Write(wxT("/Effects/Noise/Amplitude"), noiseAmplitude);
|
2012-08-02 06:03:19 +00:00
|
|
|
gPrefs->Flush();
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// 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)
|
2014-06-03 20:30:19 +00:00
|
|
|
: EffectDialog(parent, title, INSERT_EFFECT),
|
2010-01-23 19:44:49 +00:00
|
|
|
mEffect(effect)
|
|
|
|
{
|
|
|
|
mNoiseDurationT = NULL;
|
|
|
|
/* // already initialized in EffectNoise::PromptUser
|
|
|
|
nDuration = mDuration;
|
|
|
|
nAmplitude = noiseAmplitude;
|
|
|
|
nType = noiseType;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
void NoiseDialog::PopulateOrExchange( ShuttleGui & S )
|
|
|
|
{
|
|
|
|
S.StartMultiColumn(2, wxCENTER);
|
|
|
|
{
|
2013-02-14 01:10:59 +00:00
|
|
|
S.TieChoice(_("Noise type:"), nType, nTypeList);
|
2011-06-16 23:29:56 +00:00
|
|
|
S.TieNumericTextBox(_("Amplitude (0-1)") + wxString(wxT(":")), nAmplitude, 10);
|
2011-03-25 05:53:02 +00:00
|
|
|
S.AddPrompt(_("Duration") + wxString(wxT(":")));
|
2010-01-23 19:44:49 +00:00
|
|
|
if (mNoiseDurationT == NULL)
|
|
|
|
{
|
|
|
|
mNoiseDurationT = new
|
2014-11-08 15:18:43 +00:00
|
|
|
NumericTextCtrl(NumericConverter::TIME, this,
|
2010-01-23 19:44:49 +00:00
|
|
|
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"));
|
2012-08-01 00:42:12 +00:00
|
|
|
mNoiseDurationT->SetFormatString(mNoiseDurationT->GetBuiltinFormat(nIsSelection==true?(_("hh:mm:ss + samples")):(_("hh:mm:ss + milliseconds"))));
|
2010-01-23 19:44:49 +00:00
|
|
|
mNoiseDurationT->EnableMenu();
|
|
|
|
}
|
|
|
|
S.AddWindow(mNoiseDurationT, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL);
|
|
|
|
}
|
|
|
|
S.EndMultiColumn();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NoiseDialog::TransferDataToWindow()
|
|
|
|
{
|
|
|
|
EffectDialog::TransferDataToWindow();
|
|
|
|
|
|
|
|
// Must handle this ourselves since ShuttleGui doesn't know about it
|
2014-11-08 15:18:43 +00:00
|
|
|
mNoiseDurationT->SetValue(nDuration);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NoiseDialog::TransferDataFromWindow()
|
|
|
|
{
|
|
|
|
EffectDialog::TransferDataFromWindow();
|
|
|
|
|
|
|
|
nAmplitude = TrapDouble(nAmplitude, AMP_MIN, AMP_MAX);
|
|
|
|
|
|
|
|
// Must handle this ourselves since ShuttleGui doesn't know about it
|
2014-11-08 15:18:43 +00:00
|
|
|
nDuration = mNoiseDurationT->GetValue();
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void NoiseDialog::OnTimeCtrlUpdate(wxCommandEvent & WXUNUSED(event)) {
|
2010-01-23 19:44:49 +00:00
|
|
|
Fit();
|
|
|
|
}
|