/*
The Twelly Tool v1.03 - Absolutely Rework
My bytebeats are getting better, so I have
to rework my tools to make it more optimized.
So I decided to rework my tool
*/
/* Call-counts */
/* All filters and effects here (or almost all) are infinitely instanciables, so they need a call-count/index variable */
LPRI = 0,
LPFI = 0,
DLYI = 0,
LRPI = 0,
PCHI = 0,
/* Constants */
t || (
SampleRate = 48e3,
Tuning = 440,
SamplesPerBeat = 0x4000,
BeatsPerMinute = 120,
Volume = 16,
FilterBuffer = [],
DelayBuffers = [],
[ResX, ResY] = [[], []],
LerpVars = [],
PitchVars = []
),
/* Those functions calculates essential constants, such as tone and speed, do not touch these! */
GetSpeed = (SampleRate, BPM, SamplesPerBeat) => t * (BPM / (60 * SampleRate / SamplesPerBeat)),
GetTone = (Tuning, SampleRate, Transpose=0) => (2 ** ((-9 + Transpose) / 12) * Tuning * 128 / SampleRate),
/* Now the time constants */
tt = t * GetTone(Tuning, SampleRate),
ts = GetSpeed(SampleRate, BeatsPerMinute, SamplesPerBeat),
/* Some shortcuts */
Repeat = (Obj, Times) => Obj.repeat(Times),
From = (Length, Func) => Array.from({ length: Length }, (_, i) => Func(_, i)),
Reverse = (Arr) => Arr.reverse(),
Join = (Arr, Sep) => Arr.join(Sep),
Split = (Arr, Sep) => Arr.split(Sep),
JoinRev = (Arr) => [...Arr, ...Reverse(Arr)],
ReplaceNaN = (Arr) => Array.from(Arr, x => x === undefined ? NaN : x),
Len = (Arr) => Arr.length,
Concat = (Str1, Str2) => Str1.concat(Str2),
/* =========== BASE FUNCTIONS =========== */
/* Those functions are the base functions, those functions that you gotta need when creating bytebeats with my tool */
Bar = (Start, End, Divisor) => (floor(ts / Divisor) + Start) % End,
Rbar = ReverseBar = (End, Divisor) => (End - 1) - Bar(0, End, Divisor),
BASE64_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/+",
Dec = Decode = (SourceString) => (
[...SourceString].map(x => x == "-" ? NaN : BASE64_CHARS.indexOf(x))
),
Enc = Encode = (Numbers) => (
Join(Numbers.map(x => Number.isNaN(x) ? "-" : BASE64_CHARS[x]), "")
),
Pch = Pitcher = Value => (Call = PCHI++, PitchVars[Call] ??= 0, PitchVars[Call] += Value / SampleRate),
Seq = ArraySequencer = (Data, Divisor) => Data[Bar(0, Len(Data), Divisor)],
Rseq = ReversedArraySequencer = (Data, Divisor) => Data[Rbar(0, Len(Data), Divisor)],
Mseq = MelodicSequencer = (Data, Divisor, Transpose=0, MultiplyByT = 0) => (MultiplyByT == 1 ? tt * 2 ** ((Decode(Seq(Data, Divisor)) - Transpose) / 12) || 0 : Pch(GetTone(Tuning, SampleRate / (2 ** 16) * (1 / 2.666667 + 1)) * 2 ** ((Decode(Seq(Data, Divisor)) - Transpose) / 12) || 0)),
Cseq = ChordSequencer = (Data, Divisor, Waveform) => (
Index = [...Seq(Data, Divisor)],
Index.map(x => Dec(x)).reduce((ac, i) => ac + Waveform(tt * 2 ** (i / 12)) % 256 / Index.length, 0)
),
Bseq = BeatSequencer = (Data, Divisor, Elements) => (
Data.reduce((ac, i) => ac + (Seq(i, Divisor) == "1" ? Elements[Data.indexOf(i)] : 0), 0)
),
Dseq = DecodeSequencer = (Data, Divisor) => Dec(Seq(Data, Divisor)),
SoftClamp = (Input) => tanh(Input * PI / 128) * Volume,
HardClamp = (Input) => min(max(Input, -128), 127),
/* []====================FILTERS=====================[] */
/* Those filters are important when creating waveforms or editing audio, use they well! */
LPF = (Input, Amp) => (
Call = LPFI++,
AmpLPF = Amp / (48e3 / SampleRate),
FilterBuffer[Call] ??= 0,
FilterBuffer[Call] += (Input - FilterBuffer[Call]) * AmpLPF
),
LPR = (Input, Frequency, Resonance) => (
Call = LPRI++,
ResX[Call] ??= 0,
ResY[Call] ??= 0,
Feedback = Resonance + Resonance / (1 - Frequency),
ResX[Call] += Frequency * (Input - ResX[Call] + Feedback * (ResX[Call] - ResY[Call])),
ResY[Call] += Frequency * (ResX[Call] - ResY[Call]),
ResY[Call]
),
DLY = Delay = (Input, Samples, Feedback) => (
Call = DLYI