1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-01 08:29:27 +02:00
audacity/src/effects/Noise.cpp
Steve Daulton d9f3c432d4 Fix for bugs 943, 942, 941, 843 and 775.
Non-linear effects now process tracks before mixing.
This will be slower when multiple tracks are selected
but the preview should now match the applied effect.
SetLinearEffectFlag(true) allows linear effects to
preview more quickly when multiple tracks selected, by
pre-mixing selected tracks.
Simple generators like Tone and Noise may be marked as
'linear' so that they only preview a few seconds.
Generators that vary over time (such as Chirp) must use
the full duration that is set. As this currently
requires calculating the full duration, preview for
'non-linear' generators are not limited to the preview
length.
2015-05-15 12:51:51 +01:00

271 lines
6.2 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
Noise.cpp
Dominic Mazzoni
*******************************************************************//**
\class EffectNoise
\brief An effect to add white noise.
*//*******************************************************************/
#include "../Audacity.h"
#include <math.h>
#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] =
{
XO("White"),
XO("Pink"),
XO("Brownian")
};
// Define keys, defaults, minimums, and maximums for the effect parameters
//
// Name Type Key Def Min Max Scale
Param( Type, int, XO("Type"), kWhite, 0, kNumTypes - 1, 1 );
Param( Amp, double, XO("Amplitude"), 0.8, 0.0, 1.0, 1 );
//
// EffectNoise
//
EffectNoise::EffectNoise()
{
mType = DEF_Type;
mAmp = DEF_Amp;
SetLinearEffectFlag(true);
y = z = buf0 = buf1 = buf2 = buf3 = buf4 = buf5 = buf6 = 0;
}
EffectNoise::~EffectNoise()
{
}
// IdentInterface implementation
wxString EffectNoise::GetSymbol()
{
return NOISE_PLUGIN_SYMBOL;
}
wxString EffectNoise::GetDescription()
{
return XO("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;
float amplitude;
float div = ((float) RAND_MAX) / 2.0f;
switch (mType)
{
default:
case kWhite: // white
for (sampleCount i = 0; i < size; i++)
{
buffer[i] = mAmp * ((rand() / div) - 1.0f);
}
break;
case kPink: // pink
// based on Paul Kellet's "instrumentation grade" algorithm.
// 0.129f is an experimental normalization factor.
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 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;
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] = mAmp * y;
}
break;
}
return size;
}
bool EffectNoise::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.Write(KEY_Type, kTypeStrings[mType]);
parms.Write(KEY_Amp, mAmp);
return true;
}
bool EffectNoise::SetAutomationParameters(EffectAutomationParameters & parms)
{
ReadAndVerifyEnum(Type, wxArrayString(kNumTypes, kTypeStrings));
ReadAndVerifyDouble(Amp);
mType = Type;
mAmp = Amp;
return true;
}
// Effect implementation
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;
}
void EffectNoise::PopulateOrExchange(ShuttleGui & S)
{
wxASSERT(kNumTypes == WXSIZEOF(kTypeStrings));
wxArrayString typeChoices;
for (int i = 0; i < kNumTypes; i++)
{
typeChoices.Add(wxGetTranslation(kTypeStrings[i]));
}
S.StartMultiColumn(2, wxCENTER);
{
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);
bool isSelection;
double duration = GetDuration(&isSelection);
S.AddPrompt(_("Duration:"));
mNoiseDurationT = new
NumericTextCtrl(NumericConverter::TIME,
S.GetParent(),
wxID_ANY,
isSelection ? _("hh:mm:ss + samples") : _("hh:mm:ss + milliseconds"),
duration,
mProjectRate,
wxDefaultPosition,
wxDefaultSize,
true);
mNoiseDurationT->SetName(_("Duration"));
mNoiseDurationT->EnableMenu();
S.AddWindow(mNoiseDurationT, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL);
}
S.EndMultiColumn();
}
bool EffectNoise::TransferDataToWindow()
{
if (!mUIParent->TransferDataToWindow())
{
return false;
}
mNoiseDurationT->SetValue(GetDuration());
return true;
}
bool EffectNoise::TransferDataFromWindow()
{
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
SetDuration(mNoiseDurationT->GetValue());
return true;
}