diff --git a/README.md b/README.md index 07ae08e..aaaac9f 100644 --- a/README.md +++ b/README.md @@ -83,13 +83,14 @@ it's useful when you want to play a note super fast (over 1/64 tempo) but don't ### sosten -sustains a sound by replaying a grain of sound on loop +sustains a sound by replaying a grain of sound on loop. small but versatile parameters: - `enable`: will enable the sustain if it's over 0.5 - `length`: length of the grain in samples. maximum is 48000 cause i said so - `manual/pitch detection`: whether to use the manually set length (if under 0.5) or use the detected pitch (over 0.5) - `dissipation`: amount of dissipation of the input +- `direction`: direction in which the grain is played to use this plugin, add an automation for `enable` and set the value to `1.0` wherever you want the sustain to happen. as soon as that happens, it'll start looping the last `length` samples @@ -97,13 +98,23 @@ if set to manual, it uses the provided length for the looped grain. if pitch det dissipation is a weird thingy. it smooths out the sound, and i think it's a lowpass filter? not sure. makes cool sounds though. what it does is roughly `x[n] = dissipation * x[n] + (1 - dissipation) * x[n + 1]` after each time it plays a sample, so `dissipation = 1` will leave the audio untouched, and setting it to `0.5` provides the greatest effect -low lengths will almost produce a tone of frequency `1 / length`, which makes for interesting sounds +direction is a selector, with three ranges: +- `[0, 0.4)`: the grain will be played backwards +- `[0.4, 0.6)`: the grain will cycle through forwards and backwards +- `[0.6, 1.0]`: the grain will play forwards + +my three main uses are: +- sustaining a note, which you can do with `manual/pitch detection = 1`, `direction = 1`, and any amount of dissipation +- wavetable-ish kinda thing, by setting `manual = 0` and a really low length, you can play notes of frequency `1 / length` +- glitch repetition effect, by setting `manual = 0`, any direction (but usually forward), any dissipation, and a medium length. enable at the end of a bar or smth + +but you can probably use it for more stuff! idk! this are just my suggestions ### quinoa [WIP] nothing implemented yet, but it's supposed to be a granular synthesis plugin that does stuff with an audio file -since this needs a ui so we can select a file to play, and i still don't know how to do that, it's kinda stuck +since this needs a ui so we can select a file to play, and i still don't know how to do that, progress is kinda stuck ### XLowpass diff --git a/crates/sosten/src/lib.rs b/crates/sosten/src/lib.rs index 8d38997..fb69f20 100644 --- a/crates/sosten/src/lib.rs +++ b/crates/sosten/src/lib.rs @@ -27,6 +27,9 @@ baseplug::model! { #[model(min = 0.0, max = 1.0)] #[parameter(name = "dissipation")] dissipation: f32, + #[model(min = 0.0, max = 1.0)] + #[parameter(name = "direction")] + direction: f32, } } @@ -37,6 +40,7 @@ impl Default for SostenModel { length: 1000.0, manual: 0.0, dissipation: 1.0, + direction: 1.0, } } } @@ -53,6 +57,9 @@ struct Sosten { /// Period of the processed input /// We keep both so we can instantly switch period: Option, + + /// Keeps track of whether we are going forward while in cycle mode + forwards_in_cycle_mode: bool, } impl Plugin for Sosten { @@ -76,6 +83,8 @@ impl Plugin for Sosten { detector_thread: pitch_detection::PitchDetectorThread::::new(), used_period: None, period: None, + + forwards_in_cycle_mode: true, } } @@ -146,9 +155,38 @@ impl Plugin for Sosten { self.buffers.r[a] += (1.0 - diss) * self.buffers.r[(a + 1) % LEN]; // Loop index after we finish playing a section - self.buffers.idx += 1; - if self.buffers.idx >= len { - self.buffers.idx = 0; + if model.direction[i] > 0.6 { + // we are going forwards, so increase the idx + self.buffers.idx += 1; + // and loop at the end + if self.buffers.idx >= len { + self.buffers.idx = 0; + } + } else if model.direction[i] > 0.4 { + // we're in cycle mode + + // alternate directions at the end + if self.buffers.idx == 0 { + self.forwards_in_cycle_mode = true; + } + if self.buffers.idx >= len { + self.forwards_in_cycle_mode = false; + } + + // increase/decrease index + if self.forwards_in_cycle_mode { + self.buffers.idx += 1; + } else { + self.buffers.idx -= 1; + } + } else { + // we are going backwards, so loop first + // this ensures we don't do 0 - 1 + if self.buffers.idx == 0 { + self.buffers.idx = len + 1; + } + // then decrease index + self.buffers.idx -= 1; } } else { // If it's not on a repeat section, pass all the audio fully