summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2015-05-11 23:43:11 +1000
committerDamien Zammit <damien@zamaudio.com>2015-05-11 23:43:11 +1000
commitc4fe3ff6b0406efa65c9241f147c867745ae03b5 (patch)
treedd37e5e93160d16f351dd4c98ea672fda84bbd7c
parentf75581f76d3e0acd8b604c07ff1e69a649b505ff (diff)
Add ZamChild670 ladspa only. (no gui yet)
Signed-off-by: Damien Zammit <damien@zamaudio.com>
-rw-r--r--Makefile2
-rw-r--r--Makefile.mk2
-rw-r--r--plugins/ZamChild670/DistrhoPluginInfo.h37
-rw-r--r--plugins/ZamChild670/Makefile42
-rw-r--r--plugins/ZamChild670/ZamChild670Plugin.cpp209
-rw-r--r--plugins/ZamChild670/ZamChild670Plugin.hpp121
-rw-r--r--plugins/ZamChild670/generatedwdfutilities.h62
-rw-r--r--plugins/ZamChild670/glue.h13
-rw-r--r--plugins/ZamChild670/sidechainamplifier.cpp52
-rw-r--r--plugins/ZamChild670/sidechainamplifier.h157
-rw-r--r--plugins/ZamChild670/tubemodel.cpp51
-rw-r--r--plugins/ZamChild670/tubemodel.h185
-rw-r--r--plugins/ZamChild670/variablemuamplifier.cpp60
-rw-r--r--plugins/ZamChild670/variablemuamplifier.h113
-rw-r--r--plugins/ZamChild670/wavechild670.cpp36
-rw-r--r--plugins/ZamChild670/wavechild670.h233
-rw-r--r--plugins/ZamChild670/wdfcircuits.cpp25
-rw-r--r--plugins/ZamChild670/wdfcircuits.h633
18 files changed, 2031 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index bfe24b8..b48b037 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ BINDIR ?= bin
NAME = zam-plugins
VERSION = $(shell cat .version)
-PLUGINS=ZamComp ZamCompX2 ZaMultiComp ZamTube ZamEQ2 ZamAutoSat ZamGEQ31 ZamGEQ31X2 ZaMultiCompX2 ZamPiano ZamSFZ
+PLUGINS=ZamComp ZamCompX2 ZaMultiComp ZamTube ZamEQ2 ZamAutoSat ZamGEQ31 ZamGEQ31X2 ZaMultiCompX2 ZamPiano ZamSFZ ZamChild670
all: libs $(PLUGINS) gen
diff --git a/Makefile.mk b/Makefile.mk
index e450b8a..30e6703 100644
--- a/Makefile.mk
+++ b/Makefile.mk
@@ -21,7 +21,7 @@ endif
# --------------------------------------------------------------
# Common build and link flags
-BASE_FLAGS = -Wall -Wextra -pipe -Wno-switch
+BASE_FLAGS = -Wall -Wextra -pipe -Wno-switch -Wno-reorder
BASE_OPTS = -O2 -ffast-math -fdata-sections -ffunction-sections
ifneq ($(NOOPT),true)
BASE_OPTS += -mtune=generic -msse -msse2 -mfpmath=sse
diff --git a/plugins/ZamChild670/DistrhoPluginInfo.h b/plugins/ZamChild670/DistrhoPluginInfo.h
new file mode 100644
index 0000000..133905b
--- /dev/null
+++ b/plugins/ZamChild670/DistrhoPluginInfo.h
@@ -0,0 +1,37 @@
+/*
+ * ZamCompX2
+ * Copyright (C) 2014 Damien Zammit <damien@zamaudio.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * For a full copy of the GNU General Public License see the doc/GPL.txt file.
+ */
+
+#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED
+#define DISTRHO_PLUGIN_INFO_H_INCLUDED
+
+#define DISTRHO_PLUGIN_NAME "ZamChild670"
+
+#define DISTRHO_PLUGIN_HAS_UI 0
+#define DISTRHO_PLUGIN_IS_SYNTH 0
+
+#define DISTRHO_PLUGIN_NUM_INPUTS 2
+#define DISTRHO_PLUGIN_NUM_OUTPUTS 2
+
+#define DISTRHO_PLUGIN_WANT_LATENCY 0
+#define DISTRHO_PLUGIN_WANT_PROGRAMS 1
+#define DISTRHO_PLUGIN_WANT_STATE 0
+#define DISTRHO_PLUGIN_WANT_TIMEPOS 0
+#define DISTRHO_PLUGIN_IS_RT_SAFE 1
+
+#define DISTRHO_PLUGIN_URI "urn:zamaudio:ZamChild670"
+
+#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED
diff --git a/plugins/ZamChild670/Makefile b/plugins/ZamChild670/Makefile
new file mode 100644
index 0000000..7de113d
--- /dev/null
+++ b/plugins/ZamChild670/Makefile
@@ -0,0 +1,42 @@
+#!/usr/bin/make -f
+# Makefile for zam-plugins #
+# ------------------------ #
+# Created by falkTX
+#
+
+# --------------------------------------------------------------
+# Project name, used for binaries
+
+NAME = ZamChild670
+
+# --------------------------------------------------------------
+# Files to build
+
+OBJS_DSP = \
+ ZamChild670Plugin.cpp.o \
+ sidechainamplifier.cpp.o \
+ tubemodel.cpp.o \
+ variablemuamplifier.cpp.o \
+ wdfcircuits.cpp.o \
+ wavechild670.cpp.o
+
+OBJS_UI = #\
+ #ZamCompX2Artwork.cpp.o \
+ #ZamCompX2UI.cpp.o
+
+# --------------------------------------------------------------
+# Do some magic
+
+include ../Makefile.mk
+
+# --------------------------------------------------------------
+# Enable all possible plugin types
+
+ifeq ($(LINUX),true)
+#all: jack ladspa dssi lv2_sep vst
+all: ladspa
+else
+all: ladspa vst
+endif
+
+# --------------------------------------------------------------
diff --git a/plugins/ZamChild670/ZamChild670Plugin.cpp b/plugins/ZamChild670/ZamChild670Plugin.cpp
new file mode 100644
index 0000000..dc3f5aa
--- /dev/null
+++ b/plugins/ZamChild670/ZamChild670Plugin.cpp
@@ -0,0 +1,209 @@
+/*
+ * ZamChild670 Stereo tube limiter
+ * Copyright (C) 2015 Damien Zammit <damien@zamaudio.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * For a full copy of the GNU General Public License see the doc/GPL.txt file.
+ */
+
+#include "ZamChild670Plugin.hpp"
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+
+ZamChild670Plugin::ZamChild670Plugin()
+ : Plugin(paramCount, 1, 0) // 1 program, 0 states
+{
+ // set default values
+ inputLevel = from_dB(0.0);
+ ACThreshold = from_dB(-6.f);
+ timeConstantSelect = 2;
+ DCThreshold = from_dB(-12.f);
+ outputGain = from_dB(0.0);
+ params = new Wavechild670Parameters(inputLevel,
+ ACThreshold, timeConstantSelect, DCThreshold,
+ inputLevel, ACThreshold, timeConstantSelect, DCThreshold,
+ true, false, true, outputGain, false);
+ zamchild = new Wavechild670(d_getSampleRate(), *params);
+ d_setProgram(0);
+}
+
+ZamChild670Plugin::~ZamChild670Plugin()
+{
+ delete params;
+ delete zamchild;
+}
+
+// -----------------------------------------------------------------------
+// Init
+
+void ZamChild670Plugin::d_initParameter(uint32_t index, Parameter& parameter)
+{
+ switch (index)
+ {
+ case paramInlevel:
+ parameter.hints = kParameterIsAutomable;
+ parameter.name = "Input level";
+ parameter.symbol = "inlevel";
+ parameter.unit = "dB";
+ parameter.ranges.def = -16.0f;
+ parameter.ranges.min = -30.0f;
+ parameter.ranges.max = 0.0f;
+ break;
+ case paramAC:
+ parameter.hints = kParameterIsAutomable;
+ parameter.name = "AC Threshold";
+ parameter.symbol = "acthres";
+ parameter.unit = "dB";
+ parameter.ranges.def = -3.0f;
+ parameter.ranges.min = -20.0f;
+ parameter.ranges.max = 0.0f;
+ break;
+ case paramDC:
+ parameter.hints = kParameterIsAutomable;
+ parameter.name = "DC Threshold";
+ parameter.symbol = "dcthres";
+ parameter.unit = "dB";
+ parameter.ranges.def = -6.0f;
+ parameter.ranges.min = -20.0f;
+ parameter.ranges.max = 0.0f;
+ break;
+ case paramTau:
+ parameter.hints = kParameterIsAutomable | kParameterIsInteger;
+ parameter.name = "Time constant select";
+ parameter.symbol = "tau";
+ parameter.unit = " ";
+ parameter.ranges.def = 2.0f;
+ parameter.ranges.min = 1.0f;
+ parameter.ranges.max = 6.0f;
+ break;
+ case paramOutlevel:
+ parameter.hints = kParameterIsAutomable;
+ parameter.name = "Output level";
+ parameter.symbol = "outlevel";
+ parameter.unit = "dB";
+ parameter.ranges.def = 0.0f;
+ parameter.ranges.min = -30.0f;
+ parameter.ranges.max = 0.0f;
+ break;
+ }
+}
+
+void ZamChild670Plugin::d_initProgramName(uint32_t index, d_string& programName)
+{
+ if (index != 0)
+ return;
+
+ programName = "Default";
+}
+
+// -----------------------------------------------------------------------
+// Internal data
+
+float ZamChild670Plugin::d_getParameterValue(uint32_t index) const
+{
+ switch (index)
+ {
+ case paramInlevel:
+ return inputLevel;
+ break;
+ case paramAC:
+ return ACThreshold;
+ break;
+ case paramDC:
+ return DCThreshold;
+ break;
+ case paramTau:
+ return timeConstantSelect;
+ break;
+ case paramOutlevel:
+ return outputGain;
+ break;
+ default:
+ return 0.0f;
+ }
+}
+
+void ZamChild670Plugin::d_setParameterValue(uint32_t index, float value)
+{
+ switch (index)
+ {
+ case paramInlevel:
+ inputLevel = value;
+ break;
+ case paramAC:
+ ACThreshold = value;
+ break;
+ case paramDC:
+ DCThreshold = value;
+ break;
+ case paramTau:
+ timeConstantSelect = value;
+ break;
+ case paramOutlevel:
+ outputGain = value;
+ break;
+ }
+}
+
+void ZamChild670Plugin::d_setProgram(uint32_t index)
+{
+ if (index != 0)
+ return;
+
+ /* Default parameter values */
+ inputLevel = 0.0;
+ ACThreshold = -6.f;
+ timeConstantSelect = 2;
+ DCThreshold = -12.f;
+ outputGain = 0.0;
+
+ /* reset filter values */
+ d_activate();
+}
+
+// -----------------------------------------------------------------------
+// Process
+
+void ZamChild670Plugin::d_activate()
+{
+ params->inputLevelA = params->inputLevelB = from_dB(inputLevel);
+ params->ACThresholdA = params->ACThresholdB = from_dB(ACThreshold);
+ params->timeConstantSelectA = params->timeConstantSelectB = timeConstantSelect;
+ params->DCThresholdA = params->DCThresholdB = from_dB(DCThreshold);
+ params->outputGain = from_dB(outputGain);
+ zamchild->setParameters(*params);
+ zamchild->warmUp();
+}
+
+void ZamChild670Plugin::d_run(const float** inputs, float** outputs, uint32_t frames)
+{
+ params->inputLevelA = params->inputLevelB = from_dB(inputLevel);
+ params->ACThresholdA = params->ACThresholdB = from_dB(ACThreshold);
+ params->timeConstantSelectA = params->timeConstantSelectB = timeConstantSelect;
+ params->DCThresholdA = params->DCThresholdB = from_dB(DCThreshold);
+ params->outputGain = from_dB(outputGain);
+ zamchild->setParameters(*params);
+
+ zamchild->process(inputs, outputs, (ulong)frames);
+}
+// -----------------------------------------------------------------------
+
+Plugin* createPlugin()
+{
+ return new ZamChild670Plugin();
+}
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
diff --git a/plugins/ZamChild670/ZamChild670Plugin.hpp b/plugins/ZamChild670/ZamChild670Plugin.hpp
new file mode 100644
index 0000000..762d547
--- /dev/null
+++ b/plugins/ZamChild670/ZamChild670Plugin.hpp
@@ -0,0 +1,121 @@
+/*
+ * ZamChild670 stereo tube limiter
+ * Copyright (C) 2015 Damien Zammit <damien@zamaudio.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * For a full copy of the GNU General Public License see the doc/GPL.txt file.
+ */
+
+#ifndef ZAMCHILD670PLUGIN_HPP_INCLUDED
+#define ZAMCHILD670PLUGIN_HPP_INCLUDED
+
+#include "DistrhoPlugin.hpp"
+#include "wavechild670.h"
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+
+class ZamChild670Plugin : public Plugin
+{
+public:
+ enum Parameters
+ {
+ paramInlevel = 0,
+ paramAC,
+ paramDC,
+ paramTau,
+ paramOutlevel,
+ paramCount
+ };
+
+ ZamChild670Plugin();
+ ~ZamChild670Plugin();
+
+protected:
+ // -------------------------------------------------------------------
+ // Information
+
+ const char* d_getLabel() const noexcept override
+ {
+ return "ZamChild670";
+ }
+
+ const char* d_getMaker() const noexcept override
+ {
+ return "Damien Zammit";
+ }
+
+ const char* d_getLicense() const noexcept override
+ {
+ return "GPL v2+";
+ }
+
+ uint32_t d_getVersion() const noexcept override
+ {
+ return 0x1000;
+ }
+
+ int64_t d_getUniqueId() const noexcept override
+ {
+ return d_cconst('Z', 'C', 'L', 'D');
+ }
+
+ // -------------------------------------------------------------------
+ // Init
+
+ void d_initParameter(uint32_t index, Parameter& parameter) override;
+ void d_initProgramName(uint32_t index, d_string& programName) override;
+
+ // -------------------------------------------------------------------
+ // Internal data
+
+ float d_getParameterValue(uint32_t index) const override;
+ void d_setParameterValue(uint32_t index, float value) override;
+ void d_setProgram(uint32_t index) override;
+
+ // -------------------------------------------------------------------
+ // Process
+
+ static inline float
+ sanitize_denormal(float v) {
+ if(!std::isnormal(v))
+ return 0.f;
+ return v;
+ }
+
+ static inline float
+ from_dB(float gdb) {
+ return (exp(gdb/20.f*log(10.f)));
+ }
+
+ static inline float
+ to_dB(float g) {
+ return (20.f*log10(g));
+ }
+
+ void d_activate() override;
+ void d_run(const float** inputs, float** outputs, uint32_t frames) override;
+
+ // -------------------------------------------------------------------
+
+private:
+ Wavechild670Parameters *params;
+ Wavechild670 *zamchild;
+ float inputLevel, ACThreshold, timeConstantSelect, DCThreshold, outputGain;
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
+
+#endif // ZAMCOMPX2_HPP_INCLUDED
diff --git a/plugins/ZamChild670/generatedwdfutilities.h b/plugins/ZamChild670/generatedwdfutilities.h
new file mode 100644
index 0000000..7212456
--- /dev/null
+++ b/plugins/ZamChild670/generatedwdfutilities.h
@@ -0,0 +1,62 @@
+/************************************************************************************
+*
+* Wavechild670 v0.1
+*
+* generatedwdfutilities.h
+*
+* By Peter Raffensperger 10 July 2012
+*
+* Reference:
+* Toward a Wave Digital Filter Model of the Fairchild 670 Limiter, Raffensperger, P. A., (2012).
+* Proc. of the 15th International Conference on Digital Audio Effects (DAFx-12),
+* York, UK, September 17-21, 2012.
+*
+* Note:
+* Fairchild (R) a registered trademark of Avid Technology, Inc., which is in no way associated or
+* affiliated with the author.
+*
+* License:
+* Wavechild670 is licensed under the GNU GPL v2 license. If you use this
+* software in an academic context, we would appreciate it if you referenced the original
+* paper.
+*
+************************************************************************************/
+
+
+
+#ifndef GENERATEDWDFUTILITIES_H
+#define GENERATEDWDFUTILITIES_H
+
+#include "tubemodel.h"
+
+class BidirectionalUnitDelay;
+
+class BidirectionalUnitDelayInterface {
+public:
+ friend class BidirectionalUnitDelay;
+ void setA(Real a_){ a = a_; }
+ Real getB() { return b;}
+protected:
+ Real a;
+ Real b;
+};
+
+class BidirectionalUnitDelay {
+public:
+ BidirectionalUnitDelayInterface* getInterface(uint index){
+ if (index == 0){
+ return &interface0;
+ }
+ return &interface1;
+ }
+ void advance(){
+ interface0.b = interface1.a;
+ interface1.b = interface0.a;
+ }
+protected:
+ BidirectionalUnitDelayInterface interface0;
+ BidirectionalUnitDelayInterface interface1;
+};
+
+
+#endif
diff --git a/plugins/ZamChild670/glue.h b/plugins/ZamChild670/glue.h
new file mode 100644
index 0000000..0ced6ca
--- /dev/null
+++ b/plugins/ZamChild670/glue.h
@@ -0,0 +1,13 @@
+#include <cmath>
+#include <cstdlib>
+#include <vector>
+
+#ifndef GLUE_H
+#define GLUE_H
+
+#define Assert(x)
+#define Confirm(x)
+typedef double Real;
+
+
+#endif
diff --git a/plugins/ZamChild670/sidechainamplifier.cpp b/plugins/ZamChild670/sidechainamplifier.cpp
new file mode 100644
index 0000000..46afb09
--- /dev/null
+++ b/plugins/ZamChild670/sidechainamplifier.cpp
@@ -0,0 +1,52 @@
+/************************************************************************************
+*
+* Wavechild670 v0.1
+*
+* sidechainamplifier.cpp
+*
+* By Peter Raffensperger 10 July 2012
+*
+* Reference:
+* Toward a Wave Digital Filter Model of the Fairchild 670 Limiter, Raffensperger, P. A., (2012).
+* Proc. of the 15th International Conference on Digital Audio Effects (DAFx-12),
+* York, UK, September 17-21, 2012.
+*
+* Note:
+* Fairchild (R) a registered trademark of Avid Technology, Inc., which is in no way associated or
+* affiliated with the author.
+*
+* License:
+* Wavechild670 is licensed under the GNU GPL v2 license. If you use this
+* software in an academic context, we would appreciate it if you referenced the original
+* paper.
+*
+************************************************************************************/
+
+
+
+#include "sidechainamplifier.h"
+
+//Input stage
+const Real SidechainAmplifier::RinSeriesValue = 600;
+const Real SidechainAmplifier::RinParallelValue = 1360;
+const Real SidechainAmplifier::Lp = 2e-3;
+const Real SidechainAmplifier::Rp = 10.0;
+const Real SidechainAmplifier::Rc = 50e3;
+const Real SidechainAmplifier::Lm = 5.7;
+const Real SidechainAmplifier::Rs = 50.0;
+const Real SidechainAmplifier::Ls = 1e-3;
+const Real SidechainAmplifier::Cw = 10e-12;
+const Real SidechainAmplifier::NpOverNs = 1.0/17.0;
+const Real SidechainAmplifier::RpotValue = 2*76e3; //includes the 25k center tap resistor. The pot itself is 100k. Two in series is the load seen by the sidechain input, while the input voltage to the sidechain amp is the voltage across just one of them.
+
+//DC Threshold stage, 12AX7 amplifier
+const Real SidechainAmplifier::DCThresholdScaleFactor = 12.2;
+const Real SidechainAmplifier::DCThresholdOffset = 0.1;
+const Real SidechainAmplifier::VscScaleFactor = -6.0;
+
+//Drive stage, 12BH7 + 6973 amplifier stages
+const Real SidechainAmplifier::overallVoltageGain = 8.4; //Used to be 17
+const Real SidechainAmplifier::finalOutputClipVoltage = 100.0;
+const Real SidechainAmplifier::diodeDropX2 = 0.6; //Twice the diode voltage drop, germanium diodes
+const Real SidechainAmplifier::nominalOutputConductance = 1.0 / 160.0; //ohms. Used to be 80
+const Real SidechainAmplifier::maxOutputCurrent = 0.5; //amps
diff --git a/plugins/ZamChild670/sidechainamplifier.h b/plugins/ZamChild670/sidechainamplifier.h
new file mode 100644
index 0000000..4972c46
--- /dev/null
+++ b/plugins/ZamChild670/sidechainamplifier.h
@@ -0,0 +1,157 @@
+/************************************************************************************
+*
+* Wavechild670 v0.1
+*
+* sidechainamplifier.h
+*
+* By Peter Raffensperger 10 July 2012
+*
+* Reference:
+* Toward a Wave Digital Filter Model of the Fairchild 670 Limiter, Raffensperger, P. A., (2012).
+* Proc. of the 15th International Conference on Digital Audio Effects (DAFx-12),
+* York, UK, September 17-21, 2012.
+*
+* Note:
+* Fairchild (R) a registered trademark of Avid Technology, Inc., which is in no way associated or
+* affiliated with the author.
+*
+* License:
+* Wavechild670 is licensed under the GNU GPL v2 license. If you use this
+* software in an academic context, we would appreciate it if you referenced the original
+* paper.
+*
+************************************************************************************/
+
+
+
+#ifndef SIDECHAINAMPLIFIER_H
+#define SIDECHAINAMPLIFIER_H
+
+#include "glue.h"
+#include "wdfcircuits.h"
+
+class SidechainAmplifier {
+public:
+ SidechainAmplifier(Real sampleRate, Real ACThresholdNew, Real DCThresholdNew) : inputCircuit(Cw, 0.0, Lm, Lp, Ls, NpOverNs, Rc, RinParallelValue, RpotValue, Rp, Rs, RinSeriesValue, sampleRate) {
+ setThresholds(ACThresholdNew, DCThresholdNew);
+
+ calls = 0;
+ currentOvers = 0;
+
+ }
+ virtual ~SidechainAmplifier(){
+ }
+
+ virtual void setThresholds(Real ACThresholdNew, Real DCThresholdNew){
+ Assert(DCThresholdNew >= 0.0);
+ Assert(DCThresholdNew <= 1.0);
+
+ Assert(ACThresholdNew >= 0.0);
+ Assert(ACThresholdNew <= 1.0);
+
+ DCThresholdProcessed = -DCThresholdScaleFactor*(DCThresholdNew + DCThresholdOffset);
+ ACThresholdProcessed = 0.5*ACThresholdNew*ACThresholdNew; //A nice curve that approximates the piecewise linear taper on the centre-potted tap curve on the Fairchild 670
+ }
+
+ virtual Real advanceAndGetCurrent(Real VinSidechain, Real VlevelCap) {
+ Assert(!isnan(VinSidechain));
+ Assert(!isnan(VlevelCap));
+ calls++;
+ Real VgPlus = ACThresholdProcessed*inputCircuit.advance(VinSidechain);
+ Assert(!isnan(VgPlus));
+ Real Vsc = getDCThresholdStageVsc(VgPlus);
+ Confirm(!isnan(Vsc));
+ Real Vamp = Vsc * overallVoltageGain;
+ //Vamp = BasicDSP::clip(Vamp, -finalOutputClipVoltage, finalOutputClipVoltage); //Voltage saturation of the final output stage
+ Real Vdiff = fabs(Vamp) - VlevelCap;
+
+ Real Iout = getDriveStageCurrent(Vdiff, VlevelCap);
+ Confirm(!isnan(Iout));
+ return Iout;
+ }
+protected:
+
+ inline Real getDCThresholdStageVsc(Real VgPlus) {
+ Real xp = log1p(exp(VgPlus + DCThresholdProcessed));
+ Real xm = log1p(exp(-VgPlus + DCThresholdProcessed));
+ Real x = xp - xm;
+ return VscScaleFactor*x;
+ }
+
+ inline Real sidechainAmplifierCurrentSaturation(Real i) {
+ Assert(isfinite(i));
+ //One side-saturation (does not saturate negatives)
+ const Real b = 10.0/maxOutputCurrent;
+ const Real c = 10.0;
+ Real isat = log1p(exp(b*i-c))/b;
+ isat = fmin(isat, i);
+ Confirm(isfinite(isat));
+ if (i > maxOutputCurrent) {
+ currentOvers += 1;
+ }
+ return i - isat;
+ }
+
+ inline Real diodeModel(Real V) {
+ const Real b = 10.0/diodeDropX2;
+ const Real c = 10.0;
+ if (V < 20.0){
+ return log1p(exp(b*V-c))/b;
+ }
+ else{
+ return V - diodeDropX2;
+ }
+ }
+
+// inline Real resistorPlusDiodeModel(Real Vdiff) {
+// const Real isat = diodeModelBase(0.0);
+// Real i = diodeModelBase(Vdiff) - isat;
+// return i;
+// }
+
+ inline Real getDriveStageCurrent(Real Vdiff, Real Vcap) {
+ Assert(isfinite(Vdiff));
+ Assert(isfinite(Vcap));
+ Real current = diodeModel(Vdiff) * nominalOutputConductance;
+ Confirm(isfinite(current));
+ current = sidechainAmplifierCurrentSaturation(current);
+ return current;
+ }
+
+protected:
+ uint calls;
+ uint currentOvers;
+
+ Real ACThresholdProcessed;
+ Real DCThresholdProcessed;
+
+ TransformerCoupledInputCircuit inputCircuit;
+
+ //Input stage
+ static const Real RinSeriesValue;
+ static const Real RinParallelValue;
+ static const Real Lp;
+ static const Real Rp;
+ static const Real Rc;
+ static const Real Lm;
+ static const Real Rs;
+ static const Real Ls;
+ static const Real Cw;
+ static const Real NpOverNs;
+ static const Real RpotValue; // = 2*76e3 //include the 25k center tap resistor. The pot itis 100k. Two in series is the load seen by the sidechain input, while the input voltage to the sidechain amp is the voltage across just one of them.
+
+ //DC Threshold stage, 12AX7 amplifier
+ static const Real DCThresholdScaleFactor; // 12.2
+ static const Real DCThresholdOffset; // 0.1
+ static const Real VscScaleFactor; // -6.0
+
+ //Drive stage, 12BH7 + 6973 amplifier stages
+ static const Real overallVoltageGain; // 17 //17 seemed like the gain of the drive stage in my SPICE simulation, but this number was then empirically fiddled to better match the performance implied by Fairchild 670 manual (and to get more compression)
+ static const Real finalOutputClipVoltage; // 100.0
+ static const Real diodeDropX2; // 1.5 //Twice the diode voltage drop
+ static const Real nominalOutputConductance; // 1.0/80.0 //ohms
+ static const Real maxOutputCurrent; // 0.5 //amps
+
+};
+
+#endif
diff --git a/plugins/ZamChild670/tubemodel.cpp b/plugins/ZamChild670/tubemodel.cpp
new file mode 100644
index 0000000..f1a6dda
--- /dev/null
+++ b/plugins/ZamChild670/tubemodel.cpp
@@ -0,0 +1,51 @@
+/************************************************************************************
+*
+* Wavechild670 v0.1
+*
+* tubemodel.cpp
+*
+* By Peter Raffensperger 10 July 2012
+*
+* Reference:
+* Toward a Wave Digital Filter Model of the Fairchild 670 Limiter, Raffensperger, P. A., (2012).
+* Proc. of the 15th International Conference on Digital Audio Effects (DAFx-12),
+* York, UK, September 17-21, 2012.
+*
+* Note:
+* Fairchild (R) a registered trademark of Avid Technology, Inc., which is in no way associated or
+* affiliated with the author.
+*
+* License:
+* Wavechild670 is licensed under the GNU GPL v2 license. If you use this
+* software in an academic context, we would appreciate it if you referenced the original
+* paper.
+*
+************************************************************************************/
+
+
+
+#include "tubemodel.h"
+
+const Real TriodeRemoteCutoff6386::fa = -0.1961135820501605;
+const Real TriodeRemoteCutoff6386::aa = 3.980508168e-08;
+const Real TriodeRemoteCutoff6386::ab = 2.3830020303;
+const Real TriodeRemoteCutoff6386::e = -1.8;
+const Real TriodeRemoteCutoff6386::d = 0.5;
+const Real TriodeRemoteCutoff6386::c = 10.0;
+const Real TriodeRemoteCutoff6386::g = 5.0;
+const Real TriodeRemoteCutoff6386::h = 0.5;
+
+Real WDFTubeInterface::iterateNewtonRaphson(Real x, Real dx){
+ /*
+ x(n+1) = x(n) - Fn(x)/Fn'(x)
+
+ Fn'(x) = dFn(x)/dx = (Fn(x + dx) - Fn(x))/(dx) #Finite difference approximation
+
+ x(n+1) = x(n) - dx*Fn(x)/(Fn(x+dx) - Fn(x))
+ */
+ Real F = evaluateImplicitEquation(x);
+ Real xNew = x - dx*F/(evaluateImplicitEquation(x + dx) - F);
+ Assert(isfinite(xNew));
+ return xNew;
+}
+
diff --git a/plugins/ZamChild670/tubemodel.h b/plugins/ZamChild670/tubemodel.h
new file mode 100644
index 0000000..c146fe1
--- /dev/null
+++ b/plugins/ZamChild670/tubemodel.h
@@ -0,0 +1,185 @@
+/************************************************************************************
+*
+* Wavechild670 v0.1
+*
+* tubemodel.h
+*
+* By Peter Raffensperger 10 July 2012
+*
+* Reference:
+* Toward a Wave Digital Filter Model of the Fairchild 670 Limiter, Raffensperger, P. A., (2012).
+* Proc. of the 15th International Conference on Digital Audio Effects (DAFx-12),
+* York, UK, September 17-21, 2012.
+*
+* Note:
+* Fairchild (R) a registered trademark of Avid Technology, Inc., which is in no way associated or
+* affiliated with the author.
+*
+* License:
+* Wavechild670 is licensed under the GNU GPL v2 license. If you use this
+* software in an academic context, we would appreciate it if you referenced the original
+* paper.
+*
+************************************************************************************/
+
+
+
+#ifndef TUBEMODEL_H
+#define TUBEMODEL_H
+
+#include "glue.h"
+
+class TriodeModel {
+public:
+ TriodeModel() {}
+ virtual ~TriodeModel() {}
+ virtual Real getIa(Real Vgk, Real Vak) {
+ return 0.0;
+ }
+ virtual Real getIg(Real Vgk, Real Vak) {
+ return 0.0;
+ }
+
+ virtual TriodeModel* clone() const { return new TriodeModel(*this); }
+private:
+ TriodeModel(const TriodeModel& other) { }
+};
+
+class TriodeRemoteCutoff6386 : public TriodeModel {
+public:
+ TriodeRemoteCutoff6386() : VgkLast(1.0), numeratorLast(0.0) { }
+ virtual ~TriodeRemoteCutoff6386() { }
+
+ virtual Real getIa(Real Vgk, Real Vak){
+ if (Vak < 0.0) {
+ Vak = 0.0;
+ }
+ if (Vgk > 0.0) {
+ Vgk = 0.0;
+ }
+ Real p1 = 3.981e-8;
+ Real p2 = 2.383;
+ Real p3 = 0.5;
+ Real p4 = 0.1;
+ Real p5 = 1.8;
+ Real p6 = 0.5;
+ Real p7 = -0.03922;
+ Real p8 = 0.2;
+ Real iakAlt = p1*pow(Vak, p2) / (pow((p3-p4*Vgk), p5)*(p6+exp(p7*Vak-p8*Vgk)));
+ return iakAlt;
+
+ }
+ virtual TriodeModel* clone() const { return new TriodeRemoteCutoff6386(*this); }
+
+private:
+ TriodeRemoteCutoff6386(const TriodeRemoteCutoff6386& other) {
+ VgkLast = other.VgkLast;
+ numeratorLast = other.numeratorLast;
+ }
+
+protected:
+
+ static inline Real getA(Real Vak){
+ return aa*pow(Vak, ab);
+ }
+ static inline Real getF(Real Vak){
+ return fa*Vak;
+ }
+
+protected:
+ Real VgkLast;
+ Real numeratorLast;
+
+ static const Real fa;
+ static const Real aa;
+ static const Real ab;
+ static const Real e;
+ static const Real d;
+ static const Real c;
+ static const Real g;
+ static const Real h;
+};
+
+class WDFTubeInterface {
+public:
+ WDFTubeInterface() { model = NULL; }
+ WDFTubeInterface(TriodeModel *model_, Real numParallelInstances_=3.0) : model(model_),
+ numParallelInstances(numParallelInstances_) {
+ a = 0.0;
+ Vgk = 0.0;
+ Iak = 0.0;
+ VakGuess = 100.0;
+ }
+ ~WDFTubeInterface() { delete model; }
+
+ WDFTubeInterface(WDFTubeInterface& other) {
+ model = other.model->clone();
+ numParallelInstances = other.numParallelInstances;
+ a = other.a;
+ Vgk = other.Vgk;
+ Iak = other.Iak;
+ VakGuess = other.VakGuess;
+ }
+
+ Real getB(Real a_, Real r0_, Real Vgate, Real Vk){
+ Assert(model);
+ /*
+ Reference:
+ "Wave Digital Simulation of a Vacuum-Tube Amplifier"
+ By M. Karjalainen and J. Pakarinen, ICASSP 2006
+
+ Vak + R0*f(Vgk, Vak) - a = 0 #[Karjalainen and Pakarinen, eq 7]
+ b = Vak - Ro*f(Vgk, Vak) #[Karjalainen and Pakarinen, eq 8]
+ */
+
+ r0 = r0_;
+
+ a = a_;
+
+ Vgk = Vgate - Vk;
+
+ Real Vak = VakGuess;
+ uint iteration = 0;
+ Real err = 1e6;
+ Iak = 0.0;
+
+ while (fabs(err)/fabs(Vak) > 1e-9){
+ VakGuess = iterateNewtonRaphson(Vak);
+ err = Vak - VakGuess;
+ Vak = VakGuess;
+
+ if (iteration > 100){
+ break;
+ }
+ ++iteration;
+ }
+ Real b = Vak - r0*Iak;
+ /*
+ a = v + Ri
+ b = v - Ri
+ v = a + b
+ */
+ return b;
+ }
+
+protected:
+ Real evaluateImplicitEquation(Real Vak){
+ Assert(!isnan(Vak));
+ Assert(!isnan(Vgk));
+ Iak = model->getIa(Vgk, Vak) * numParallelInstances;
+ Assert(!isnan(Iak));
+ return Vak + r0*Iak - a;
+ }
+ Real iterateNewtonRaphson(Real x, Real dxFactor=1e-6);
+
+ Real numParallelInstances;
+
+ Real r0;
+ Real a;
+ Real Vgk;
+ Real Iak;
+ Real VakGuess;
+ TriodeModel *model;
+};
+
+#endif
diff --git a/plugins/ZamChild670/variablemuamplifier.cpp b/plugins/ZamChild670/variablemuamplifier.cpp
new file mode 100644
index 0000000..d94f93f
--- /dev/null
+++ b/plugins/ZamChild670/variablemuamplifier.cpp
@@ -0,0 +1,60 @@
+/************************************************************************************
+*
+* Wavechild670 v0.1
+*
+* variablemuamplifier.cpp
+*
+* By Peter Raffensperger 10 July 2012
+*
+* Reference:
+* Toward a Wave Digital Filter Model of the Fairchild 670 Limiter, Raffensperger, P. A., (2012).
+* Proc. of the 15th International Conference on Digital Audio Effects (DAFx-12),
+* York, UK, September 17-21, 2012.
+*
+* Note:
+* Fairchild (R) a registered trademark of Avid Technology, Inc., which is in no way associated or
+* affiliated with the author.
+*
+* License:
+* Wavechild670 is licensed under the GNU GPL v2 license. If you use this
+* software in an academic context, we would appreciate it if you referenced the original
+* paper.
+*
+************************************************************************************/
+
+
+
+#include "variablemuamplifier.h"
+
+const Real VariableMuAmplifier::RinputValue = 600.0;
+const Real VariableMuAmplifier::RinputTerminationValue = 360.0;
+const Real VariableMuAmplifier::inputTxLp = 4e-3;
+const Real VariableMuAmplifier::inputTxRp = 10.0;
+const Real VariableMuAmplifier::inputTxRc = 10e3;
+const Real VariableMuAmplifier::inputTxLm = 35.7;
+const Real VariableMuAmplifier::inputTxRs = 50.0;
+const Real VariableMuAmplifier::inputTxLs = 1e-3;
+const Real VariableMuAmplifier::inputTxCw = 210e-12;
+const Real VariableMuAmplifier::inputTxNpOverNs = 2.0/9.0 ;
+//1:9 from the Drip Fairchild 670 transformer docs, decreased to meet the desired distortion specs, possibly with good reason given that the two primary sides are connected together!
+const Real VariableMuAmplifier::RgateValue = 100e3;
+const Real VariableMuAmplifier::VgateBiasConst = -7.2;
+
+//Amplifier
+const Real VariableMuAmplifier::numTubeParallelInstances = 2.0;
+const Real VariableMuAmplifier::RcathodeValue = 705;
+const Real VariableMuAmplifier::CcathodeValue = 8e-6; //Should be twice the number on the Fairchild 670 schematic because there's effectively two of these in series
+const Real VariableMuAmplifier::VcathodeBias = -3.1;
+const Real VariableMuAmplifier::RoutputValue = 600.0;
+const Real VariableMuAmplifier::RsidechainValue = 1000.0; //should only be non-infinite in a feedback topology
+const Real VariableMuAmplifier::RplateValue = 33;
+const Real VariableMuAmplifier::Vplate = 240.0;
+
+const Real VariableMuAmplifier::outputTxLp = 100e-6;
+const Real VariableMuAmplifier::outputTxRp = 5.0;
+const Real VariableMuAmplifier::outputTxRc = inputTxRc;
+const Real VariableMuAmplifier::outputTxLm = inputTxLm;
+const Real VariableMuAmplifier::outputTxRs = 1.0;
+const Real VariableMuAmplifier::outputTxLs = 400e-6;
+const Real VariableMuAmplifier::outputTxCw = 1e-12;
+const Real VariableMuAmplifier::outputTxNpOverNs = 1.0/inputTxNpOverNs; //Somehow this gets inverted in the wdf code
diff --git a/plugins/ZamChild670/variablemuamplifier.h b/plugins/ZamChild670/variablemuamplifier.h
new file mode 100644
index 0000000..3ddf7d7
--- /dev/null
+++ b/plugins/ZamChild670/variablemuamplifier.h
@@ -0,0 +1,113 @@
+/************************************************************************************
+*
+* Wavechild670 v0.1
+*
+* variablemuamplifier.h
+*
+* By Peter Raffensperger 10 July 2012
+*
+* Reference:
+* Toward a Wave Digital Filter Model of the Fairchild 670 Limiter, Raffensperger, P. A., (2012).
+* Proc. of the 15th International Conference on Digital Audio Effects (DAFx-12),
+* York, UK, September 17-21, 2012.
+*
+* Note:
+* Fairchild (R) a registered trademark of Avid Technology, Inc., which is in no way associated or
+* affiliated with the author.
+*
+* License:
+* Wavechild670 is licensed under the GNU GPL v2 license. If you use this
+* software in an academic context, we would appreciate it if you referenced the original
+* paper.
+*
+************************************************************************************/
+
+
+
+#ifndef VARIABLEMUAMPLIFIER_H
+#define VARIABLEMUAMPLIFIER_H
+
+#include "glue.h"
+#include "wdfcircuits.h"
+#include "tubemodel.h"
+
+#define CATHODE_CAPACITOR_CONN_R 1e-6
+
+class VariableMuAmplifier {
+ /*
+ Simulation of a variable-Mu tube amplifier using the 6386 remote-cutoff tube
+ Peter Raffensperger
+ 2012
+
+ References:
+ "Wave Digital Simulation of a Vacuum-Tube Amplifier"
+ By M. Karjalainen and J. Pakarinen, ICASSP 2006
+
+ */
+public:
+ VariableMuAmplifier(Real sampleRate) : inputCircuit(inputTxCw, 0.0, inputTxLm, inputTxLp, inputTxLs, inputTxNpOverNs, inputTxRc, RinputTerminationValue, RgateValue, inputTxRp, inputTxRs, RinputValue, sampleRate),
+ tubeModelInterface(new TriodeRemoteCutoff6386(), numTubeParallelInstances),
+ tubeAmpPush(CcathodeValue, outputTxCw, VcathodeBias, Vplate, outputTxLm, outputTxLp, outputTxLs, outputTxNpOverNs, outputTxRc, RoutputValue, outputTxRp, outputTxRs, RsidechainValue, RcathodeValue, RplateValue, CATHODE_CAPACITOR_CONN_R, cathodeCapacitorConn.getInterface(0), sampleRate, tubeModelInterface),
+ tubeAmpPull(CcathodeValue, outputTxCw, VcathodeBias, Vplate, outputTxLm, outputTxLp, outputTxLs, outputTxNpOverNs, outputTxRc, RoutputValue, outputTxRp, outputTxRs, RsidechainValue, RcathodeValue, RplateValue, CATHODE_CAPACITOR_CONN_R, cathodeCapacitorConn.getInterface(1), sampleRate, tubeModelInterface) {
+
+ }
+ virtual ~VariableMuAmplifier() { }
+
+ virtual Real advanceAndGetOutputVoltage(Real inputVoltage, Real VlevelCap){
+ Assert(!isnan(inputVoltage));
+ Assert(!isnan(VlevelCap));
+ Real Vgate = inputCircuit.advance(inputVoltage);
+ Assert(!isnan(Vgate));
+ Real VoutPush = tubeAmpPush.advance(VgateBiasConst - VlevelCap + Vgate);
+ Real VoutPull = tubeAmpPull.advance(VgateBiasConst - VlevelCap - Vgate);
+ cathodeCapacitorConnector.advance();
+ return VoutPush - VoutPull;
+ }
+protected:
+ //Input circuit
+ TransformerCoupledInputCircuit inputCircuit;
+ BidirectionalUnitDelay cathodeCapacitorConn;
+
+ //Amplifier
+ WDFTubeInterface tubeModelInterface;
+ BidirectionalUnitDelay cathodeCapacitorConnector;
+ TubeStageCircuit tubeAmpPull;
+ TubeStageCircuit tubeAmpPush;
+
+ //Input circuit
+ static const Real RinputValue;
+ static const Real RinputTerminationValue;
+ static const Real inputTxLp;
+ static const Real inputTxRp;
+ static const Real inputTxRc;
+ static const Real inputTxLm;
+ static const Real inputTxRs;
+ static const Real inputTxLs;
+ static const Real inputTxCw;
+ static const Real inputTxNpOverNs;
+ static const Real RgateValue;
+ static const Real VgateBiasConst;
+
+ //Amplifier
+ static const Real numTubeParallelInstances;
+
+ static const Real RcathodeValue;
+ static const Real CcathodeValue; //Should be twice the number on the Fairchild 670 schematic because there's effectively two of these in series
+ static const Real VcathodeBias;
+ static const Real RoutputValue;
+ static const Real RsidechainValue; //should only be non-infinite in a feedback topology
+ static const Real RplateValue;
+ static const Real Vplate;
+
+ static const Real outputTxLp;
+ static const Real outputTxRp;
+ static const Real outputTxRc;
+ static const Real outputTxLm;
+ static const Real outputTxRs;
+ static const Real outputTxLs;
+ static const Real outputTxCw;
+ static const Real outputTxNpOverNs;
+};
+
+
+#endif
diff --git a/plugins/ZamChild670/wavechild670.cpp b/plugins/ZamChild670/wavechild670.cpp
new file mode 100644
index 0000000..c9cbe32
--- /dev/null
+++ b/plugins/ZamChild670/wavechild670.cpp
@@ -0,0 +1,36 @@
+/************************************************************************************
+*
+* Wavechild670 v0.1
+*
+* wavechild670.cpp
+*
+* By Peter Raffensperger 10 July 2012
+*
+* Reference:
+* Toward a Wave Digital Filter Model of the Fairchild 670 Limiter, Raffensperger, P. A., (2012).
+* Proc. of the 15th International Conference on Digital Audio Effects (DAFx-12),
+* York, UK, September 17-21, 2012.
+*
+* Note:
+* Fairchild (R) a registered trademark of Avid Technology, Inc., which is in no way associated or
+* affiliated with the author.
+*
+* License:
+* Wavechild670 is licensed under the GNU GPL v2 license. If you use this
+* software in an academic context, we would appreciate it if you referenced the original
+* paper.
+*
+************************************************************************************/
+
+
+
+#include "wavechild670.h"
+
+const Real Wavechild670::levelTimeConstantCircuitComponentValues[6][6] = {
+ /* C1, C2, C3, R1, R2, R3 */
+ { 2e-6, 8e-6, 20e-6, 51.9e3, 10e9, 10e9 },
+ { 2e-6, 8e-6, 20e-6, 149.9e3, 10e9, 10e9 },
+ { 4e-6, 8e-6, 20e-6, 220e3, 10e9, 10e9 },
+ { 8e-6, 8e-6, 20e-6, 220e3, 10e9, 10e9 },
+ { 4e-6, 8e-6, 20e-6, 220e3, 100e3, 10e9 },
+ { 2e-6, 8e-6, 20e-6, 220e3, 100e3, 100e3 }};
diff --git a/plugins/ZamChild670/wavechild670.h b/plugins/ZamChild670/wavechild670.h
new file mode 100644
index 0000000..ab30f95
--- /dev/null
+++ b/plugins/ZamChild670/wavechild670.h
@@ -0,0 +1,233 @@
+/************************************************************************************
+*
+* Wavechild670 v0.1
+*
+* wavechild670.h
+*
+* By Peter Raffensperger 10 July 2012
+*
+* Reference:
+* Toward a Wave Digital Filter Model of the Fairchild 670 Limiter, Raffensperger, P. A., (2012).
+* Proc. of the 15th International Conference on Digital Audio Effects (DAFx-12),
+* York, UK, September 17-21, 2012.
+*
+* Note:
+* Fairchild (R) a registered trademark of Avid Technology, Inc., which is in no way associated or
+* affiliated with the author.
+*
+* License:
+* Wavechild670 is licensed under the GNU GPL v2 license. If you use this
+* software in an academic context, we would appreciate it if you referenced the original
+* paper.
+*
+************************************************************************************/
+
+
+
+#ifndef WAVECHILD670_H
+#define WAVECHILD670_H
+
+#include "glue.h"
+#include "sidechainamplifier.h"
+#include "variablemuamplifier.h"
+
+#define LEVELTC_CIRCUIT_DEFAULT_C_C1 2e-6
+#define LEVELTC_CIRCUIT_DEFAULT_C_C2 8e-6
+#define LEVELTC_CIRCUIT_DEFAULT_C_C3 20e-6
+#define LEVELTC_CIRCUIT_DEFAULT_R_R1 220e3
+#define LEVELTC_CIRCUIT_DEFAULT_R_R2 1e9
+#define LEVELTC_CIRCUIT_DEFAULT_R_R3 1e9
+
+class Wavechild670Parameters {
+public:
+ Wavechild670Parameters(Real inputLevelA_, Real ACThresholdA_, uint timeConstantSelectA_, Real DCThresholdA_,
+ Real inputLevelB_, Real ACThresholdB_, uint timeConstantSelectB_, Real DCThresholdB_,
+ bool sidechainLink_, bool isMidSide_, bool useFeedbackTopology_, Real outputGain_, bool hardClipOutput_){
+ inputLevelA = inputLevelA_;
+ ACThresholdA = ACThresholdA_;
+ timeConstantSelectA = timeConstantSelectA_;
+ DCThresholdA = DCThresholdA_;
+
+ inputLevelB = inputLevelB_;
+ ACThresholdB = ACThresholdB_;
+ timeConstantSelectB = timeConstantSelectB_;
+ DCThresholdB = DCThresholdB_;
+
+ sidechainLink = sidechainLink_;
+ isMidSide = isMidSide_;
+ useFeedbackTopology = useFeedbackTopology_;
+ outputGain = outputGain_;
+ hardClipOutput = hardClipOutput_;
+
+ }
+ virtual ~Wavechild670Parameters() {}
+public:
+ Real inputLevelA;
+ Real ACThresholdA;
+ uint timeConstantSelectA;
+ Real DCThresholdA;
+
+ Real inputLevelB;
+ Real ACThresholdB;
+ uint timeConstantSelectB;
+ Real DCThresholdB;
+
+ bool sidechainLink;
+ bool isMidSide;
+ bool useFeedbackTopology;
+
+ Real outputGain;
+ bool hardClipOutput;
+private:
+ Wavechild670Parameters() {}
+};
+
+class Wavechild670 {
+public:
+ Wavechild670(Real sampleRate_, Wavechild670Parameters& parameters) :
+ sampleRate(sampleRate_),
+ useFeedbackTopology(parameters.useFeedbackTopology), isMidSide(parameters.isMidSide), sidechainLink(parameters.sidechainLink),
+ sidechainAmplifierA(sampleRate, parameters.ACThresholdA, parameters.DCThresholdA), sidechainAmplifierB(sampleRate, parameters.ACThresholdB, parameters.DCThresholdB),
+ levelTimeConstantCircuitA(LEVELTC_CIRCUIT_DEFAULT_C_C1, LEVELTC_CIRCUIT_DEFAULT_C_C2, LEVELTC_CIRCUIT_DEFAULT_C_C3, LEVELTC_CIRCUIT_DEFAULT_R_R1, LEVELTC_CIRCUIT_DEFAULT_R_R2, LEVELTC_CIRCUIT_DEFAULT_R_R3, sampleRate),
+ levelTimeConstantCircuitB(LEVELTC_CIRCUIT_DEFAULT_C_C1, LEVELTC_CIRCUIT_DEFAULT_C_C2, LEVELTC_CIRCUIT_DEFAULT_C_C3, LEVELTC_CIRCUIT_DEFAULT_R_R1, LEVELTC_CIRCUIT_DEFAULT_R_R2, LEVELTC_CIRCUIT_DEFAULT_R_R3, sampleRate),
+ VlevelCapA(0.0), VlevelCapB(0.0),
+ signalAmplifierA(sampleRate), signalAmplifierB(sampleRate), inputLevelA(parameters.inputLevelA), inputLevelB(parameters.inputLevelB) {
+ setParameters(parameters);
+ }
+ virtual ~Wavechild670() {}
+
+ virtual void setParameters(Wavechild670Parameters& parameters){
+ inputLevelA = parameters.inputLevelA;
+ sidechainAmplifierA.setThresholds(parameters.ACThresholdA, parameters.DCThresholdA);
+
+ inputLevelB = parameters.inputLevelB;
+ sidechainAmplifierB.setThresholds(parameters.ACThresholdB, parameters.DCThresholdB);
+
+ select670TimeConstants(parameters.timeConstantSelectA, parameters.timeConstantSelectB);
+
+ sidechainLink = parameters.sidechainLink;
+ isMidSide = parameters.isMidSide;
+ useFeedbackTopology = parameters.useFeedbackTopology;
+ outputGain = parameters.outputGain;
+ hardClipOutput = parameters.hardClipOutput;
+ }
+
+ virtual void warmUp(Real warmUpTimeInSeconds=0.5){
+ ulong numSamples = (ulong) warmUpTimeInSeconds*sampleRate;
+ for (ulong i = 0; i < numSamples/2; i += 1) {
+ Real VoutA = signalAmplifierA.advanceAndGetOutputVoltage(0.0, VlevelCapA);
+ Real VoutB = signalAmplifierB.advanceAndGetOutputVoltage(0.0, VlevelCapB);
+ }
+ for (ulong i = 0; i < numSamples/2; i += 1) {
+ Real VoutA = signalAmplifierA.advanceAndGetOutputVoltage(0.0, VlevelCapA);
+ Real VoutB = signalAmplifierB.advanceAndGetOutputVoltage(0.0, VlevelCapB);
+ advanceSidechain(VoutA, VoutB); //Feedback topology with implicit unit delay between the sidechain input and the output,
+ }
+ }
+
+ //virtual void process(Real *VinputLeft, Real *VinputRight, Real *VoutLeft, Real *VoutRight, ulong numSamples) {
+ virtual void process(const float **VinputInterleaved, float **VoutInterleaved, ulong numSamples) {
+ Assert(VinputInterleaved);
+ Assert(VoutInterleaved);
+ static uint numChannels = 2;
+
+ for (ulong i = 0; i < numSamples; i += numChannels) {
+ Real VinputA;
+ Real VinputB;
+ if (isMidSide) {
+ VinputA = (double)((VinputInterleaved[0][i]) + (VinputInterleaved[0][i]))/sqrt(2.0);
+ VinputB = (double)((VinputInterleaved[1][i]) - (VinputInterleaved[1][i]))/sqrt(2.0);
+ }
+ else {
+ VinputA = (double)(VinputInterleaved[0][i]);
+ VinputB = (double)(VinputInterleaved[1][i]);
+ }
+ VinputA *= inputLevelA;
+ VinputB *= inputLevelB;
+
+
+ if (!useFeedbackTopology) { // => Feedforward
+ advanceSidechain(VinputA, VinputB); //Feedforward topology
+ }
+ Real VoutA = signalAmplifierA.advanceAndGetOutputVoltage(VinputA, VlevelCapA);
+ Real VoutB = signalAmplifierB.advanceAndGetOutputVoltage(VinputB, VlevelCapB);
+ if (useFeedbackTopology) {
+ advanceSidechain(VoutA, VoutB); //Feedback topology with implicit unit delay between the sidechain input and the output,
+ //and probably an implicit unit delay between the sidechain capacitor voltage input and the capacitor voltage
+ //(at least they're not the proper WDF coupling between the two)
+ }
+
+
+ Real VoutLeft;
+ Real VoutRight;
+
+ if (isMidSide) {
+ VoutLeft = (VoutA + VoutB)/sqrt(2.0);
+ VoutRight = (VoutA - VoutB)/sqrt(2.0);
+ }
+ else {
+ VoutLeft = VoutA;
+ VoutRight = VoutB;
+ }
+ VoutLeft = VoutLeft * outputGain;
+ VoutRight = VoutRight * outputGain;
+
+ VoutInterleaved[0][i] = (float)VoutLeft;
+ VoutInterleaved[1][i] = (float)VoutRight;
+ }
+ }
+
+protected:
+ virtual void select670TimeConstants(uint tcA, uint tcB){
+ Assert(tcA >= 1);
+ Assert(tcA <= 6);
+ tcA -= 1;
+ levelTimeConstantCircuitA.updateRValues(levelTimeConstantCircuitComponentValues[tcA][0], levelTimeConstantCircuitComponentValues[tcA][1], levelTimeConstantCircuitComponentValues[tcA][2], levelTimeConstantCircuitComponentValues[tcA][3], levelTimeConstantCircuitComponentValues[tcA][4], levelTimeConstantCircuitComponentValues[tcA][5], sampleRate);
+ Assert(tcB >= 1);
+ Assert(tcB <= 6);
+ tcB -= 1;
+ levelTimeConstantCircuitA.updateRValues(levelTimeConstantCircuitComponentValues[tcB][0], levelTimeConstantCircuitComponentValues[tcB][1], levelTimeConstantCircuitComponentValues[tcB][2], levelTimeConstantCircuitComponentValues[tcB][3], levelTimeConstantCircuitComponentValues[tcB][4], levelTimeConstantCircuitComponentValues[tcB][5], sampleRate);
+ }
+
+ virtual void advanceSidechain(Real VinSidechainA, Real VinSidechainB) {
+
+ Real sidechainCurrentA = sidechainAmplifierA.advanceAndGetCurrent(VinSidechainA, VlevelCapA);
+ Real sidechainCurrentB = sidechainAmplifierB.advanceAndGetCurrent(VinSidechainB, VlevelCapB);
+ if (sidechainLink) {
+ Real sidechainCurrentTotal = (sidechainCurrentA + sidechainCurrentB)/2.0;// #Effectively compute the two circuits in parallel, crude but effective (I haven't prove this is exactly right)
+ Real VlevelCapAx = levelTimeConstantCircuitA.advance(sidechainCurrentTotal);
+ Real VlevelCapBx = levelTimeConstantCircuitB.advance(sidechainCurrentTotal); // #maintain the voltage in circuit B in case the user disengages the link
+ VlevelCapA = (VlevelCapAx + VlevelCapBx) / 2.0;
+ VlevelCapB = (VlevelCapAx + VlevelCapBx) / 2.0;
+ }
+ else {
+ VlevelCapA = levelTimeConstantCircuitA.advance(sidechainCurrentA);
+ VlevelCapB = levelTimeConstantCircuitB.advance(sidechainCurrentB);
+ }
+ }
+
+protected:
+ Real sampleRate;
+ Real outputGain;
+ bool hardClipOutput;
+
+ Real VlevelCapA;
+ Real VlevelCapB;
+
+ Real inputLevelA;
+ Real inputLevelB;
+
+ bool useFeedbackTopology;
+ bool isMidSide;
+ bool sidechainLink;
+ SidechainAmplifier sidechainAmplifierA;
+ SidechainAmplifier sidechainAmplifierB;
+ LevelTimeConstantCircuit levelTimeConstantCircuitA;
+ LevelTimeConstantCircuit levelTimeConstantCircuitB;
+ VariableMuAmplifier signalAmplifierA;
+ VariableMuAmplifier signalAmplifierB;
+
+ static const Real levelTimeConstantCircuitComponentValues[6][6];
+};
+
+#endif
diff --git a/plugins/ZamChild670/wdfcircuits.cpp b/plugins/ZamChild670/wdfcircuits.cpp
new file mode 100644
index 0000000..284785f
--- /dev/null
+++ b/plugins/ZamChild670/wdfcircuits.cpp
@@ -0,0 +1,25 @@
+/************************************************************************************
+*
+* Wavechild670 v0.1
+*
+* wdfcircuits.cpp
+*
+* By Peter Raffensperger 10 July 2012
+*
+* Reference:
+* Toward a Wave Digital Filter Model of the Fairchild 670 Limiter, Raffensperger, P. A., (2012).
+* Proc. of the 15th International Conference on Digital Audio Effects (DAFx-12),
+* York, UK, September 17-21, 2012.
+*
+* Note:
+* Fairchild (R) a registered trademark of Avid Technology, Inc., which is in no way associated or
+* affiliated with the author.
+*
+* License:
+* Wavechild670 is licensed under the GNU GPL v2 license. If you use this
+* software in an academic context, we would appreciate it if you referenced the original
+* paper.
+*
+************************************************************************************/
+
+#include "wdfcircuits.h"
diff --git a/plugins/ZamChild670/wdfcircuits.h b/plugins/ZamChild670/wdfcircuits.h
new file mode 100644
index 0000000..fda90ac
--- /dev/null
+++ b/plugins/ZamChild670/wdfcircuits.h
@@ -0,0 +1,633 @@
+/************************************************************************************
+*
+* Wavechild670 v0.1
+*
+* wdfcircuits.h
+*
+* By Peter Raffensperger 10 July 2012
+*
+* Reference:
+* Toward a Wave Digital Filter Model of the Fairchild 670 Limiter, Raffensperger, P. A., (2012).
+* Proc. of the 15th International Conference on Digital Audio Effects (DAFx-12),
+* York, UK, September 17-21, 2012.
+*
+* Note:
+* Fairchild (R) a registered trademark of Avid Technology, Inc., which is in no way associated or
+* affiliated with the author.
+*
+* License:
+* Wavechild670 is licensed under the GNU GPL v2 license. If you use this
+* software in an academic context, we would appreciate it if you referenced the original
+* paper.
+*
+************************************************************************************/
+
+
+
+//Autogenerated wave digital filter circuits
+//Peter Raffensperger
+#ifndef WDFCIRCUITS_H
+#define WDFCIRCUITS_H
+
+#include "glue.h"
+#include "generatedwdfutilities.h"
+
+// AUTOGENERATED Wave digital filter 2012-03-14 15:24:51.084121
+// Advanced Machine Audio Python WDF Generator
+// Peter Raffensperger, 2012
+class TubeStageCircuit {
+ /*Circuit schematic: (B = winding symbol)
+ VplateSource
+ |
+ Rplate Primary Secondary
+ | Np : Ns
+ --------Lp---Rp--------------B B------Rs----Ls------------------------
+ | | B B | | |
+ Rc Lm B TXFMR B Cw Routput Rsidechain
+ | | B B | | |
+ -----------------------------B B--------------------------------------
+ |
+ Vgate --Tube
+ |
+ -----------------
+ | |
+ Rcathode Ccathode
+ | |
+ VcathodeSource cathodeCapacitorConn
+ */
+public:
+ TubeStageCircuit(Real C_Ccathode, Real C_Cw, Real E_VcathodeBias, Real E_Vplate, Real L_Lm, Real L_Lp, Real L_Ls, Real NpOverNs, Real R_Rc, Real R_Routput, Real R_Rp, Real R_Rs, Real R_Rsidechain, Real R_VcathodeBias, Real R_Vplate, Real R_cathodeCapacitorConn, BidirectionalUnitDelayInterface* cathodeCapacitorConn_, Real sampleRate, WDFTubeInterface& tube_) : tube(tube_){
+ updateRValues(C_Ccathode, C_Cw, E_VcathodeBias, E_Vplate, L_Lm, L_Lp, L_Ls, NpOverNs, R_Rc, R_Routput, R_Rp, R_Rs, R_Rsidechain, R_VcathodeBias, R_Vplate, R_cathodeCapacitorConn, cathodeCapacitorConn_, sampleRate);
+ Ccathodea = 0.0;
+ Lpa = 0.0;
+ Lma = 0.0;
+ Lsa = 0.0;
+ Cwa = 0.0;
+ Vcathode = 0.0;
+ }
+
+ void updateRValues(Real C_Ccathode, Real C_Cw, Real E_VcathodeBias, Real E_Vplate, Real L_Lm, Real L_Lp, Real L_Ls, Real NpOverNs, Real R_Rc, Real R_Routput, Real R_Rp, Real R_Rs, Real R_Rsidechain, Real R_VcathodeBias, Real R_Vplate, Real R_cathodeCapacitorConn, BidirectionalUnitDelayInterface* cathodeCapacitorConn_, Real sampleRate){
+ Real VcathodeBiasR = R_VcathodeBias;
+ VcathodeBiasE = E_VcathodeBias;
+ Real CcathodeR = 1.0 / (2.0*C_Ccathode*sampleRate);
+ Real VplateR = R_Vplate;
+ VplateE = E_Vplate;
+ Real RoutputR = R_Routput;
+ Real RsidechainR = R_Rsidechain;
+ Real outputParallelConn_1R = RoutputR;
+ Real outputParallelConn_2R = RsidechainR;
+ Real outputParallelConn_3R = 1.0 /(1.0 / outputParallelConn_1R + 1.0 / outputParallelConn_2R);
+ outputParallelConn_3Gamma1 = 1.0 / outputParallelConn_1R/(1.0 / outputParallelConn_1R + 1.0 / outputParallelConn_2R);
+ Assert(outputParallelConn_3Gamma1 >= 0.0 && outputParallelConn_3Gamma1 <= 1.0);
+ Real LpR = 2.0*L_Lp*sampleRate;
+ Real RpR = R_Rp;
+ Real LmR = 2.0*L_Lm*sampleRate;
+ Real RcR = R_Rc;
+ Real LsR = 2.0*L_Ls*sampleRate;
+ Real RsR = R_Rs;
+ Real CwR = 1.0 / (2.0*C_Cw*sampleRate);
+ transformern = 1.0 / NpOverNs;
+ transformerOneOvern = NpOverNs;
+ Real secondaryOutputParallelConn_1R = outputParallelConn_3R;
+ Real secondaryOutputParallelConn_2R = CwR;
+ Real secondaryOutputParallelConn_3R = 1.0 /(1.0 / secondaryOutputParallelConn_1R + 1.0 / secondaryOutputParallelConn_2R);
+ secondaryOutputParallelConn_3Gamma1 = 1.0 / secondaryOutputParallelConn_1R/(1.0 / secondaryOutputParallelConn_1R + 1.0 / secondaryOutputParallelConn_2R);
+ Assert(secondaryOutputParallelConn_3Gamma1 >= 0.0 && secondaryOutputParallelConn_3Gamma1 <= 1.0);
+ Real secondarySeriesConn2_3R = (RsR + LsR);
+ secondarySeriesConn2_3Gamma1 = RsR/(RsR + LsR);
+ Assert(secondarySeriesConn2_3Gamma1 >= 0.0 && secondarySeriesConn2_3Gamma1 <= 1.0);
+ secondarySeriesConn1_3Gamma1 = secondaryOutputParallelConn_3R/(secondaryOutputParallelConn_3R + secondarySeriesConn2_3R);
+ Assert(secondarySeriesConn1_3Gamma1 >= 0.0 && secondarySeriesConn1_3Gamma1 <= 1.0);
+ Real transformerR = (secondaryOutputParallelConn_3R + secondarySeriesConn2_3R)/(transformern*transformern);
+ Real primaryParallelConn1_1R = transformerR;
+ Real primarySeriesConn2_3R = (LpR + RpR);
+ primarySeriesConn2_3Gamma1 = LpR/(LpR + RpR);
+ Assert(primarySeriesConn2_3Gamma1 >= 0.0 && primarySeriesConn2_3Gamma1 <= 1.0);
+ Real primaryParallelConn2_1R = LmR;
+ Real primaryParallelConn2_2R = RcR;
+ Real primaryParallelConn2_3R = 1.0 /(1.0 / primaryParallelConn2_1R + 1.0 / primaryParallelConn2_2R);
+ primaryParallelConn2_3Gamma1 = 1.0 / primaryParallelConn2_1R/(1.0 / primaryParallelConn2_1R + 1.0 / primaryParallelConn2_2R);
+ Assert(primaryParallelConn2_3Gamma1 >= 0.0 && primaryParallelConn2_3Gamma1 <= 1.0);
+ Real primaryParallelConn1_2R = primaryParallelConn2_3R;
+ Real primaryParallelConn1_3R = 1.0 /(1.0 / primaryParallelConn1_1R + 1.0 / primaryParallelConn1_2R);
+ primaryParallelConn1_3Gamma1 = 1.0 / primaryParallelConn1_1R/(1.0 / primaryParallelConn1_1R + 1.0 / primaryParallelConn1_2R);
+ Assert(primaryParallelConn1_3Gamma1 >= 0.0 && primaryParallelConn1_3Gamma1 <= 1.0);
+ Real primaryInputSeriesConn_3R = (primarySeriesConn2_3R + primaryParallelConn1_3R);
+ primaryInputSeriesConn_3Gamma1 = primarySeriesConn2_3R/(primarySeriesConn2_3R + primaryParallelConn1_3R);
+ Assert(primaryInputSeriesConn_3Gamma1 >= 0.0 && primaryInputSeriesConn_3Gamma1 <= 1.0);
+ Real cathodeCapacitorConnR = R_cathodeCapacitorConn;
+ Real cathodeCapSeriesConn_3R = (CcathodeR + cathodeCapacitorConnR);
+ cathodeCapSeriesConn_3Gamma1 = CcathodeR/(CcathodeR + cathodeCapacitorConnR);
+ Assert(cathodeCapSeriesConn_3Gamma1 >= 0.0 && cathodeCapSeriesConn_3Gamma1 <= 1.0);
+ Real cathodeParallelConn_1R = VcathodeBiasR;
+ Real cathodeParallelConn_2R = cathodeCapSeriesConn_3R;
+ Real cathodeParallelConn_3R = 1.0 /(1.0 / cathodeParallelConn_1R + 1.0 / cathodeParallelConn_2R);
+ cathodeParallelConn_3Gamma1 = 1.0 / cathodeParallelConn_1R/(1.0 / cathodeParallelConn_1R + 1.0 / cathodeParallelConn_2R);
+ Assert(cathodeParallelConn_3Gamma1 >= 0.0 && cathodeParallelConn_3Gamma1 <= 1.0);
+ Real tubeSeriesConn1_3R = (primaryInputSeriesConn_3R + VplateR);
+ tubeSeriesConn1_3Gamma1 = primaryInputSeriesConn_3R/(primaryInputSeriesConn_3R + VplateR);
+ Assert(tubeSeriesConn1_3Gamma1 >= 0.0 && tubeSeriesConn1_3Gamma1 <= 1.0);
+ Real tubeSeriesConn2_3R = (tubeSeriesConn1_3R + cathodeParallelConn_3R);
+ tubeSeriesConn2_3Gamma1 = tubeSeriesConn1_3R/(tubeSeriesConn1_3R + cathodeParallelConn_3R);
+ Assert(tubeSeriesConn2_3Gamma1 >= 0.0 && tubeSeriesConn2_3Gamma1 <= 1.0);
+ cathodeCapacitorConn = cathodeCapacitorConn_;
+ tubeR = tubeSeriesConn2_3R;
+ }
+
+ Real advance(Real vgate){
+ //Get Bs
+ //tubeSeriesConn2_3GetB
+ //tubeSeriesConn1_3GetB
+ //primaryInputSeriesConn_3GetB
+ //primarySeriesConn2_3GetB
+ Real Lpb = -Lpa;
+ //primarySeriesConn2_1SetA
+ //RpGetB
+ //primarySeriesConn2_2SetA
+ Real primarySeriesConn2_3b3 = -(Lpb);
+ //primaryInputSeriesConn_1SetA
+ //primaryParallelConn1_3GetB
+ //transformerGetB
+ //secondarySeriesConn1_3GetB
+ //secondaryOutputParallelConn_3GetB
+ //outputParallelConn_3GetB
+ //RoutputGetB
+ //outputParallelConn_1SetA
+ //RsidechainGetB
+ //outputParallelConn_2SetA
+ Real outputParallelConn_3b3 = -outputParallelConn_3Gamma1*(0.0);
+ //secondaryOutputParallelConn_1SetA
+ Real Cwb = Cwa;
+ //secondaryOutputParallelConn_2SetA
+ Real secondaryOutputParallelConn_3b3 = Cwb - secondaryOutputParallelConn_3Gamma1*(Cwb - outputParallelConn_3b3);
+ //secondarySeriesConn1_1SetA
+ //secondarySeriesConn2_3GetB
+ //RsGetB
+ //secondarySeriesConn2_1SetA
+ Real Lsb = -Lsa;
+ //secondarySeriesConn2_2SetA
+ Real secondarySeriesConn2_3b3 = -(Lsb);
+ //secondarySeriesConn1_2SetA
+ Real secondarySeriesConn1_3b3 = -(secondaryOutputParallelConn_3b3 + secondarySeriesConn2_3b3);
+ //primaryParallelConn1_1SetA
+ //primaryParallelConn2_3GetB
+ Real Lmb = -Lma;
+ //primaryParallelConn2_1SetA
+ //RcGetB
+ //primaryParallelConn2_2SetA
+ Real primaryParallelConn2_3b3 = -primaryParallelConn2_3Gamma1*(-Lmb);
+ //primaryParallelConn1_2SetA
+ Real primaryParallelConn1_3b3 = primaryParallelConn2_3b3 - primaryParallelConn1_3Gamma1*(primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern);
+ //primaryInputSeriesConn_2SetA
+ Real primaryInputSeriesConn_3b3 = -(primarySeriesConn2_3b3 + primaryParallelConn1_3b3);
+ //tubeSeriesConn1_1SetA
+ //VplateGetB
+ //tubeSeriesConn1_2SetA
+ Real tubeSeriesConn1_3b3 = -(primaryInputSeriesConn_3b3 + VplateE);
+ //tubeSeriesConn2_1SetA
+ //cathodeParallelConn_3GetB
+ //VcathodeBiasGetB
+ //cathodeParallelConn_1SetA
+ //cathodeCapSeriesConn_3GetB
+ Real Ccathodeb = Ccathodea;
+ //cathodeCapSeriesConn_1SetA
+ //cathodeCapacitorConnGetB
+ //cathodeCapSeriesConn_2SetA
+ Real cathodeCapSeriesConn_3b3 = -(Ccathodeb + cathodeCapacitorConn->getB());
+ //cathodeParallelConn_2SetA
+ Real cathodeParallelConn_3b3 = cathodeCapSeriesConn_3b3 - cathodeParallelConn_3Gamma1*(cathodeCapSeriesConn_3b3 - VcathodeBiasE);
+ //tubeSeriesConn2_2SetA
+ Real tubeSeriesConn2_3b3 = -(tubeSeriesConn1_3b3 + cathodeParallelConn_3b3);
+ //Call tube model
+ Real b = tube.getB(tubeSeriesConn2_3b3, tubeR, vgate, Vcathode);
+ //Set As
+ //tubeSeriesConn2_3SetA
+ Real tubeSeriesConn2_3b1 = tubeSeriesConn1_3b3 - tubeSeriesConn2_3Gamma1*(tubeSeriesConn1_3b3 + cathodeParallelConn_3b3 + b);
+ //tubeSeriesConn1_3SetA
+ Real tubeSeriesConn1_3b1 = primaryInputSeriesConn_3b3 - tubeSeriesConn1_3Gamma1*(primaryInputSeriesConn_3b3 + VplateE + tubeSeriesConn2_3b1);
+ //primaryInputSeriesConn_3SetA
+ Real primaryInputSeriesConn_3b1 = primarySeriesConn2_3b3 - primaryInputSeriesConn_3Gamma1*(primarySeriesConn2_3b3 + primaryParallelConn1_3b3 + tubeSeriesConn1_3b1);
+ //primarySeriesConn2_3SetA
+ Real primarySeriesConn2_3b1 = Lpb - primarySeriesConn2_3Gamma1*(Lpb + primaryInputSeriesConn_3b1);
+ Lpa = primarySeriesConn2_3b1;
+ //RpSetA
+ Real primaryInputSeriesConn_3b2 = -(primarySeriesConn2_3b3 + tubeSeriesConn1_3b1 - primaryInputSeriesConn_3Gamma1*(primarySeriesConn2_3b3 + primaryParallelConn1_3b3 + tubeSeriesConn1_3b1));
+ //primaryParallelConn1_3SetA
+ Real primaryParallelConn1_3b1 = primaryInputSeriesConn_3b2 + primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern - primaryParallelConn1_3Gamma1*(primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern);
+ //transformerSetA
+ //secondarySeriesConn1_3SetA
+ Real secondarySeriesConn1_3b1 = secondaryOutputParallelConn_3b3 - secondarySeriesConn1_3Gamma1*(secondaryOutputParallelConn_3b3 + secondarySeriesConn2_3b3 + primaryParallelConn1_3b1*transformern);
+ //secondaryOutputParallelConn_3SetA
+ //outputParallelConn_3SetA
+ //RoutputSetA
+ //RsidechainSetA
+ Real secondaryOutputParallelConn_3b2 = secondarySeriesConn1_3b1 - secondaryOutputParallelConn_3Gamma1*(Cwb - outputParallelConn_3b3);
+ Cwa = secondaryOutputParallelConn_3b2;
+ Real secondarySeriesConn1_3b2 = -(secondaryOutputParallelConn_3b3 + primaryParallelConn1_3b1*transformern - secondarySeriesConn1_3Gamma1*(secondaryOutputParallelConn_3b3 + secondarySeriesConn2_3b3 + primaryParallelConn1_3b1*transformern));
+ //secondarySeriesConn2_3SetA
+ //RsSetA
+ Real secondarySeriesConn2_3b2 = -(secondarySeriesConn1_3b2 - secondarySeriesConn2_3Gamma1*(Lsb + secondarySeriesConn1_3b2));
+ Lsa = secondarySeriesConn2_3b2;
+ Real primaryParallelConn1_3b2 = primaryInputSeriesConn_3b2 - primaryParallelConn1_3Gamma1*(primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern);
+ //primaryParallelConn2_3SetA
+ Real primaryParallelConn2_3b1 = primaryParallelConn1_3b2 - Lmb - primaryParallelConn2_3Gamma1*(-Lmb);
+ Lma = primaryParallelConn2_3b1;
+ //RcSetA
+ Real tubeSeriesConn2_3b2 = -(tubeSeriesConn1_3b3 + b - tubeSeriesConn2_3Gamma1*(tubeSeriesConn1_3b3 + cathodeParallelConn_3b3 + b));
+ //cathodeParallelConn_3SetA
+ Real cathodeParallelConn_3b2 = tubeSeriesConn2_3b2 - cathodeParallelConn_3Gamma1*(cathodeCapSeriesConn_3b3 - VcathodeBiasE);
+ //cathodeCapSeriesConn_3SetA
+ Real cathodeCapSeriesConn_3b1 = Ccathodeb - cathodeCapSeriesConn_3Gamma1*(Ccathodeb + cathodeCapacitorConn->getB() + cathodeParallelConn_3b2);
+ Ccathodea = cathodeCapSeriesConn_3b1;
+ Real cathodeCapSeriesConn_3b2 = -(Ccathodeb + cathodeParallelConn_3b2 - cathodeCapSeriesConn_3Gamma1*(Ccathodeb + cathodeCapacitorConn->getB() + cathodeParallelConn_3b2));
+ //cathodeCapacitorConnSetA
+ Real cathodeCapacitorConna = cathodeCapSeriesConn_3b2;
+ cathodeCapacitorConn->setA(cathodeCapacitorConna);
+ Vcathode = -(Ccathodea + Ccathodeb);
+ return -(Cwa + Cwb);
+ }
+
+ std::vector<Real> getState(){
+ std::vector<Real> state(6, 0.0);
+ state[0] = Ccathodea;
+ state[1] = Lpa;
+ state[2] = Lma;
+ state[3] = Lsa;
+ state[4] = Cwa;
+ state[5] = Vcathode;
+ return state;
+ }
+ void setState(std::vector<Real> state) {
+ Assert(state.size() == 6);
+ Ccathodea = state[0];
+ Lpa = state[1];
+ Lma = state[2];
+ Lsa = state[3];
+ Cwa = state[4];
+ Vcathode = state[5];
+ }
+private:
+ //State variables
+ Real Ccathodea;
+ Real Lpa;
+ Real Lma;
+ Real Lsa;
+ Real Cwa;
+ Real Vcathode;
+
+ //R values
+ Real outputParallelConn_3Gamma1;
+ BidirectionalUnitDelayInterface* cathodeCapacitorConn;
+ Real primarySeriesConn2_3Gamma1;
+ Real cathodeCapSeriesConn_3Gamma1;
+ Real tubeSeriesConn1_3Gamma1;
+ Real VplateE;
+ Real secondarySeriesConn2_3Gamma1;
+ Real primaryInputSeriesConn_3Gamma1;
+ Real secondaryOutputParallelConn_3Gamma1;
+ Real cathodeParallelConn_3Gamma1;
+ Real secondarySeriesConn1_3Gamma1;
+ Real transformerOneOvern;
+ Real transformern;
+ Real VcathodeBiasE;
+ Real tubeSeriesConn2_3Gamma1;
+ Real primaryParallelConn2_3Gamma1;
+ Real primaryParallelConn1_3Gamma1;
+ Real tubeR;
+ //Extra members
+ WDFTubeInterface tube;
+};
+
+
+
+// AUTOGENERATED Wave digital filter 2012-03-14 15:24:51.132756
+// Advanced Machine Audio Python WDF Generator
+// Peter Raffensperger, 2012
+class TransformerCoupledInputCircuit {
+ /*Circuit schematic:
+ Primary Secondary
+ Np : Ns
+ ----Rin-------Lp---Rp--------------B B------Rs----Ls------------
+ | | | | B B | |
+ Vin RinTerm Rc Lm B TXFMR B Cw Rload
+ | | | | B B | |
+ -----------------------------------B B--------------------------
+ B = winding symbol
+ */
+public:
+ TransformerCoupledInputCircuit(Real C_Cw, Real E_inputSource, Real L_Lm, Real L_Lp, Real L_Ls, Real NpOverNs, Real R_Rc, Real R_RinputTermination, Real R_Rload, Real R_Rp, Real R_Rs, Real R_inputSource, Real sampleRate){
+ updateRValues(C_Cw, E_inputSource, L_Lm, L_Lp, L_Ls, NpOverNs, R_Rc, R_RinputTermination, R_Rload, R_Rp, R_Rs, R_inputSource, sampleRate);
+ Lpa = 0.0;
+ Lma = 0.0;
+ Lsa = 0.0;
+ Cwa = 0.0;
+ }
+
+ void updateRValues(Real C_Cw, Real E_inputSource, Real L_Lm, Real L_Lp, Real L_Ls, Real NpOverNs, Real R_Rc, Real R_RinputTermination, Real R_Rload, Real R_Rp, Real R_Rs, Real R_inputSource, Real sampleRate){
+ Real RloadR = R_Rload;
+ Real inputSourceR = R_inputSource;
+ inputSourceE = E_inputSource;
+ Real RinputTerminationR = R_RinputTermination;
+ Real LpR = 2.0*L_Lp*sampleRate;
+ Real RpR = R_Rp;
+ Real LmR = 2.0*L_Lm*sampleRate;
+ Real RcR = R_Rc;
+ Real LsR = 2.0*L_Ls*sampleRate;
+ Real RsR = R_Rs;
+ Real CwR = 1.0 / (2.0*C_Cw*sampleRate);
+ transformern = 1.0 / NpOverNs;
+ transformerOneOvern = NpOverNs;
+ Real secondaryOutputParallelConn_1R = RloadR;
+ Real secondaryOutputParallelConn_2R = CwR;
+ Real secondaryOutputParallelConn_3R = 1.0 /(1.0 / secondaryOutputParallelConn_1R + 1.0 / secondaryOutputParallelConn_2R);
+ secondaryOutputParallelConn_3Gamma1 = 1.0 / secondaryOutputParallelConn_1R/(1.0 / secondaryOutputParallelConn_1R + 1.0 / secondaryOutputParallelConn_2R);
+ Assert(secondaryOutputParallelConn_3Gamma1 >= 0.0 && secondaryOutputParallelConn_3Gamma1 <= 1.0);
+ Real secondarySeriesConn2_3R = (RsR + LsR);
+ secondarySeriesConn2_3Gamma1 = RsR/(RsR + LsR);
+ Assert(secondarySeriesConn2_3Gamma1 >= 0.0 && secondarySeriesConn2_3Gamma1 <= 1.0);
+ secondarySeriesConn1_3Gamma1 = secondaryOutputParallelConn_3R/(secondaryOutputParallelConn_3R + secondarySeriesConn2_3R);
+ Assert(secondarySeriesConn1_3Gamma1 >= 0.0 && secondarySeriesConn1_3Gamma1 <= 1.0);
+ Real transformerR = (secondaryOutputParallelConn_3R + secondarySeriesConn2_3R)/(transformern*transformern);
+ Real primaryParallelConn1_1R = transformerR;
+ Real primarySeriesConn2_3R = (LpR + RpR);
+ primarySeriesConn2_3Gamma1 = LpR/(LpR + RpR);
+ Assert(primarySeriesConn2_3Gamma1 >= 0.0 && primarySeriesConn2_3Gamma1 <= 1.0);
+ Real primaryParallelConn2_1R = LmR;
+ Real primaryParallelConn2_2R = RcR;
+ Real primaryParallelConn2_3R = 1.0 /(1.0 / primaryParallelConn2_1R + 1.0 / primaryParallelConn2_2R);
+ primaryParallelConn2_3Gamma1 = 1.0 / primaryParallelConn2_1R/(1.0 / primaryParallelConn2_1R + 1.0 / primaryParallelConn2_2R);
+ Assert(primaryParallelConn2_3Gamma1 >= 0.0 && primaryParallelConn2_3Gamma1 <= 1.0);
+ Real primaryParallelConn1_2R = primaryParallelConn2_3R;
+ Real primaryParallelConn1_3R = 1.0 /(1.0 / primaryParallelConn1_1R + 1.0 / primaryParallelConn1_2R);
+ primaryParallelConn1_3Gamma1 = 1.0 / primaryParallelConn1_1R/(1.0 / primaryParallelConn1_1R + 1.0 / primaryParallelConn1_2R);
+ Assert(primaryParallelConn1_3Gamma1 >= 0.0 && primaryParallelConn1_3Gamma1 <= 1.0);
+ Real primaryInputSeriesConn_3R = (primarySeriesConn2_3R + primaryParallelConn1_3R);
+ primaryInputSeriesConn_3Gamma1 = primarySeriesConn2_3R/(primarySeriesConn2_3R + primaryParallelConn1_3R);
+ Assert(primaryInputSeriesConn_3Gamma1 >= 0.0 && primaryInputSeriesConn_3Gamma1 <= 1.0);
+ Real parallelConn_3R = (primaryInputSeriesConn_3R + RinputTerminationR);
+ parallelConn_3Gamma1 = primaryInputSeriesConn_3R/(primaryInputSeriesConn_3R + RinputTerminationR);
+ Assert(parallelConn_3Gamma1 >= 0.0 && parallelConn_3Gamma1 <= 1.0);
+ seriesConn_3Gamma1 = parallelConn_3R/(parallelConn_3R + inputSourceR);
+ Assert(seriesConn_3Gamma1 >= 0.0 && seriesConn_3Gamma1 <= 1.0);
+ }
+
+ Real advance(Real vin){
+ inputSourceE = vin;
+ //Get Bs
+ //seriesConn_3GetB
+ //parallelConn_3GetB
+ //primaryInputSeriesConn_3GetB
+ //primarySeriesConn2_3GetB
+ Real Lpb = -Lpa;
+ //primarySeriesConn2_1SetA
+ //RpGetB
+ //primarySeriesConn2_2SetA
+ Real primarySeriesConn2_3b3 = -(Lpb);
+ //primaryInputSeriesConn_1SetA
+ //primaryParallelConn1_3GetB
+ //transformerGetB
+ //secondarySeriesConn1_3GetB
+ //secondaryOutputParallelConn_3GetB
+ //RloadGetB
+ //secondaryOutputParallelConn_1SetA
+ Real Cwb = Cwa;
+ //secondaryOutputParallelConn_2SetA
+ Real secondaryOutputParallelConn_3b3 = Cwb - secondaryOutputParallelConn_3Gamma1*(Cwb);
+ //secondarySeriesConn1_1SetA
+ //secondarySeriesConn2_3GetB
+ //RsGetB
+ //secondarySeriesConn2_1SetA
+ Real Lsb = -Lsa;
+ //secondarySeriesConn2_2SetA
+ Real secondarySeriesConn2_3b3 = -(Lsb);
+ //secondarySeriesConn1_2SetA
+ Real secondarySeriesConn1_3b3 = -(secondaryOutputParallelConn_3b3 + secondarySeriesConn2_3b3);
+ //primaryParallelConn1_1SetA
+ //primaryParallelConn2_3GetB
+ Real Lmb = -Lma;
+ //primaryParallelConn2_1SetA
+ //RcGetB
+ //primaryParallelConn2_2SetA
+ Real primaryParallelConn2_3b3 = -primaryParallelConn2_3Gamma1*(-Lmb);
+ //primaryParallelConn1_2SetA
+ Real primaryParallelConn1_3b3 = primaryParallelConn2_3b3 - primaryParallelConn1_3Gamma1*(primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern);
+ //primaryInputSeriesConn_2SetA
+ Real primaryInputSeriesConn_3b3 = -(primarySeriesConn2_3b3 + primaryParallelConn1_3b3);
+ //parallelConn_1SetA
+ //RinputTerminationGetB
+ //parallelConn_2SetA
+ Real parallelConn_3b3 = -(primaryInputSeriesConn_3b3);
+ //seriesConn_1SetA
+ //inputSourceGetB
+ //seriesConn_2SetA
+ Real seriesConn_3b3 = -(parallelConn_3b3 + inputSourceE);
+ Real b = -(seriesConn_3b3);
+ //Set As
+ //seriesConn_3SetA
+ Real seriesConn_3b1 = parallelConn_3b3 - seriesConn_3Gamma1*(parallelConn_3b3 + inputSourceE + b);
+ //parallelConn_3SetA
+ Real parallelConn_3b1 = primaryInputSeriesConn_3b3 - parallelConn_3Gamma1*(primaryInputSeriesConn_3b3 + seriesConn_3b1);
+ //primaryInputSeriesConn_3SetA
+ Real primaryInputSeriesConn_3b1 = primarySeriesConn2_3b3 - primaryInputSeriesConn_3Gamma1*(primarySeriesConn2_3b3 + primaryParallelConn1_3b3 + parallelConn_3b1);
+ //primarySeriesConn2_3SetA
+ Real primarySeriesConn2_3b1 = Lpb - primarySeriesConn2_3Gamma1*(Lpb + primaryInputSeriesConn_3b1);
+ Lpa = primarySeriesConn2_3b1;
+ //RpSetA
+ Real primaryInputSeriesConn_3b2 = -(primarySeriesConn2_3b3 + parallelConn_3b1 - primaryInputSeriesConn_3Gamma1*(primarySeriesConn2_3b3 + primaryParallelConn1_3b3 + parallelConn_3b1));
+ //primaryParallelConn1_3SetA
+ Real primaryParallelConn1_3b1 = primaryInputSeriesConn_3b2 + primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern - primaryParallelConn1_3Gamma1*(primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern);
+ //transformerSetA
+ //secondarySeriesConn1_3SetA
+ Real secondarySeriesConn1_3b1 = secondaryOutputParallelConn_3b3 - secondarySeriesConn1_3Gamma1*(secondaryOutputParallelConn_3b3 + secondarySeriesConn2_3b3 + primaryParallelConn1_3b1*transformern);
+ //secondaryOutputParallelConn_3SetA
+ //RloadSetA
+ Real secondaryOutputParallelConn_3b2 = secondarySeriesConn1_3b1 - secondaryOutputParallelConn_3Gamma1*(Cwb);
+ Cwa = secondaryOutputParallelConn_3b2;
+ Real secondarySeriesConn1_3b2 = -(secondaryOutputParallelConn_3b3 + primaryParallelConn1_3b1*transformern - secondarySeriesConn1_3Gamma1*(secondaryOutputParallelConn_3b3 + secondarySeriesConn2_3b3 + primaryParallelConn1_3b1*transformern));
+ //secondarySeriesConn2_3SetA
+ //RsSetA
+ Real secondarySeriesConn2_3b2 = -(secondarySeriesConn1_3b2 - secondarySeriesConn2_3Gamma1*(Lsb + secondarySeriesConn1_3b2));
+ Lsa = secondarySeriesConn2_3b2;
+ Real primaryParallelConn1_3b2 = primaryInputSeriesConn_3b2 - primaryParallelConn1_3Gamma1*(primaryParallelConn2_3b3 - secondarySeriesConn1_3b3*transformerOneOvern);
+ //primaryParallelConn2_3SetA
+ Real primaryParallelConn2_3b1 = primaryParallelConn1_3b2 - Lmb - primaryParallelConn2_3Gamma1*(-Lmb);
+ Lma = primaryParallelConn2_3b1;
+ //RcSetA
+ //RinputTerminationSetA
+ return -(Cwa + Cwb);
+ }
+
+ std::vector<Real> getState(){
+ std::vector<Real> state(4, 0.0);
+ state[0] = Lpa;
+ state[1] = Lma;
+ state[2] = Lsa;
+ state[3] = Cwa;
+ return state;
+ }
+ void setState(std::vector<Real> state) {
+ Assert(state.size() == 4);
+ Lpa = state[0];
+ Lma = state[1];
+ Lsa = state[2];
+ Cwa = state[3];
+ }
+private:
+ //State variables
+ Real Lpa;
+ Real Lma;
+ Real Lsa;
+ Real Cwa;
+
+ //R values
+ Real primarySeriesConn2_3Gamma1;
+ Real seriesConn_3Gamma1;
+ Real secondarySeriesConn2_3Gamma1;
+ Real primaryInputSeriesConn_3Gamma1;
+ Real parallelConn_3Gamma1;
+ Real secondaryOutputParallelConn_3Gamma1;
+ Real secondarySeriesConn1_3Gamma1;
+ Real transformerOneOvern;
+ Real inputSourceE;
+ Real transformern;
+ Real primaryParallelConn2_3Gamma1;
+ Real primaryParallelConn1_3Gamma1;
+ //Extra members
+};
+
+
+
+// AUTOGENERATED Wave digital filter 2012-03-14 15:24:51.156199
+// Advanced Machine Audio Python WDF Generator
+// Peter Raffensperger, 2012
+class LevelTimeConstantCircuit {
+ /*Circuit schematic:
+ --------------------------
+ | | | | |
+ | | | R2 R3
+ Iin R1 C1 | |
+ | | | C2 C3
+ | | | | |
+ --------------------------
+ */
+public:
+ LevelTimeConstantCircuit(Real C_C1, Real C_C2, Real C_C3, Real R_R1, Real R_R2, Real R_R3, Real sampleRate){
+ updateRValues(C_C1, C_C2, C_C3, R_R1, R_R2, R_R3, sampleRate);
+ C1a = 0.0;
+ C2a = 0.0;
+ C3a = 0.0;
+ }
+
+ void updateRValues(Real C_C1, Real C_C2, Real C_C3, Real R_R1, Real R_R2, Real R_R3, Real sampleRate){
+ Real R1R = R_R1;
+ Real C1R = 1.0 / (2.0*C_C1*sampleRate);
+ Real R2R = R_R2;
+ Real C2R = 1.0 / (2.0*C_C2*sampleRate);
+ Real R3R = R_R3;
+ Real C3R = 1.0 / (2.0*C_C3*sampleRate);
+ Real serialConn2_3R = (R2R + C2R);
+ serialConn2_3Gamma1 = R2R/(R2R + C2R);
+ Assert(serialConn2_3Gamma1 >= 0.0 && serialConn2_3Gamma1 <= 1.0);
+ Real serialConn3_3R = (R3R + C3R);
+ serialConn3_3Gamma1 = R3R/(R3R + C3R);
+ Assert(serialConn3_3Gamma1 >= 0.0 && serialConn3_3Gamma1 <= 1.0);
+ Real parallelConn23_1R = serialConn2_3R;
+ Real parallelConn23_2R = serialConn3_3R;
+ Real parallelConn23_3R = 1.0 /(1.0 / parallelConn23_1R + 1.0 / parallelConn23_2R);
+ parallelConn23_3Gamma1 = 1.0 / parallelConn23_1R/(1.0 / parallelConn23_1R + 1.0 / parallelConn23_2R);
+ Assert(parallelConn23_3Gamma1 >= 0.0 && parallelConn23_3Gamma1 <= 1.0);
+ Real parallelConn1_1R = R1R;
+ Real parallelConn1_2R = C1R;
+ Real parallelConn1_3R = 1.0 /(1.0 / parallelConn1_1R + 1.0 / parallelConn1_2R);
+ parallelConn1_3Gamma1 = 1.0 / parallelConn1_1R/(1.0 / parallelConn1_1R + 1.0 / parallelConn1_2R);
+ Assert(parallelConn1_3Gamma1 >= 0.0 && parallelConn1_3Gamma1 <= 1.0);
+ Real parallelConnInput_1R = parallelConn1_3R;
+ Real parallelConnInput_2R = parallelConn23_3R;
+ Real parallelConnInput_3R = 1.0 /(1.0 / parallelConnInput_1R + 1.0 / parallelConnInput_2R);
+ parallelConnInput_3Gamma1 = 1.0 / parallelConnInput_1R/(1.0 / parallelConnInput_1R + 1.0 / parallelConnInput_2R);
+ Assert(parallelConnInput_3Gamma1 >= 0.0 && parallelConnInput_3Gamma1 <= 1.0);
+ Rsource = parallelConnInput_3R;
+ }
+
+ Real advance(Real Iin){
+ //parallelConnInput_3GetB
+ //parallelConn1_3GetB
+ //R1GetB
+ //parallelConn1_1SetA
+ Real C1b = C1a;
+ //parallelConn1_2SetA
+ Real parallelConn1_3b3 = C1b - parallelConn1_3Gamma1*(C1b);
+ //parallelConnInput_1SetA
+ //parallelConn23_3GetB
+ //serialConn2_3GetB
+ //R2GetB
+ //serialConn2_1SetA
+ Real C2b = C2a;
+ //serialConn2_2SetA
+ Real serialConn2_3b3 = -(C2b);
+ //parallelConn23_1SetA
+ //serialConn3_3GetB
+ //R3GetB
+ //serialConn3_1SetA
+ Real C3b = C3a;
+ //serialConn3_2SetA
+ Real serialConn3_3b3 = -(C3b);
+ //parallelConn23_2SetA
+ Real parallelConn23_3b3 = serialConn3_3b3 - parallelConn23_3Gamma1*(serialConn3_3b3 - serialConn2_3b3);
+ //parallelConnInput_2SetA
+ Real parallelConnInput_3b3 = parallelConn23_3b3 - parallelConnInput_3Gamma1*(parallelConn23_3b3 - parallelConn1_3b3);
+ //Current source law
+ Real e = Iin * Rsource;
+ Real b = (parallelConnInput_3b3) - 2.0*e;
+ //parallelConnInput_3SetA
+ Real parallelConnInput_3b1 = b + parallelConn23_3b3 - parallelConn1_3b3 - parallelConnInput_3Gamma1*(parallelConn23_3b3 - parallelConn1_3b3);
+ //parallelConn1_3SetA
+ //R1SetA
+ Real parallelConn1_3b2 = parallelConnInput_3b1 - parallelConn1_3Gamma1*(C1b);
+ C1a = parallelConn1_3b2;
+ Real parallelConnInput_3b2 = b - parallelConnInput_3Gamma1*(parallelConn23_3b3 - parallelConn1_3b3);
+ //parallelConn23_3SetA
+ Real parallelConn23_3b1 = parallelConnInput_3b2 + serialConn3_3b3 - serialConn2_3b3 - parallelConn23_3Gamma1*(serialConn3_3b3 - serialConn2_3b3);
+ //serialConn2_3SetA
+ //R2SetA
+ Real serialConn2_3b2 = -(parallelConn23_3b1 - serialConn2_3Gamma1*(C2b + parallelConn23_3b1));
+ C2a = serialConn2_3b2;
+ Real parallelConn23_3b2 = parallelConnInput_3b2 - parallelConn23_3Gamma1*(serialConn3_3b3 - serialConn2_3b3);
+ //serialConn3_3SetA
+ //R3SetA
+ Real serialConn3_3b2 = -(parallelConn23_3b2 - serialConn3_3Gamma1*(C3b + parallelConn23_3b2));
+ C3a = serialConn3_3b2;
+ return -(C1a + C1b);
+ }
+
+ std::vector<Real> getState(){
+ std::vector<Real> state(3, 0.0);
+ state[0] = C1a;
+ state[1] = C2a;
+ state[2] = C3a;
+ return state;
+ }
+ void setState(std::vector<Real> state) {
+ Assert(state.size() == 3);
+ C1a = state[0];
+ C2a = state[1];
+ C3a = state[2];
+ }
+private:
+ //State variables
+ Real C1a;
+ Real C2a;
+ Real C3a;
+
+ //R values
+ Real serialConn2_3Gamma1;
+ Real Rsource;
+ Real parallelConn1_3Gamma1;
+ Real serialConn3_3Gamma1;
+ Real parallelConnInput_3Gamma1;
+ Real parallelConn23_3Gamma1;
+ //Extra members
+};
+
+#endif
+