audacia/src/effects/Noise.cpp

247 lines
7.0 KiB
C++
Raw Normal View History

/**********************************************************************
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"
#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
//
// EffectNoise
//
bool EffectNoise::Init()
{
gPrefs->Read(wxT("/Effects/Noise/Duration"), &mDuration, 1L);
return true;
}
bool EffectNoise::PromptUser()
{
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
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
// 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) )
{
return true;
}
bool EffectNoise::MakeNoise(float *buffer, sampleCount len, float fs, float amplitude)
{
float white;
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
// 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 *
(buf0 + buf1 + buf2 + buf3 + buf4 + buf5 + buf6 + white * 0.5362);
2014-06-03 20:30:19 +00:00
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;
for(i=0; i<len; 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;
}
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)
gPrefs->Write(wxT("/Effects/Noise/Duration"), mDuration);
gPrefs->Write(wxT("/Effects/Noise/Type"), noiseType);
gPrefs->Write(wxT("/Effects/Noise/Amplitude"), noiseAmplitude);
gPrefs->Flush();
}
//----------------------------------------------------------------------------
// 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),
mEffect(effect)
{
mNoiseDurationT = NULL;
/* // already initialized in EffectNoise::PromptUser
nDuration = mDuration;
nAmplitude = noiseAmplitude;
nType = noiseType;
*/
}
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.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
mNoiseDurationT->SetValue(nDuration);
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
nDuration = mNoiseDurationT->GetValue();
return true;
}
void NoiseDialog::OnTimeCtrlUpdate(wxCommandEvent & WXUNUSED(event)) {
Fit();
}