Lowering: patch repeat restarts pitch and arpeggio, not the envelope; README store-kind rollback note #37
9 changed files with 104 additions and 38 deletions
|
|
@ -164,3 +164,10 @@ dotnet build -p:CultLibRoot=<path> # or set CULTLIB_ROOT=<path>
|
|||
```
|
||||
|
||||
Without an override the sibling `..\CultLib` checkout is used and must itself be at that revision.
|
||||
|
||||
**Stores are one-way, and rolling back can lose data.** Since the pin move (#35) list elements carry ids, and a store holding any element id is stamped with a newer header. What an older build does with it depends on the store kind:
|
||||
|
||||
- **Single-file stores** (header v3 with ids): the patch catalog (`patches/aquasynth-patch-cultcache.cc`), the speech training store and the daemon store. Pins before `cultlib-unity-v2.0.0` / `caching-unity-v2.0.0`, including NuGet `cultlib-v1.0.32`, read these without complaint, silently drop the ids, and can rewrite elements without them. Only v2.0.0 and later refuse by name.
|
||||
- **Directory stores** (header v5 with ids): the IPA trial results store (`ipa-trial-results.cc`, `UseDirectoryStore`). These are refused by name from `cultlib-unity-v1.0.57` / `caching-unity-v1.2.0`.
|
||||
|
||||
So: take a copy of any store before the upgrade and restore from it if you roll back, never write with the new pin and then read with an old one, and upgrade every reader before any writer. Stores written before the move still open; ids are minted on load.
|
||||
|
|
|
|||
|
|
@ -29,12 +29,10 @@ public static partial class FaustEmitter
|
|||
if (patch.Repeat is { } repeat)
|
||||
{
|
||||
var interval = parameters.Expression("/patch/repeat", repeat.IntervalSeconds);
|
||||
source.AppendLine($"age = time - floor(time / {interval}) * {interval};");
|
||||
}
|
||||
else
|
||||
{
|
||||
source.AppendLine("age = time;");
|
||||
// sfxr's repeat restarts the pitch slide and the arpeggio, not the envelope: age keeps running, the voices wrap their pitch age.
|
||||
source.AppendLine($"repeat_interval = {interval};");
|
||||
}
|
||||
source.AppendLine("age = time;");
|
||||
source.AppendLine("clip01(x) = min(1.0, max(0.0, x));");
|
||||
source.AppendLine("wrap01(x) = x - floor(x);");
|
||||
source.AppendLine("slew(rate,x) = x : *(1.0 - exp((0.0 - max(0.0001, rate)) / ma.SR)) : + ~ *(exp((0.0 - max(0.0001, rate)) / ma.SR));");
|
||||
|
|
@ -325,6 +323,9 @@ public static partial class FaustEmitter
|
|||
? $"{voiceAge} = wrap01(age / {F(voice.Note.TriggerIntervalSeconds)}) * {F(voice.Note.TriggerIntervalSeconds)};"
|
||||
: $"{voiceAge} = age;");
|
||||
|
||||
var pitchAge = patch.Repeat is null ? voiceAge : $"{name}_pitch_age";
|
||||
if (patch.Repeat is not null) source.AppendLine($"{pitchAge} = {voiceAge} - floor({voiceAge} / repeat_interval) * repeat_interval;");
|
||||
|
||||
var minFreq = parameters.Expression(OwnerField(ownerPath, "pitch/min_freq"), voice.Pitch.MinFrequencyHz);
|
||||
var noteFreq = NoteFrequencyExpression(source, patch.Playback, voice.Note, name, OwnerField(ownerPath, "note/frequency"), parameters);
|
||||
var noteGate = NoteGateExpression(source, patch.Playback, voice.Note, name, OwnerField(ownerPath, "note/gate"), parameters);
|
||||
|
|
@ -333,7 +334,7 @@ public static partial class FaustEmitter
|
|||
var vibratoDepth = parameters.Expression(OwnerField(ownerPath, "pitch/vibrato"), voice.Pitch.VibratoDepth);
|
||||
var vibratoHz = parameters.Expression(OwnerField(ownerPath, "pitch/vibrato_hz"), voice.Pitch.VibratoHz);
|
||||
var vibratoDelay = parameters.Expression(OwnerField(ownerPath, "pitch/vibrato_delay"), voice.Pitch.VibratoDelaySeconds);
|
||||
var baseFreq = $"max({minFreq}, {noteFreq} * pow(2.0, {pitchRamp} * {voiceAge} + 0.5 * {pitchDelta} * {voiceAge} * {voiceAge}))";
|
||||
var baseFreq = $"max({minFreq}, {noteFreq} * pow(2.0, {pitchRamp} * {pitchAge} + 0.5 * {pitchDelta} * {pitchAge} * {pitchAge}))";
|
||||
var hasVibrato = voice.Pitch.VibratoDepth != 0 && voice.Pitch.VibratoHz > 0 ||
|
||||
parameters.IsBound(OwnerField(ownerPath, "pitch/vibrato")) ||
|
||||
parameters.IsBound(OwnerField(ownerPath, "pitch/vibrato_hz"));
|
||||
|
|
@ -342,7 +343,7 @@ public static partial class FaustEmitter
|
|||
: "";
|
||||
var arpeggio = voice.Arpeggio is null
|
||||
? "1.0"
|
||||
: $"select2({voiceAge} < {parameters.Expression(OwnerField(ownerPath, "arpeggio/delay"), voice.Arpeggio.DelaySeconds)}, {parameters.Expression(OwnerField(ownerPath, "arpeggio/multiplier"), voice.Arpeggio.Multiplier)}, 1.0)";
|
||||
: $"select2({pitchAge} < {parameters.Expression(OwnerField(ownerPath, "arpeggio/delay"), voice.Arpeggio.DelaySeconds)}, {parameters.Expression(OwnerField(ownerPath, "arpeggio/multiplier"), voice.Arpeggio.Multiplier)}, 1.0)";
|
||||
var frequency = $"(({baseFreq}){vibrato}) * {arpeggio} * pow(2.0, patch_mod_pitch + {pitch})";
|
||||
var dutyExpression = $"clip01({parameters.Expression(OwnerField(ownerPath, "osc/duty"), voice.Oscillator.Duty)} + {parameters.Expression(OwnerField(ownerPath, "duty/ramp"), voice.Duty.RampPerSecond)} * {voiceAge} + patch_mod_duty + {duty})";
|
||||
var fmIndex = $"max(0.0, {parameters.Expression(OwnerField(ownerPath, "fm/index"), voice.Fm.Index)} + patch_mod_fm_index + {fmIndexMod}) * {FmDecay(parameters.Expression(OwnerField(ownerPath, "fm/decay"), voice.Fm.IndexDecaySeconds), voice.Fm.IndexDecaySeconds, parameters.IsBound(OwnerField(ownerPath, "fm/decay")), voiceAge)}";
|
||||
|
|
|
|||
44
tests/AquaSynth.Dsl.Tests/RepeatLoweringTests.cs
Normal file
44
tests/AquaSynth.Dsl.Tests/RepeatLoweringTests.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
using AquaSynth.Dsl;
|
||||
|
||||
namespace AquaSynth.Dsl.Tests;
|
||||
|
||||
// sfxr's repeat restarts the pitch slide and the arpeggio; it does not restart the envelope. Before this, `patch repeat` wrapped the
|
||||
// whole age, so a repeat shorter than sustain+decay never reached the release (the 2026-11-11 explosion/golf/powerup finding).
|
||||
public sealed class RepeatLoweringTests
|
||||
{
|
||||
private const string Script = """
|
||||
patch repeat=0.11315
|
||||
voice
|
||||
wave=sine
|
||||
freq=57.5946
|
||||
sustain=0.1306122449
|
||||
decay=0.1777777778
|
||||
pitch_ramp=-0.208544
|
||||
arp_delay=0.05
|
||||
arp_mult=1.5
|
||||
""";
|
||||
|
||||
[Fact]
|
||||
public void RepeatWrapsPitchAndArpeggioAgeButNotTheEnvelope()
|
||||
{
|
||||
var source = FaustEmitter.EmitScript(Script).Source;
|
||||
|
||||
Assert.Contains("age = time;", source);
|
||||
Assert.DoesNotContain("floor(time /", source);
|
||||
Assert.Contains("voice_0_pitch_age = voice_0_age - floor(voice_0_age / repeat_interval) * repeat_interval;", source);
|
||||
Assert.Contains("0.208544", source);
|
||||
Assert.Contains("* voice_0_pitch_age", source);
|
||||
Assert.Contains("select2(voice_0_pitch_age <", source);
|
||||
Assert.Contains("oneshot_adsr_at(voice_0_age,", source);
|
||||
Assert.DoesNotContain("oneshot_adsr_at(voice_0_pitch_age", source);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WithoutRepeatThereIsNoPitchAge()
|
||||
{
|
||||
var source = FaustEmitter.EmitScript(Script.Replace("patch repeat=0.11315\n", "")).Source;
|
||||
|
||||
Assert.DoesNotContain("pitch_age", source);
|
||||
Assert.DoesNotContain("repeat_interval", source);
|
||||
}
|
||||
}
|
||||
|
|
@ -85,18 +85,18 @@ Sustained patches such as the thruster keep sounding until stopped; the render c
|
|||
| `patch/advanced-glass-creature` | start | none | decays | 3 s | unheard |
|
||||
| `patch/advanced-human-larynx-graph` | start | curves/breath_phrase/depth 0..1 (default 0.9); curves/fold_onset/depth 0..1 (default 0.8); curves/lip_vowel/depth 0..1 (default 0.65); human/constriction/diameter 0.02..3 (default 0.95); human/constriction/index 0..6 (default 4.8); human/fold/opening 0..1 (default 0.16); human/fold/tension 0..1 (default 0.58); human/lip/opening 0..2 (default 1.2); human/subglottal 0..1.5 (default 0.78); human/tongue/diameter 0.05..3 (default 1.25); human/tongue/index 0..6 (default 3.3) | decays | 3 s | unheard |
|
||||
| `patch/advanced-machine-breath` | start | none | decays | 3 s | unheard |
|
||||
| `patch/advanced-ritual-sequence` | start | none | sustained | 3 s | unheard |
|
||||
| `patch/advanced-ritual-sequence` | start | none | decays | 3 s | unheard |
|
||||
| `patch/advanced-subtractive-drums` | start | none | decays | 3 s | unheard |
|
||||
| `patch/advanced-syrinx-voice` | start | curves/beak_phrase/depth 0..1 (default 0.72); curves/left_phrase_opening/depth 0..1 (default 0.85); curves/left_phrase_pressure/depth 0..1 (default 0.92); curves/right_phrase_opening/depth 0..1 (default 0.85); curves/right_phrase_pressure/depth 0..1 (default 0.92); voice/beak/opening 0..1.5 (default 0.88); voice/left/opening 0..1 (default 0.23); voice/left/pressure 0..1.5 (default 0.78); voice/left/tension 0..1 (default 0.43); voice/right/opening 0..1 (default 0.19); voice/right/pressure 0..1.5 (default 0.66); voice/right/tension 0..1 (default 0.5) | decays | 3 s | unheard |
|
||||
| `patch/bfxr-coin-spark` | start | none | decays | 3 s | unheard |
|
||||
| `patch/bfxr-portal-chirp` | start | none | decays | 3 s | unheard |
|
||||
| `patch/bfxr-shield-pop` | start | none | decays | 3 s | unheard |
|
||||
| `patch/bfxr-ui-bloom` | start | none | sustained | 3 s | unheard |
|
||||
| `patch/bfxr-ui-bloom` | start | none | decays | 3 s | unheard |
|
||||
| `patch/dx7-algorithm-32-additive-organ` | start | macro/drawbar 0..1 (default 0.78); macro/shimmer 0..0.3 (default 0.08) | decays | 3 s | unheard |
|
||||
| `patch/dx7-algorithm-8-bright-pair` | start | macro/brightness 0..5 (default 2.6); macro/strike 0.02..0.6 (default 0.18) | decays | 3 s | unheard |
|
||||
| `patch/dx7-public-domain-mc-mm-5-3` | start | none | decays | 3 s | unheard |
|
||||
| `patch/dx7-public-domain-prc-synth1-calibrated` | start | none | decays | 3 s | unheard |
|
||||
| `patch/examples-language-tour` | start | none | sustained | 3 s | unheard |
|
||||
| `patch/examples-language-tour` | start | none | decays | 3 s | unheard |
|
||||
| `patch/fm-bell-bell` | start | none | decays | 3 s | unheard |
|
||||
| `patch/fm-bell-chime` | start | none | decays | 3 s | unheard |
|
||||
| `patch/fm-bell-coin` | start | none | decays | 3 s | unheard |
|
||||
|
|
@ -108,7 +108,7 @@ Sustained patches such as the thruster keep sounding until stopped; the render c
|
|||
| `patch/sfxr-jump` | start | none | decays | 3 s | unheard |
|
||||
| `patch/sfxr-laser` | start | none | decays | 3 s | unheard |
|
||||
| `patch/sfxr-pickup` | start | none | decays | 3 s | unheard |
|
||||
| `patch/sfxr-powerup` | start | none | sustained | 3 s | unheard |
|
||||
| `patch/sfxr-powerup` | start | none | decays | 3 s | unheard |
|
||||
| `patch/wobble-bass-growl` | start | none | decays | 3 s | unheard |
|
||||
| `patch/wobble-bass-neuro` | start | none | decays | 3 s | unheard |
|
||||
| `patch/wobble-bass-talker` | start | none | decays | 3 s | unheard |
|
||||
|
|
|
|||
|
|
@ -859,7 +859,7 @@
|
|||
"kind": "start",
|
||||
"detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays."
|
||||
},
|
||||
"behaviour": "sustained: still sounding at the end of the render window, runs until stopped",
|
||||
"behaviour": "decays: dies away inside the render window",
|
||||
"duration_s": 3,
|
||||
"duration_note": "the render window, not the effect's length",
|
||||
"render": {
|
||||
|
|
@ -1106,7 +1106,7 @@
|
|||
"kind": "start",
|
||||
"detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays."
|
||||
},
|
||||
"behaviour": "sustained: still sounding at the end of the render window, runs until stopped",
|
||||
"behaviour": "decays: dies away inside the render window",
|
||||
"duration_s": 3,
|
||||
"duration_note": "the render window, not the effect's length",
|
||||
"render": {
|
||||
|
|
@ -1265,7 +1265,7 @@
|
|||
"kind": "start",
|
||||
"detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays."
|
||||
},
|
||||
"behaviour": "sustained: still sounding at the end of the render window, runs until stopped",
|
||||
"behaviour": "decays: dies away inside the render window",
|
||||
"duration_s": 3,
|
||||
"duration_note": "the render window, not the effect's length",
|
||||
"render": {
|
||||
|
|
@ -1565,7 +1565,7 @@
|
|||
"kind": "start",
|
||||
"detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays."
|
||||
},
|
||||
"behaviour": "sustained: still sounding at the end of the render window, runs until stopped",
|
||||
"behaviour": "decays: dies away inside the render window",
|
||||
"duration_s": 3,
|
||||
"duration_note": "the render window, not the effect's length",
|
||||
"render": {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ declare name "advanced-ritual-sequence";
|
|||
declare options "[nvoices:1]";
|
||||
|
||||
time = ba.time / ma.SR;
|
||||
age = time - floor(time / 0.42) * 0.42;
|
||||
repeat_interval = 0.42;
|
||||
age = time;
|
||||
clip01(x) = min(1.0, max(0.0, x));
|
||||
wrap01(x) = x - floor(x);
|
||||
slew(rate,x) = x : *(1.0 - exp((0.0 - max(0.0001, rate)) / ma.SR)) : + ~ *(exp((0.0 - max(0.0001, rate)) / ma.SR));
|
||||
|
|
@ -41,8 +42,9 @@ patch_mod_formant_mix = 0.0;
|
|||
patch_mod_fm_index = 0 + 0.75 * lfo_tri(2.38, 0);
|
||||
|
||||
voice_0_age = age;
|
||||
voice_0_freq = ((max(20, 196 * pow(2.0, 0 * voice_0_age + 0.5 * 0 * voice_0_age * voice_0_age)))) * select2(voice_0_age < 0.065, 1.4983, 1.0) * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_0_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 196 * pow(2.0, 0 * voice_0_age + 0.5 * 0 * voice_0_age * voice_0_age)))) * select2(voice_0_age < 0.065, 1.4983, 1.0) * pow(2.0, patch_mod_pitch + 0.0)) + 0 + sin(2.0 * ma.PI * os.phasor(1.0, ((max(20, 196 * pow(2.0, 0 * voice_0_age + 0.5 * 0 * voice_0_age * voice_0_age)))) * select2(voice_0_age < 0.065, 1.4983, 1.0) * pow(2.0, patch_mod_pitch + 0.0) * max(0.0, 2))) * (max(0.0, 1.8 + patch_mod_fm_index + 0.0) * exp(-voice_0_age / max(0.32, 0.0001))) / ma.PI));
|
||||
voice_0_pitch_age = voice_0_age - floor(voice_0_age / repeat_interval) * repeat_interval;
|
||||
voice_0_freq = ((max(20, 196 * pow(2.0, 0 * voice_0_pitch_age + 0.5 * 0 * voice_0_pitch_age * voice_0_pitch_age)))) * select2(voice_0_pitch_age < 0.065, 1.4983, 1.0) * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_0_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 196 * pow(2.0, 0 * voice_0_pitch_age + 0.5 * 0 * voice_0_pitch_age * voice_0_pitch_age)))) * select2(voice_0_pitch_age < 0.065, 1.4983, 1.0) * pow(2.0, patch_mod_pitch + 0.0)) + 0 + sin(2.0 * ma.PI * os.phasor(1.0, ((max(20, 196 * pow(2.0, 0 * voice_0_pitch_age + 0.5 * 0 * voice_0_pitch_age * voice_0_pitch_age)))) * select2(voice_0_pitch_age < 0.065, 1.4983, 1.0) * pow(2.0, patch_mod_pitch + 0.0) * max(0.0, 2))) * (max(0.0, 1.8 + patch_mod_fm_index + 0.0) * exp(-voice_0_age / max(0.32, 0.0001))) / ma.PI));
|
||||
voice_0_colored = (voice_0_osc * (1.0 - clip01(0 + patch_mod_noise + 0.0)) + no.noise * clip01(0 + patch_mod_noise + 0.0));
|
||||
voice_0_driven = ma.tanh(voice_0_colored * (1.0 + clip01(0.1 + patch_mod_drive + 0.0) * 12.0)) / ma.tanh(1.0 + clip01(0.1 + patch_mod_drive + 0.0) * 12.0);
|
||||
voice_0_folded = voice_0_driven * (1.0 - clip01(0 + patch_mod_fold + 0.0)) + fold(voice_0_driven * (1.0 + clip01(0 + patch_mod_fold + 0.0) * 3.5)) * clip01(0 + patch_mod_fold + 0.0);
|
||||
|
|
@ -52,8 +54,9 @@ voice_0_formants = voice_0_phased;
|
|||
voice_0 = ((voice_0_phased * (1.0 - clip01(0 + patch_mod_formant_mix + 0.0)) + voice_0_formants * clip01(0 + patch_mod_formant_mix + 0.0)) * oneshot_adsr_at(voice_0_age, 0.001, 0, 0.8474576, 0.5, 0.045) * max(0.0, 1.0 + patch_mod_gain + 0.0) * 0.1534);
|
||||
|
||||
voice_1_age = age;
|
||||
voice_1_freq = ((max(20, 293.66 * pow(2.0, 0 * voice_1_age + 0.5 * 0 * voice_1_age * voice_1_age)))) * select2(voice_1_age < 0.065, 1.3348, 1.0) * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_1_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 293.66 * pow(2.0, 0 * voice_1_age + 0.5 * 0 * voice_1_age * voice_1_age)))) * select2(voice_1_age < 0.065, 1.3348, 1.0) * pow(2.0, patch_mod_pitch + 0.0)) + 0 + sin(2.0 * ma.PI * os.phasor(1.0, ((max(20, 293.66 * pow(2.0, 0 * voice_1_age + 0.5 * 0 * voice_1_age * voice_1_age)))) * select2(voice_1_age < 0.065, 1.3348, 1.0) * pow(2.0, patch_mod_pitch + 0.0) * max(0.0, 2))) * (max(0.0, 1.8 + patch_mod_fm_index + 0.0) * exp(-voice_1_age / max(0.32, 0.0001))) / ma.PI));
|
||||
voice_1_pitch_age = voice_1_age - floor(voice_1_age / repeat_interval) * repeat_interval;
|
||||
voice_1_freq = ((max(20, 293.66 * pow(2.0, 0 * voice_1_pitch_age + 0.5 * 0 * voice_1_pitch_age * voice_1_pitch_age)))) * select2(voice_1_pitch_age < 0.065, 1.3348, 1.0) * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_1_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 293.66 * pow(2.0, 0 * voice_1_pitch_age + 0.5 * 0 * voice_1_pitch_age * voice_1_pitch_age)))) * select2(voice_1_pitch_age < 0.065, 1.3348, 1.0) * pow(2.0, patch_mod_pitch + 0.0)) + 0 + sin(2.0 * ma.PI * os.phasor(1.0, ((max(20, 293.66 * pow(2.0, 0 * voice_1_pitch_age + 0.5 * 0 * voice_1_pitch_age * voice_1_pitch_age)))) * select2(voice_1_pitch_age < 0.065, 1.3348, 1.0) * pow(2.0, patch_mod_pitch + 0.0) * max(0.0, 2))) * (max(0.0, 1.8 + patch_mod_fm_index + 0.0) * exp(-voice_1_age / max(0.32, 0.0001))) / ma.PI));
|
||||
voice_1_colored = (voice_1_osc * (1.0 - clip01(0 + patch_mod_noise + 0.0)) + no.noise * clip01(0 + patch_mod_noise + 0.0));
|
||||
voice_1_driven = ma.tanh(voice_1_colored * (1.0 + clip01(0.1 + patch_mod_drive + 0.0) * 12.0)) / ma.tanh(1.0 + clip01(0.1 + patch_mod_drive + 0.0) * 12.0);
|
||||
voice_1_folded = voice_1_driven * (1.0 - clip01(0 + patch_mod_fold + 0.0)) + fold(voice_1_driven * (1.0 + clip01(0 + patch_mod_fold + 0.0) * 3.5)) * clip01(0 + patch_mod_fold + 0.0);
|
||||
|
|
@ -63,8 +66,9 @@ voice_1_formants = voice_1_phased;
|
|||
voice_1 = ((voice_1_phased * (1.0 - clip01(0 + patch_mod_formant_mix + 0.0)) + voice_1_formants * clip01(0 + patch_mod_formant_mix + 0.0)) * oneshot_adsr_at(voice_1_age, 0.001, 0, 0.8474576, 0.38, 0.035) * max(0.0, 1.0 + patch_mod_gain + 0.0) * 0.09);
|
||||
|
||||
voice_2_age = age;
|
||||
voice_2_freq = ((max(20, 392 * pow(2.0, 0 * voice_2_age + 0.5 * 0 * voice_2_age * voice_2_age)))) * select2(voice_2_age < 0.065, 1.2599, 1.0) * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_2_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 392 * pow(2.0, 0 * voice_2_age + 0.5 * 0 * voice_2_age * voice_2_age)))) * select2(voice_2_age < 0.065, 1.2599, 1.0) * pow(2.0, patch_mod_pitch + 0.0)) + 0 + sin(2.0 * ma.PI * os.phasor(1.0, ((max(20, 392 * pow(2.0, 0 * voice_2_age + 0.5 * 0 * voice_2_age * voice_2_age)))) * select2(voice_2_age < 0.065, 1.2599, 1.0) * pow(2.0, patch_mod_pitch + 0.0) * max(0.0, 2))) * (max(0.0, 1.8 + patch_mod_fm_index + 0.0) * exp(-voice_2_age / max(0.32, 0.0001))) / ma.PI));
|
||||
voice_2_pitch_age = voice_2_age - floor(voice_2_age / repeat_interval) * repeat_interval;
|
||||
voice_2_freq = ((max(20, 392 * pow(2.0, 0 * voice_2_pitch_age + 0.5 * 0 * voice_2_pitch_age * voice_2_pitch_age)))) * select2(voice_2_pitch_age < 0.065, 1.2599, 1.0) * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_2_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 392 * pow(2.0, 0 * voice_2_pitch_age + 0.5 * 0 * voice_2_pitch_age * voice_2_pitch_age)))) * select2(voice_2_pitch_age < 0.065, 1.2599, 1.0) * pow(2.0, patch_mod_pitch + 0.0)) + 0 + sin(2.0 * ma.PI * os.phasor(1.0, ((max(20, 392 * pow(2.0, 0 * voice_2_pitch_age + 0.5 * 0 * voice_2_pitch_age * voice_2_pitch_age)))) * select2(voice_2_pitch_age < 0.065, 1.2599, 1.0) * pow(2.0, patch_mod_pitch + 0.0) * max(0.0, 2))) * (max(0.0, 1.8 + patch_mod_fm_index + 0.0) * exp(-voice_2_age / max(0.32, 0.0001))) / ma.PI));
|
||||
voice_2_colored = (voice_2_osc * (1.0 - clip01(0 + patch_mod_noise + 0.0)) + no.noise * clip01(0 + patch_mod_noise + 0.0));
|
||||
voice_2_driven = ma.tanh(voice_2_colored * (1.0 + clip01(0.1 + patch_mod_drive + 0.0) * 12.0)) / ma.tanh(1.0 + clip01(0.1 + patch_mod_drive + 0.0) * 12.0);
|
||||
voice_2_folded = voice_2_driven * (1.0 - clip01(0 + patch_mod_fold + 0.0)) + fold(voice_2_driven * (1.0 + clip01(0 + patch_mod_fold + 0.0) * 3.5)) * clip01(0 + patch_mod_fold + 0.0);
|
||||
|
|
@ -74,7 +78,8 @@ voice_2_formants = voice_2_phased;
|
|||
voice_2 = ((voice_2_phased * (1.0 - clip01(0 + patch_mod_formant_mix + 0.0)) + voice_2_formants * clip01(0 + patch_mod_formant_mix + 0.0)) * oneshot_adsr_at(voice_2_age, 0.001, 0, 0.8474576, 0.32, 0.028) * max(0.0, 1.0 + patch_mod_gain + 0.0) * 0.07);
|
||||
|
||||
voice_3_age = age;
|
||||
voice_3_freq = ((max(20, 3100 * pow(2.0, 0 * voice_3_age + 0.5 * 0 * voice_3_age * voice_3_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_3_pitch_age = voice_3_age - floor(voice_3_age / repeat_interval) * repeat_interval;
|
||||
voice_3_freq = ((max(20, 3100 * pow(2.0, 0 * voice_3_pitch_age + 0.5 * 0 * voice_3_pitch_age * voice_3_pitch_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_3_osc = no.noise;
|
||||
voice_3_colored = (voice_3_osc * (1.0 - clip01(1 + patch_mod_noise + 0.0)) + no.noise * clip01(1 + patch_mod_noise + 0.0));
|
||||
voice_3_driven = ma.tanh(voice_3_colored * (1.0 + clip01(0.1 + patch_mod_drive + 0.0) * 12.0)) / ma.tanh(1.0 + clip01(0.1 + patch_mod_drive + 0.0) * 12.0);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ declare name "bfxr-ui-bloom";
|
|||
declare options "[nvoices:1]";
|
||||
|
||||
time = ba.time / ma.SR;
|
||||
age = time - floor(time / 0.18) * 0.18;
|
||||
repeat_interval = 0.18;
|
||||
age = time;
|
||||
clip01(x) = min(1.0, max(0.0, x));
|
||||
wrap01(x) = x - floor(x);
|
||||
slew(rate,x) = x : *(1.0 - exp((0.0 - max(0.0001, rate)) / ma.SR)) : + ~ *(exp((0.0 - max(0.0001, rate)) / ma.SR));
|
||||
|
|
@ -41,8 +42,9 @@ patch_mod_formant_mix = 0.0;
|
|||
patch_mod_fm_index = 0.0;
|
||||
|
||||
voice_0_age = age;
|
||||
voice_0_freq = ((max(20, 392 * pow(2.0, 0.18 * voice_0_age + 0.5 * 0 * voice_0_age * voice_0_age)))) * select2(voice_0_age < 0.08, 1.25, 1.0) * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_0_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 392 * pow(2.0, 0.18 * voice_0_age + 0.5 * 0 * voice_0_age * voice_0_age)))) * select2(voice_0_age < 0.08, 1.25, 1.0) * pow(2.0, patch_mod_pitch + 0.0)) + 0));
|
||||
voice_0_pitch_age = voice_0_age - floor(voice_0_age / repeat_interval) * repeat_interval;
|
||||
voice_0_freq = ((max(20, 392 * pow(2.0, 0.18 * voice_0_pitch_age + 0.5 * 0 * voice_0_pitch_age * voice_0_pitch_age)))) * select2(voice_0_pitch_age < 0.08, 1.25, 1.0) * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_0_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 392 * pow(2.0, 0.18 * voice_0_pitch_age + 0.5 * 0 * voice_0_pitch_age * voice_0_pitch_age)))) * select2(voice_0_pitch_age < 0.08, 1.25, 1.0) * pow(2.0, patch_mod_pitch + 0.0)) + 0));
|
||||
voice_0_colored = (voice_0_osc * (1.0 - clip01(0 + patch_mod_noise + 0.0)) + no.noise * clip01(0 + patch_mod_noise + 0.0));
|
||||
voice_0_driven = ma.tanh(voice_0_colored * (1.0 + clip01(0.06 + patch_mod_drive + 0.0) * 12.0)) / ma.tanh(1.0 + clip01(0.06 + patch_mod_drive + 0.0) * 12.0);
|
||||
voice_0_folded = voice_0_driven * (1.0 - clip01(0 + patch_mod_fold + 0.0)) + fold(voice_0_driven * (1.0 + clip01(0 + patch_mod_fold + 0.0) * 3.5)) * clip01(0 + patch_mod_fold + 0.0);
|
||||
|
|
@ -52,8 +54,9 @@ voice_0_formants = voice_0_phased;
|
|||
voice_0 = ((voice_0_phased * (1.0 - clip01(0 + patch_mod_formant_mix + 0.0)) + voice_0_formants * clip01(0 + patch_mod_formant_mix + 0.0)) * oneshot_adsr_at(voice_0_age, 0, 0, 0.8196721, 0.5, 0.05) * max(0.0, 1.0 + patch_mod_gain + 0.0) * 0.1464);
|
||||
|
||||
voice_1_age = age;
|
||||
voice_1_freq = ((max(20, 588 * pow(2.0, 0 * voice_1_age + 0.5 * 0 * voice_1_age * voice_1_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_1_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 588 * pow(2.0, 0 * voice_1_age + 0.5 * 0 * voice_1_age * voice_1_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0)) + 0));
|
||||
voice_1_pitch_age = voice_1_age - floor(voice_1_age / repeat_interval) * repeat_interval;
|
||||
voice_1_freq = ((max(20, 588 * pow(2.0, 0 * voice_1_pitch_age + 0.5 * 0 * voice_1_pitch_age * voice_1_pitch_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_1_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 588 * pow(2.0, 0 * voice_1_pitch_age + 0.5 * 0 * voice_1_pitch_age * voice_1_pitch_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0)) + 0));
|
||||
voice_1_colored = (voice_1_osc * (1.0 - clip01(0 + patch_mod_noise + 0.0)) + no.noise * clip01(0 + patch_mod_noise + 0.0));
|
||||
voice_1_driven = ma.tanh(voice_1_colored * (1.0 + clip01(0.06 + patch_mod_drive + 0.0) * 12.0)) / ma.tanh(1.0 + clip01(0.06 + patch_mod_drive + 0.0) * 12.0);
|
||||
voice_1_folded = voice_1_driven * (1.0 - clip01(0 + patch_mod_fold + 0.0)) + fold(voice_1_driven * (1.0 + clip01(0 + patch_mod_fold + 0.0) * 3.5)) * clip01(0 + patch_mod_fold + 0.0);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ declare name "examples-language-tour";
|
|||
declare options "[nvoices:1]";
|
||||
|
||||
time = ba.time / ma.SR;
|
||||
age = time - floor(time / 0.4739614) * 0.4739614;
|
||||
repeat_interval = 0.4739614;
|
||||
age = time;
|
||||
clip01(x) = min(1.0, max(0.0, x));
|
||||
wrap01(x) = x - floor(x);
|
||||
slew(rate,x) = x : *(1.0 - exp((0.0 - max(0.0001, rate)) / ma.SR)) : + ~ *(exp((0.0 - max(0.0001, rate)) / ma.SR));
|
||||
|
|
@ -41,8 +42,9 @@ patch_mod_formant_mix = 0 + 0.08 * lfo_sin(5, 0) + 0 + 0.12 * lfo_tri(2, 0);
|
|||
patch_mod_fm_index = 0.0;
|
||||
|
||||
voice_0_age = age;
|
||||
voice_0_freq = ((max(20, 220 * pow(2.0, 0 * voice_0_age + 0.5 * 0 * voice_0_age * voice_0_age))) * (1.0 + select2(voice_0_age < 0, 0.0, sin(2.0 * ma.PI * (voice_0_age - 0) * 5) * 0.02))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_0_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 220 * pow(2.0, 0 * voice_0_age + 0.5 * 0 * voice_0_age * voice_0_age))) * (1.0 + select2(voice_0_age < 0, 0.0, sin(2.0 * ma.PI * (voice_0_age - 0) * 5) * 0.02))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0)) + 0));
|
||||
voice_0_pitch_age = voice_0_age - floor(voice_0_age / repeat_interval) * repeat_interval;
|
||||
voice_0_freq = ((max(20, 220 * pow(2.0, 0 * voice_0_pitch_age + 0.5 * 0 * voice_0_pitch_age * voice_0_pitch_age))) * (1.0 + select2(voice_0_age < 0, 0.0, sin(2.0 * ma.PI * (voice_0_age - 0) * 5) * 0.02))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_0_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 220 * pow(2.0, 0 * voice_0_pitch_age + 0.5 * 0 * voice_0_pitch_age * voice_0_pitch_age))) * (1.0 + select2(voice_0_age < 0, 0.0, sin(2.0 * ma.PI * (voice_0_age - 0) * 5) * 0.02))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0)) + 0));
|
||||
voice_0_colored = (voice_0_osc * (1.0 - clip01(0 + patch_mod_noise + 0.0)) + no.noise * clip01(0 + patch_mod_noise + 0.0));
|
||||
voice_0_driven = ma.tanh(voice_0_colored * (1.0 + clip01(0 + patch_mod_drive + 0.0) * 12.0)) / ma.tanh(1.0 + clip01(0 + patch_mod_drive + 0.0) * 12.0);
|
||||
voice_0_folded = voice_0_driven * (1.0 - clip01(0 + patch_mod_fold + 0.0)) + fold(voice_0_driven * (1.0 + clip01(0 + patch_mod_fold + 0.0) * 3.5)) * clip01(0 + patch_mod_fold + 0.0);
|
||||
|
|
@ -52,8 +54,9 @@ voice_0_formants = ((voice_0_phased : fi.resonbp(620, 6.888889, 1.0)) * 1 + (voi
|
|||
voice_0 = ((voice_0_phased * (1.0 - clip01(0.45 + patch_mod_formant_mix + 0.0)) + voice_0_formants * clip01(0.45 + patch_mod_formant_mix + 0.0)) * oneshot_adsr_at(voice_0_age, 0.002, 0, 1, 0.2, 0.03) * max(0.0, 1.0 + patch_mod_gain + 0.0) * 0.12);
|
||||
|
||||
voice_1_age = age;
|
||||
voice_1_freq = ((max(20, 440 * pow(2.0, 0 * voice_1_age + 0.5 * 0 * voice_1_age * voice_1_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_1_osc = 1.0 - 4.0 * abs(wrap01(os.phasor(1.0, ((max(20, 440 * pow(2.0, 0 * voice_1_age + 0.5 * 0 * voice_1_age * voice_1_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0)) + 0) - 0.5);
|
||||
voice_1_pitch_age = voice_1_age - floor(voice_1_age / repeat_interval) * repeat_interval;
|
||||
voice_1_freq = ((max(20, 440 * pow(2.0, 0 * voice_1_pitch_age + 0.5 * 0 * voice_1_pitch_age * voice_1_pitch_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_1_osc = 1.0 - 4.0 * abs(wrap01(os.phasor(1.0, ((max(20, 440 * pow(2.0, 0 * voice_1_pitch_age + 0.5 * 0 * voice_1_pitch_age * voice_1_pitch_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0)) + 0) - 0.5);
|
||||
voice_1_colored = (voice_1_osc * (1.0 - clip01(0 + patch_mod_noise + 0.0)) + no.noise * clip01(0 + patch_mod_noise + 0.0));
|
||||
voice_1_driven = ma.tanh(voice_1_colored * (1.0 + clip01(0 + patch_mod_drive + 0.0) * 12.0)) / ma.tanh(1.0 + clip01(0 + patch_mod_drive + 0.0) * 12.0);
|
||||
voice_1_folded = voice_1_driven * (1.0 - clip01(0 + patch_mod_fold + 0.0)) + fold(voice_1_driven * (1.0 + clip01(0 + patch_mod_fold + 0.0) * 3.5)) * clip01(0 + patch_mod_fold + 0.0);
|
||||
|
|
@ -63,8 +66,9 @@ voice_1_formants = voice_1_phased;
|
|||
voice_1 = ((voice_1_phased * (1.0 - clip01(0 + patch_mod_formant_mix + 0.0)) + voice_1_formants * clip01(0 + patch_mod_formant_mix + 0.0)) * oneshot_adsr_at(voice_1_age, 0, 0, 1, 0.18, 0.02) * max(0.0, 1.0 + patch_mod_gain + 0.0) * 0.04);
|
||||
|
||||
voice_2_age = age;
|
||||
voice_2_freq = ((max(20, 230.3403 * pow(2.0, 0.7460228 * voice_2_age + 0.5 * 0.00000008 * voice_2_age * voice_2_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_2_osc = 2.0 * wrap01(os.phasor(1.0, ((max(20, 230.3403 * pow(2.0, 0.7460228 * voice_2_age + 0.5 * 0.00000008 * voice_2_age * voice_2_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0)) + 0) - 1.0;
|
||||
voice_2_pitch_age = voice_2_age - floor(voice_2_age / repeat_interval) * repeat_interval;
|
||||
voice_2_freq = ((max(20, 230.3403 * pow(2.0, 0.7460228 * voice_2_pitch_age + 0.5 * 0.00000008 * voice_2_pitch_age * voice_2_pitch_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_2_osc = 2.0 * wrap01(os.phasor(1.0, ((max(20, 230.3403 * pow(2.0, 0.7460228 * voice_2_pitch_age + 0.5 * 0.00000008 * voice_2_pitch_age * voice_2_pitch_age)))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0)) + 0) - 1.0;
|
||||
voice_2_colored = (voice_2_osc * (1.0 - clip01(0 + patch_mod_noise + 0.0)) + no.noise * clip01(0 + patch_mod_noise + 0.0));
|
||||
voice_2_driven = ma.tanh(voice_2_colored * (1.0 + clip01(0.1212819 + patch_mod_drive + 0.0) * 12.0)) / ma.tanh(1.0 + clip01(0.1212819 + patch_mod_drive + 0.0) * 12.0);
|
||||
voice_2_folded = voice_2_driven * (1.0 - clip01(0 + patch_mod_fold + 0.0)) + fold(voice_2_driven * (1.0 + clip01(0 + patch_mod_fold + 0.0) * 3.5)) * clip01(0 + patch_mod_fold + 0.0);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ declare name "sfxr-powerup";
|
|||
declare options "[nvoices:1]";
|
||||
|
||||
time = ba.time / ma.SR;
|
||||
age = time - floor(time / 0.11315) * 0.11315;
|
||||
repeat_interval = 0.11315;
|
||||
age = time;
|
||||
clip01(x) = min(1.0, max(0.0, x));
|
||||
wrap01(x) = x - floor(x);
|
||||
slew(rate,x) = x : *(1.0 - exp((0.0 - max(0.0001, rate)) / ma.SR)) : + ~ *(exp((0.0 - max(0.0001, rate)) / ma.SR));
|
||||
|
|
@ -41,8 +42,9 @@ patch_mod_formant_mix = 0.0;
|
|||
patch_mod_fm_index = 0.0;
|
||||
|
||||
voice_0_age = age;
|
||||
voice_0_freq = ((max(20, 57.5946 * pow(2.0, -0.208544 * voice_0_age + 0.5 * 0 * voice_0_age * voice_0_age))) * (1.0 + select2(voice_0_age < 0, 0.0, sin(2.0 * ma.PI * (voice_0_age - 0) * 3.9602) * 0.09))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_0_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 57.5946 * pow(2.0, -0.208544 * voice_0_age + 0.5 * 0 * voice_0_age * voice_0_age))) * (1.0 + select2(voice_0_age < 0, 0.0, sin(2.0 * ma.PI * (voice_0_age - 0) * 3.9602) * 0.09))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0)) + 0));
|
||||
voice_0_pitch_age = voice_0_age - floor(voice_0_age / repeat_interval) * repeat_interval;
|
||||
voice_0_freq = ((max(20, 57.5946 * pow(2.0, -0.208544 * voice_0_pitch_age + 0.5 * 0 * voice_0_pitch_age * voice_0_pitch_age))) * (1.0 + select2(voice_0_age < 0, 0.0, sin(2.0 * ma.PI * (voice_0_age - 0) * 3.9602) * 0.09))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0);
|
||||
voice_0_osc = sin(2.0 * ma.PI * wrap01(os.phasor(1.0, ((max(20, 57.5946 * pow(2.0, -0.208544 * voice_0_pitch_age + 0.5 * 0 * voice_0_pitch_age * voice_0_pitch_age))) * (1.0 + select2(voice_0_age < 0, 0.0, sin(2.0 * ma.PI * (voice_0_age - 0) * 3.9602) * 0.09))) * 1.0 * pow(2.0, patch_mod_pitch + 0.0)) + 0));
|
||||
voice_0_colored = (voice_0_osc * (1.0 - clip01(0 + patch_mod_noise + 0.0)) + no.noise * clip01(0 + patch_mod_noise + 0.0));
|
||||
voice_0_driven = ma.tanh(voice_0_colored * (1.0 + clip01(0.12 + patch_mod_drive + 0.0) * 12.0)) / ma.tanh(1.0 + clip01(0.12 + patch_mod_drive + 0.0) * 12.0);
|
||||
voice_0_folded = voice_0_driven * (1.0 - clip01(0 + patch_mod_fold + 0.0)) + fold(voice_0_driven * (1.0 + clip01(0 + patch_mod_fold + 0.0) * 3.5)) * clip01(0 + patch_mod_fold + 0.0);
|
||||
|
|
|
|||
Loading…
Reference in a new issue