Aiden Benton | April 21, 2024
Volkstrautonium
RCA Mk II
Synthesizer IC
The First of Its Kind
> wave -waveform sine -frequency 440Hz | spect
(definstrument simp (start-time duration frequency amplitude)
(let* ((beg (floor (* start-time *srate*)))
(end (+ beg (floor (* duration *srate*))))
(j 0))
(run
(loop for i from beg below end do
(outa i (* amplitude (sin (* j 2.0 pi (/ frequency *srate*)))))
(incf j)))))
Wavefonix Boolean Logic
#include "SC_PlugIn.hpp"
#include "BooleanLogic.hpp"
static InterfaceTable\* ft;
namespace ModeledModules {
BooleanLogic::BooleanLogic() {
mCalcFunc = make_calc_function<BooleanLogic, &BooleanLogic::next>();
next(1);
mSelectedOperation = in0(Operation);
}
void BooleanLogic::next(int nSamples) {
// Inputs
float input1 = in0(Input1);
float input2 = in0(Input2);
switch (mSelectedOperation) {
case AND:
if(std::abs(input1) > 0 && std::abs(input2) > 0) {
out0(0) = 1.0;
} else {
out0(0) = 0.0;
}
break;
case OR:
if(std::abs(input1) > 0 || std::abs(input2) > 0) {
out0(0) = 1.0;
} else {
out0(0) = 0.0;
}
break;
case XOR:
if((std::abs(input1) > 0 && std::abs(input2) == 0) || (std::abs(input1) == 0 && std::abs(input2) > 0)) {
out0(0) = 1.0;
} else {
out0(0) = 0.0;
}
break;
case NAND:
if(std::abs(input1) > 0 && std::abs(input2) > 0) {
out0(0) = 0.0;
} else {
out0(0) = 1.0;
}
break;
case NOR:
if(std::abs(input1) > 0 || std::abs(input2) > 0) {
out0(0) = 0.0;
} else {
out0(0) = 1.0;
}
break;
case XNOR:
if((std::abs(input1) > 0 && std::abs(input2) > 0) || (std::abs(input1) == 0 && std::abs(input2) == 0)) {
out0(0) = 1.0;
} else {
out0(0) = 0.0;
}
break;
default:
out0(0) = 0.0;
break;
}
}
}
BooleanLogic : UGen {
// aliases for UGen boolean operations
const <and = 0;
const <or = 1;
const <xor = 2;
const <nand = 3;
const <nor = 4;
const <xnor = 5;
*kr { |input1, input2, operation=0|
^this.multiNew('control', input1, input2, operation);
}
checkInputs {
^this.checkValidInputs;
}
}
Mutable Instruments Ripples
void Ripples::next(int nSamples) {
const float *input = in(INPUT);
float* outbuf0 = out(0);
float* outbuf1 = out(1);
float* outbuf2 = out(2);
float width = in0(BP_RQ) * in0(BP_CF);
if(in0(LP2_CF) != 0){
LPF2.setup(sampleRate(), in0(LP2_CF), in0(LP2_R));
}
if(in0(LP4_CF) != 0){
LPF4.setup(sampleRate(), in0(LP4_CF), in0(LP4_R));
}
BPF.setup(sampleRate(), in0(BP_CF), width, in0(BP_R));
for(int i = 0; i < nSamples; ++i){
outbuf0[i] = zapgremlins(BPF.filter(input[i]));
outbuf1[i] = zapgremlins(LPF2.filter(input[i]));
outbuf2[i] = zapgremlins(LPF4.filter(input[i]));
}
}
// PluginRipples.hpp
// Aiden Benton (dev@aiden-benton.com)
#pragma once
#include "SC_PlugIn.hpp"
#include "../../external/iir1/Iir.h"
namespace ModeledModules {
class Ripples : public SCUnit {
public:
Ripples();
private:
void next(int nSamples);
Iir::ChebyshevI::LowPass<2> LPF2;
Iir::ChebyshevI::LowPass<4> LPF4;
Iir::ChebyshevI::BandPass<4> BPF;
enum inputs {INPUT, BP_CF, BP_R, BP_RQ, LP2_CF, LP2_R, LP4_CF, LP4_R};
};
} // namespace ModeledModules
Ripples : MultiOutUGen {
*ar { arg in, bpCF = 440.0, bpR = 0.5, bpRQ = 1, lp2CF= 0.0, lp2R=0.0, lp4CF=0.0, lp4R=0.0, mul=1.0, add=0.0;
^this.multiNew('audio', in, bpCF, bpR, bpRQ, lp2CF, lp2R, lp4CF, lp4R, fmFreq, fmMul, fmIndex).madd(mul, add);
}
*kr { arg in, bpCF = 440.0, bpR = 0.5, bpRQ = 1, lp2CF= 0.0, lp2R=0.0, lp4CF=0.0, lp4R=0.0, mul=1.0, add=0.0;
^this.multiNew('control', in, bpCF, bpR, bpRQ, lp2CF, lp2R, lp4CF, lp4R, fmFreq, fmMul, fmIndex).madd(mul, add);
}
init { arg ... theInputs;
inputs = theInputs;
channels = [
OutputProxy(rate, this, 0),
OutputProxy(rate, this, 1),
OutputProxy(rate, this, 2),
];
^channels
}
checkInputs {
^this.checkValidInputs;
}
}
Erica Synths DIY Delay
Constructor
DIYDelay::DIYDelay(){
mCalcFunc = make_calc_function<DIYDelay, &DIYDelay::next>();
m_maxDelay = in0(MAX_DELAY);
m_bufSize = NEXTPOWEROFTWO(sampleRate() * m_maxDelay);
m_mask = m_bufSize - 1;
m_buf = (float *)RTAlloc(mWorld, m_bufSize * sizeof(float));
if (m_buf == nullptr)
{
ClearUnitOutputs(this, 1);
if (mWorld->mVerbosity > -2)
{
Print("DIYDelay: failed to allocate memory for buffer\n");
}
return;
}
memset(m_buf, 0, m_bufSize * sizeof(float));
next(1);
}
next() Function
void DIYDelay::next(int nSamples){
// Inputs from SC
const float *input = in(INPUT);
float *outbuf = out(0);
float delay = in0(DELAY_TIME);
float fb = in0(FEEDBACK);
auto hold = static_cast<bool>(in0(HOLD));
auto reverse = static_cast<bool>(in0(REVERSE));
auto tape = static_cast<bool>(in0(TAPE));
// local stateless variables
float const *buf = m_buf;
int mask = m_mask;
int write = m_readIndex;
int read = (m_reverseIndex == 0) ? m_bufSize - 1 : m_reverseIndex;
if (delay > m_maxDelay)
{
delay = m_maxDelay;
}
// initialize delay time
float delay_samples = sampleRate() * delay;
auto offset = static_cast<int>(delay_samples);
float frac = delay_samples - (float)offset;
for (int i = 0; i < nSamples; ++i)
{
int phase1 = reverse ? read - offset : write - offset;
int phase2 = phase1 - 1;
int phase3 = phase1 - 2;
int phase0 = phase1 + 1;
float d0 = buf[phase0 & mask];
float d1 = buf[phase1 & mask];
float d2 = buf[phase2 & mask];
float d3 = buf[phase3 & mask];
float delayed = cubicinterp(frac, d0, d1, d2, d3);
float outSample = zapgremlins(input[i] + (fb * delayed));
if (tape)
{
outSample = saturation(outSample);
}
outbuf[i] = outSample;
if (!hold)
{
m_buf[write] = outSample;
}
write = (write + 1) & mask;
read = (read - 1) & mask;
}
m_readIndex = write;
m_reverseIndex = read;
}