Avatar

Please consider registering
guest

sp_LogInOut Log In sp_Registration Register

Register | Lost password?
Advanced Search

— Forum Scope —




— Match —





— Forum Options —





Minimum search word length is 3 characters - maximum search word length is 84 characters

sp_Feed Topic RSS sp_TopicIcon
Alternative PhaseShifter implementation
Avatar
Anglia
Member
Members
September 9, 2021 - 1:38 pm
Member Since: June 2, 2014
Forum Posts: 15
sp_UserOfflineSmall Offline

Hi all,

I've refactored the implementation of the PhaseShifter's processAudioSample() method, as the lists of variables, which admittedly correspond precisely with the variables covered in the PhaseShifter design section, were crying out to be refactored.

The below implementation might seem a little daunting for beginner programmers, but I'm quite sure it's solid, and more robust than the original, specifically with regards to extensibility. With the below implementation, the number of APFs can be extended (or reduced) simply be changing the value of the constant PHASER_STAGES.

There are a couple of helper methods I've used, which aren't necessarily part of this refactor, but I've included them to aid readability. These simply act as factory methods, or 'getters' (for internal use), to retrieve the desired constants for the APF cutoff values and mix coefficients. I intend at some point in the future to extend this plugin to allow the users to select from a choice of these values, but for now at least which values I'm using has been abstracted away via these factory methods. Obviously if PHASER_STAGES is changed, then the array returned by Phaser::getPhaserApfParameters() will need to extended, to ensure it also contains PHASER_STAGES number of elements.

If someone fancies doing a code review of this alternative implementation, that would be greatly appreciated!

struct PhaserAPFParameters {
	const double minF;
	const double maxF;
};
 
struct PhaserMixCoeffs
{
	const double dry;
	const double wet;
};
// --- these are the exact values from the National Semiconductor Phaser design
const PhaserAPFParameters nsPhaserParams[PHASER_STAGES] = 
    {{32.0, 1500.0}, {68.0, 3400.0}, {96.0, 4800.0}, {212.0, 10000.0}, {320.0, 16000.0}, {636.0, 20480.0}};
 
// dry/wet mix coefficients
const PhaserMixCoeffs idealPhaserMixCoeffs = {0.125, 1.25};

const PhaserAPFParameters* Phaser::getPhaserApfParameters()
{
	return nsPhaserParams;
}
 
PhaserMixCoeffs Phaser::getPhaserMixCoeffs()
{
	return idealPhaserMixCoeffs;
}
double Phaser::processAudioSample(double xn)
{
	const SignalGenData lfoData = lfo.renderAudioOutput();
 
	// --- create the bipolar modulator value
	double lfoValue = lfoData.normalOutput;
	if (parameters.quadPhaseLFO)
		lfoValue = lfoData.quadPhaseOutput_pos;
 
	const double depth = parameters.lfoDepth_Pct / 100.0;
	const double modulatorValue = lfoValue * depth;
 
	const PhaserAPFParameters* apfParams = getPhaserApfParameters();
	double gammas[PHASER_STAGES];
	double gamma = 1;
	for (uint32_t i = 0; i < PHASER_STAGES; i++)
	{
		// --- calculate modulated values for each APF; note they have different ranges
		AudioFilterParameters params = apfs[i].getParameters();
		params.fc = doBipolarModulation(modulatorValue, apfParams[i].minF, apfParams[i].maxF);
		apfs[i].setParameters(params);
 
		// --- calculate gamma values
		gamma = apfs[PHASER_STAGES - (i + 1)].getG_value() * gamma;
		gammas[i] = gamma;
	}
 
	// --- create combined feedback
	double Sn = 0;
	for (uint32_t i = 0; i < PHASER_STAGES; i++)
	{
		Sn += i < PHASER_STAGES - 1 ? gammas[PHASER_STAGES - (i+2)] * apfs[i].getS_value() : apfs[i].getS_value();
	}
	
	// --- set the alpha0 value
	const double K = parameters.intensity_Pct / 100.0;
	const double alpha0 = 1.0 / (1.0 + K * gamma);
 
	// --- form input to first APF
	double apfsOutput = alpha0 * (xn + K * Sn);
 
	// --- cascade of APFs
	for (auto& apf : apfs)
	{
		apfsOutput = apf.processAudioSample(apfsOutput);
	}
 
	// Mix dry & wet signal, based on chosen coefficients
	const PhaserMixCoeffs mixCoeffs = getPhaserMixCoeffs();
	const double output = mixCoeffs.dry * xn + mixCoeffs.wet * apfsOutput;
 
	return output;
}
Forum Timezone: America/New_York

Most Users Ever Online: 152

Currently Online:
13 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

Chaes: 56

jim: 53

Skyler: 48

Derek: 46

Frodson: 45

Peter: 43

TheSmile: 43

clau_ste: 39

Nickolai: 39

JimmyM: 33

Member Stats:

Guest Posters: 1

Members: 732

Moderators: 1

Admins: 5

Forum Stats:

Groups: 13

Forums: 42

Topics: 804

Posts: 3087

Moderators: W Pirkle: 640