Skip to content

Commit 630e897

Browse files
committed
Restore original slow lfo behavior; update README
1 parent b1c10f9 commit 630e897

File tree

4 files changed

+43
-65
lines changed

4 files changed

+43
-65
lines changed

stages/README.md

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,22 @@ Mutable Instruments Stages multi-mode firmware
22
==============================================
33

44
This is a unofficial firmware for Mutable Instruments Stages. It was originally created by joeSeggiola and started as a modification to let you enter and exit the "Ouroboros" mode (the **harmonic oscillator** easter egg) at runtime, while the module is powered on. Then, it evolved adding the ability to sequence harmonic ratios, enable slower free-running LFOs and providing a completely alternative mode that transforms the module into **six identical DAHDSR envelope generators**.
5-
This fork further adds bipolar modes for each segment type, re-trigger control for ramp segments, and restores v/oct tracking on slow-LFO mode while expanding slider range.
5+
6+
This fork further adds:
7+
8+
- **Polarity control for each segment type** (except non-looping ramp/green). Hold button and turn pot to control polarity (left = bipolar, right = unipolar). When bipolar, the segment will flash dull red about 1/sec.
9+
- **Re-trigger control for ramp segments**. Hold button and turn pot to control re-trigger behavior. When re-trigger is disabled, the segment will flash dull red about 1/sec.
10+
- **Independent LFO (clocked and free) range control for each segment**;
11+
- For free-running, ranges are the same as Tides: 2 min to 2hz at the slowest, 0.125hz to 32hz (default and Stages' original range), and 8hz to about 2khz at the fastest. As with the original Stages and Tides, this range is further expanded by CV.
12+
- For clocked, ranges are: 1/8 to 1 in low, 1/4 to 4 by default (as in original Stages), 1 to 8x in high.
13+
- Hold the segment's button and move its slider to change LFO range. LFO range is indicated by the speed of the mode indicator LED's cycle. Note: artifacts appear at high frequencies depending on wave shape. Frequency has been capped at 7khz (A8) as the module acts very strangely after that...
14+
- **Arbitrarily slow clocked LFOs**. Previously, clocked LFOs in Stages had a reset timeout at about 5 seconds; now, the reset timeout adapts to the clock cycle, allowing for arbitrarily slow clocked LFOs (logic taken from Tides 2).
15+
- **Track & hold support**. While you can [get track & hold with the original Stages](https://forum.mutable-instruments.net/t/stages-track-and-hold/16365/11), it takes 3 segments to do so. Now, a single, looping, gated step (orange) segments will track & hold. Single, non-looping, gated step segments still sample & hold.
16+
17+
For any settings that requires you hold the button to change, moving the slider or pot will disable loop mode changes or multi-mode changes, so you don't need to worry about holding th button for too long.
18+
Also changes to those settings won't occur unless you move it's respective control; thus, you won't accidentally change the range on an LFO while changing it's polarity unless you move the slider.
19+
If the slider/pot is already in the position of the setting you want, simply wiggle it to one side and then back into the desired setting while the button is held.
20+
After you release the button, you can then use the pot/slider as normal.
621

722
⚠️ **Warning:** This firmware has **not** been tested on multiple [chained][1] modules. It could behave strangely if chained. Obviously I'm not responsible for any issue you might encounter.
823

@@ -14,54 +29,40 @@ Download and installation
1429

1530
📦 Download the **[latest WAV file here][2]** and follow the [firmware update procedure here][3]. Source code is available [here][8]. joeSeggiola's original source code is available [here][9].
1631

32+
IMPORTANT: Installation will clear the module settings if coming from a different firmware. Right after updating from an earlier version of this fork, the stock Stages firmware or joeSeggiola's version, Stages may continuously cycle between green, orange, and red LEDs. Turning the module off and on again should restore functionality. This happens because this fork expands the amount of data stored for each segment, so will be incompatible with the settings stored from a different firmware. If you encounter problems, please let me know, either in a GitHub issue or otherwise.
33+
1734
[2]: https://github.com/qiemem/eurorack/releases/latest
1835
[3]: https://mutable-instruments.net/modules/stages/manual/#firmware
1936
[8]: https://github.com/qiemem/eurorack/tree/stages-multi/stages
2037
[9]: https://github.com/joeSeggiola/eurorack/tree/stages-multi/stages
2138

22-
23-
Usage
24-
-----
25-
26-
Hold one of the six buttons for 5 seconds to change mode. This setting is persisted when the module reboots. From left to right:
27-
28-
1. [Segment generator](#segment-generator)
29-
2. [Segment generator](#segment-generator)
30-
3. Segment generator with [slower free-running LFOs](#slower-free-running-lfos)
31-
4. [Six DAHDSR envelope generators](#six-dahdsr-envelope-generators)
32-
5. [Harmonic oscillator](#harmonic-oscillator), aka Ouroboros mode
33-
6. Harmonic oscillator with [alternate controls](#harmonic-oscillator-with-alternate-controls)
34-
35-
### Polarity and re-trigger control
39+
Core modification usage
40+
---
3641

3742
In the first three modes, each segment type now has both a unipolar and bipolar mode.
38-
When on a particular segment type, simply press the mode button again (short press) to access the bipolar mode.
39-
Bipolar mode is indicated by a dimmed LED.
40-
Thus, pressing the mode button now advances through six states rather than three, for both looping and non-looping segments.
43+
To make a segment bipolar, hold down its button and turn its pot above the halfway point.
44+
To make a segment unipolar, either press the button three times (changing type resets polarity) or hold down its button and turn its pot below the halfway point.
45+
When in bipolar mode, the segment will a dim red color about once a second (this should be visible regardless of base color or looping mode).
4146

4247
A bipolar ramp mode doesn't really make sense since ramps slide between the values of their neighbors.
4348
So, "bipolar" mode ramps instead prevents re-triggering if a trigger is received when that ramp segment is active.
4449
This allows you to make standard Maths like clock dividers by setting the first ramp segment to "bipolar".
4550
This also works on segments besides the first: for instance, set the D of an AD envelope to "bipolar" to prevent re-triggering on decay rather than attack.
4651

47-
Normal modes:
52+
Bipolar LFOs (single, looping green segments) output -5v to 5v. All other bipolar segment types output -8v to 8v.
53+
4854

49-
1. Bright green: Unipolar ramp.
50-
2. Dim green: Non-re-triggering ramp.
51-
3. Bright orange: Unipolar step, 0v to 8v.
52-
4. Dim orange: Bipolar step, -8v to 8v.
53-
5. Bright red: Unipolar hold, 0v to 8v.
54-
6. Dim red: Bipolar hold, -8v to 8v.
55+
Multi-mode usage
56+
-----
5557

56-
Loop modes:
57-
1. Bright green: Unipolar LFO, 0v to 8v.
58-
2. Dim green: Bipolar LFO, -5v to 5v.
59-
3. Bright orange: Unipolar step/S&H, 0v to 8v.
60-
4. Dim orange: Bipolar step/S&H, -8v to 8v.
61-
5. Bright red: Unipolar sustain, 0v to 8v.
62-
6. Dim red: Bipolar sustain, -8v to 8v.
58+
Hold one of the six buttons for 5 seconds to change mode. This setting is persisted when the module reboots. From left to right:
6359

64-
Hot tip: apply a negative voltage using a single ramp or hold segment to an LFO segment to increase period to 13 minutes.
60+
1. [Segment generator](#segment-generator)
61+
2. [Segment generator](#segment-generator)
62+
3. Segment generator with [slower free-running LFOs](#slower-free-running-lfos)
63+
4. [Six DAHDSR envelope generators](#six-dahdsr-envelope-generators)
64+
5. [Harmonic oscillator](#harmonic-oscillator), aka Ouroboros mode
65+
6. Harmonic oscillator with [alternate controls](#harmonic-oscillator-with-alternate-controls)
6566

6667
### Segment generator
6768

@@ -74,15 +75,10 @@ This is the standard mode of the module, refer to the official [Stages manual][4
7475

7576
### Slower free-running LFOs
7677

77-
Fork:
78-
79-
Stages behaves exactly like the standard segment generator mode, except that the slider range on free-running LFOs has been expanded to range from 8 minutes to C1 (the original high-end).
80-
CV input still tracks v/oct.
81-
Finally, ramp slider higher end has been increase from 32 seconds to about 58 seconds.
82-
83-
Original:
84-
8578
In this mode, Stages behaves exactly like the standard segment generator mode, except free-running LFOs (i.e. single green looping segments) are [eight time slower][5].
79+
This fork applies this 8x slowdown to each of the LFO ranges, so while the default is the same as in joeSeggiola's original, much slower LFOs may be achieved (16 minutes), while also mixing with faster LFOs.
80+
81+
Note: Since LFO range configuration has been integrated in as a segment configuration, this mode may be removed to make space for other things.
8682

8783
[5]: https://forum.mutable-instruments.net/t/stages/13643/54
8884

stages/chain_state.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@ void ChainState::HandleRequest(Settings* settings) {
524524

525525
if (request_.request == REQUEST_SET_SEGMENT_TYPE) {
526526
if (channel == request_.argument[0]) {
527+
s->segment_configuration[i] &= ~0xff00; // Reset LFO range
527528
s->segment_configuration[i] &= ~0b00001011; // Reset type and bipolar bits
528529
s->segment_configuration[i] |= ((type_bits + 1) % 3); // Cycle through 0,1,2 and set type bits
529530
dirty |= true;
@@ -540,6 +541,7 @@ void ChainState::HandleRequest(Settings* settings) {
540541
new_loop_bit = 0x4;
541542
}
542543
}
544+
s->segment_configuration[i] &= ~0xff00; // Reset LFO range
543545
s->segment_configuration[i] &= ~0b00000100; // Reset loop bits
544546
s->segment_configuration[i] |= new_loop_bit; // Set new loop bit
545547
dirty |= new_loop_bit != loop_bit;

stages/cv_reader.cc

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -77,30 +77,6 @@ void CvReader::Read(IOBuffer::Block* block) {
7777

7878

7979
float slider = lp_slider_[i];
80-
if (settings_->state().multimode == MULTI_MODE_STAGES_SLOW_LFO) {
81-
const ChainState::ChannelState *state = chain_state_->local_channel(i);
82-
if (state->configuration().type == segment::TYPE_RAMP) {
83-
if (chain_state_->loop_status(i) == ChainState::LOOP_STATUS_SELF) {
84-
if (!state->input_patched()) {
85-
// Free running LFO; input is frequency
86-
// Base freq is 2.0439497; semitones are relative to that
87-
// -120 semitones is thus about 8 minutes and 120 semitones is about 2093hz=C7
88-
// -128 is lowest and 127 is highest
89-
// Original goes from -48 (~6 seconds) to 48 (C1)
90-
const float slider_max = 48.0f / 96.0f + 0.5; // C1
91-
const float slider_min = -84.0f / 96.0f + 0.5; // 1 minutes
92-
slider = (slider_max - slider_min) * slider + slider_min;
93-
}
94-
// Leave tap LFO the same
95-
} else {
96-
// ramp; input is time; negative values don't make sense
97-
// 1.0f -> 32sec
98-
// 2.0f -> ~19min; these seemed waaay to sensitive in practice
99-
// 1.25 -> ~58sec, which is about what a Maths linear stage is
100-
// slider = 1.25f * slider; // Felt too sensitive.
101-
}
102-
}
103-
}
10480
uint16_t seg_config = settings_->state().segment_configuration[i];
10581
if (is_bipolar(seg_config) && (seg_config & 0x03) != 0) {
10682
slider = 2.0f * slider - 1.0f;

stages/segment_generator.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,10 @@ void SegmentGenerator::ProcessFreeRunningLFO(
398398
break;
399399
}
400400

401+
if (settings_->state().multimode == MULTI_MODE_STAGES_SLOW_LFO) {
402+
frequency /= 8.0f;
403+
}
404+
401405
for (size_t i = 0; i < size; ++i) {
402406
phase_ += frequency;
403407
if (phase_ >= 1.0f) {

0 commit comments

Comments
 (0)