Aiden Benton | April 21, 2024 |
1) History {.fragment .fade-right} 2) Project Overview {.fragment .fade-right}
–
note: uses electricity and electrical components as an analog to sound waves; microphone example
note: Martenot similar to theremin, Johnny Greenwood of radiohead modern martenot enthusiast; orgue des ondes had 700 vacuum tubes
–
note: had a metal string; really expensive commercial version called the volkstrautonium made by Telefunken; oskar sala continued its development until his death
–
note: first instrument to be called a synthesizer; RCA wanted to generate pop music and instrument sounds; score made of typed binary; used a long hole punched paper roll; Milton Babbitt composed for it; currently sitting in ruins :(
–
note: prototype called “The Abominatron”; 1964 for Herb Deutsch; modular system allowed for an incomprehensible number of combinations; studio and portable versions; synthesizer 1 offered basic needs
–
note: Synthesizer 2 for more complex applications in studios and universities
–
note: the synthesizer 3 was the first fully realized synthesizer
note: 1970, monophonic, more user friendly, cheaper, the archetype
note: released in 1977, hit stores in 78; analog sounds with the perks of digital memory for custom presets and keyboard scanning allowing for reactive keys; going into the 80’s digital synthesizers and samplers replace their purely analog counterparts like the Roland TR-808 drum and TB-303 bass synths
note: Invented by Konrad Zuse with his Z2 in 1939; electromechanical were the earliest form of digital computer which often took the form of numerical calculators and code breaking machines. Turing’s Bombe ENIGMA breaker is a famous example.
note: no mechanical = faster; ENIAC used panel to panel wiring and switching revealed to the public in 1946. First program in history to run on a digital, electronic, stored-program computer June 21st 1948
–
{.fragment .fade-up}
note: LEO first computer to have an office job solving the problem of production scheduling and delivery of cakes; Grace Hopper invents the compiler
note: transistors smaller, less power less heat, more reliable; Manchester TC first prototype to use the transistor; known a the Defense Calculator first computer to play checkers IBMs entry into computer market; the IBM 704 designed to solve complex problems in large scale settings first super-computer
–
note: 1955 max mathews hired at bell labs
The First of Its Kind
note: music i programmed for the ibm 704 in machine code so only worked on the computer model for which it was designed and was quote “terrible” in his own words a single triangle wave with pitch loudness and duration. 7 seconds silver. 2 added four voices and arbitrary waveforms and the concept of the wavetable oscillator
–
note: UGens super important concept; building blocks for generating audio signals and support a number of control inputs to change parameters. connection of ugens is an instrument and orchestra a collection of ugens; important concept
–
note: music 4 given to chowning who hooked up the music N computer to the same storage as a DAC computer fortran made MUSIC-V accessible to every computer that could compile FORTRAN code
> wave -waveform sine -frequency 440Hz | spect
{.fragment .fade-zoom}
note: with the advent of microprocessors, workstations with terminals, and operating systems, music programming advanced in its accessibility; and the Unix operating system could run on any computer with a c compiler. Gareth Loy and Richard Moore; CARL based on UNIX systems interconnected programs for text processing; not real-time, open-source; implemented in C and extensible through an api. cmusic implementation of music v in c; created by richard moore
note: created by Paul Lansky not a MUSIC-N descendant; C library and scoring language; like loops and conditional statements; Common Lisp Music by Bill Schottstaedt; MUSIC-N descent; nyquist is a newer lisp based language audacity;csound most popular MUSIC-N descendant;audio rate and control rate; where ar and kr come from now supports real-time audio
note: created by Miller S. Puckette at IRCAM; Pd open source; Max originally made for MIDI but added the signal capabilities of Pd where the MSP comes from
note: James McCartney 1996; scsynth writing and sends the real time audio server supercollider code is executed on; it can be communicated with via the OSC standard; the server can be used by any number of applications and programs as long as they can communicate in a way the server understands; sclang is the interpreted programming language for writing supercollider code; scide is a development environment which integrates easily with sclang and scsynth while also providing easy access to the extensive help documentation
note: Switched on Bach skyrocketed moog synthesizers into the mainstream. The album required thousands of hours of work due to the monophonic nature of the synthesizers. The album was the second classical music album ever to go platinum, and won 3 grammys. compositions for incredibly influential films. inspired stranger things soundtrack
–
note: the Beatles of electronic music; highly influential in a number of electronic and popular music genres. The single edit of the autobahn title track became an international hit in 1975. To quote Schneider “We are more like vehicles, a part of out mensch machine, out man-machine. Sometimes we play the music, sometimes the music plays us, sometimes… it plays.”
–
note: he has a large collection of analog synthesizers in his studio that he uses he also is a fan of VCV rack which provides digital implementations of analog models. to quote “A lot of those oscillators are great. Obviously, not so much the analogue oscillators like you’d get out of a Cynthia or something like that. But the digital oscillators, all the wavetable stuff and the digital FM ops, and stuff like that are fucking great.” there is a market for this kind of stuff
–
note: beyond accurate physical models, a full conversion to digital with digital capabilities; natural extensibility of scsynth, well documented, good API; familiar with the capabilites of SuperCollider and C++
–
Wavefonix Boolean Logic {.fragment .fade-up}
note: based on the Wavefonix Boolean Logic Module; talk about how my implementation differs
–
#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;
}
}
–
note: go to SC
–
Mutable Instruments Ripples {.fragment .fade-up}
note: differs in implementation no resonant filters, chebyschev filters instead due to my attempt to use digital filters for everyone as my implementation guide; no need for vca, and no other frequency input; hope to develop a version more accurate to the module in the future
–
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 {.fragment .fade-right}
note: digital and tape delay with ability to overlap, hold, and reverse with controllable feedback. I have an option for tape saturation or not, hold, and reverse. The adding on this module serves a loop function which I have not yet been able to implement.
–
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;
}
–