Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Determine correct envelope behaviour #1

Open
hornc opened this issue Mar 6, 2021 · 10 comments · Fixed by #10
Open

Determine correct envelope behaviour #1

hornc opened this issue Mar 6, 2021 · 10 comments · Fixed by #10
Assignees

Comments

@hornc
Copy link
Owner

hornc commented Mar 6, 2021

I'm not 100% sure I have the envelope behaviour correct.

The first version of the envelope I have created takes two T1 durations for attack, and decay

It would make more sense to take 3, attack, sustain, and decay.

If an envelope only receives two wait durations, is decay = 0?

That probably makes more sense than Attack, Decay, and Sustain 3rd.

The confusion arises from the one clear example of an envelope being specified with only
two levels and two durations

O1 56 A1 12 E1 13 T1 14 E1 7 T1 1

This physical EMS envelope shaper should help sort out the likely parameters: https://djjondent.blogspot.com/2015/03/ems-synthi-envelope-generator.html

UPDATE to test:

./musysim.py  <(echo -e "O1.56. A1.12. E1.13. T1.14. E1.7. T1.1.\n$"); ./sofkasim.py | ny

the original syntax (from a blog post) does not have the . separators which are required by MUSYS.

@hornc
Copy link
Owner Author

hornc commented Mar 6, 2021

I'm now thinking I got it wrong by assuming the E1 parameters were levels, they are more likely durations: the attack time 13 is applied over the following wait time 14, then the decay time of 7 is applied over the following wait time of 1. I think this means the sound is cut off before it has decayed to 0.

@hornc
Copy link
Owner Author

hornc commented Mar 6, 2021

And this from the same source: https://djjondent.blogspot.com/2020/10/ems-synthi-e-trapezoidal-envelope.html?m=1

This suggests:
Attack, On, Decay, Off but with the wait timer T1 controlling the actual time taken

Min(E1a, T1a) + On = T1a
Min(E1b, T1b) + Off = T1b

To specify a trapezoidal envelope with two envelope parameters and two wait parameters.

Will need to implement this to see how it compares.

@hornc
Copy link
Owner Author

hornc commented Mar 8, 2021

This is how I'm interpreting E1 13 T1 14 E1 7 T1 1, which may still be incorrect (but will do for now, until I get more examples working):

image

I'm assuming for the moment that the T1 wait timer is the thing that sets actual durations of the real time system, so in the same way the O1 56 T1 15 would play a tone for 0.15s, E1 13 T1 14 plays a 0.13s attack for 0.14s , (so 0.01 s of sustain) then E1 7 T1 1 plays a 0.07s decay for only 0.01s, stopping the sound before it is fully silent.

I do not know enough about the Synthi 100, or how MUSYS interfaced with it, to know whether this is correct. A simpler approach would be to take E1 13 T1 14 E1 7 T1 1 to mean 0.13s attack, 0.14s sustain, 0.07s decay, and 0.01s off, which is more akin to what the Sythni AKS' physical controls enable. It's a simpler shape though, a simple trapezium with attack to full level and decay to 0 only. The other way allows for non full-signal shaping, and sudden cut offs after partial decays. And after overthinking this, I remembered the explanation in the blog states:

"This note has pitch 56 (chosen from an eight-octave chromatic scale with notes numbered from 0 to 63), loudness 12 (on a logarithmic scale from 0 to 15), and duration 15/100 = 0.15 seconds. The loudness value also determines the envelope of the note."

So I think this makes sense -- an envelope shaper must have a sensible mode of operation with attack=0.13s, decay=0.07s, yet a full duration of only 0.15s

@hornc hornc closed this as completed in ce1679e Mar 8, 2021
@hornc
Copy link
Owner Author

hornc commented Mar 11, 2021

Reopening as I'm not completely happy with the current envelope behaviour (described above).

Now that I have sound examples playing, the NOTE macro notes tend to sound a bit 'clicky' with the sudden cut-off. Unsure if that is a problem with the macro, or the envelope parameters should fundamentally prevent such a sudden note-stop mid decay. (which seems to be the behaviour of the physical EMS synth trapezoidal envelope). I'd appreciate guidance from any audio / synth people out there who happen to stumble upon this project.

Alternative approaches references the above diagram:

  1. Some kind of blend into the next note: next sound starts 0.01s into the decay, but the decay overlaps for 0.06s. (this seems a bit forced?)
  2. The decay lasts for 0.01s, and there is a silent OFF portion for 0.06s. While this seems closest to the trapezoidal envelope behaviour, I don't like it because it swaps the semantics of the T and E values for the second pair, and it seems too long for the provided example 🤷
  3. Hack in a rapid fade so the sound cut-off is sudden, as in the waveform above, but avoids a digital click... hopefully better approximating an analog switch-off

@hornc hornc reopened this Mar 11, 2021
@hornc
Copy link
Owner Author

hornc commented Mar 11, 2021

To investigate: clicking may be caused by the envelope getting out of sync with the corresponding pitch. Drift?
Some of the longer outputs show this, most noticeable on transitions between low and high pitches.

@hornc
Copy link
Owner Author

hornc commented Mar 24, 2021

Test further on examples/random-tone-rows2.musys the clicks seem to get more noticeable as the tune progresses. The envelope does seem to get out of sync with the notes. The precision of timings needs to be fixed in sofkasim. Nyquist has a default resolution (which can be adjusted), but the current code takes none of this into consideration. Investigate and tidy, it may solve this sync problem.

@hornc
Copy link
Owner Author

hornc commented Aug 14, 2021

To test before closing:

  • Example of an extended single tone with multiple envelopes
  • Example of multiple tone transitions under one envelope

Both of these examples would not have been possible under #7

@hornc hornc self-assigned this Aug 14, 2022
@hornc hornc mentioned this issue Aug 16, 2022
3 tasks
@hornc
Copy link
Owner Author

hornc commented Aug 16, 2022

Coming back to this some time later....

This page is still relevant: https://djjondent.blogspot.com/2015/03/ems-synthi-envelope-generator.html

First sentence: "In the EMS world what we normally refer to as the Envelope Generator is called a "Envelope Shaper". There is a good reason for this as it's definitely not your usual ADSR. "

From the Gorgono article: "The device E1 (an envelope shaper), controls both the
attack and the decay of the note."

So the terminology matches, and appears significant.

E1 13 T1 14 E1 7 T1 1
  • attack : 0.13s
  • on-time : 0.14s
  • decay : 0.07s
  • off-time : 0.01s

Total duration: 0.35s

This seems pretty sensible and straightforward. I'm not sure why I got so confused previously. I think I was trying to meld standard ADSR and clues in the MUSYS spec. It seems highly likely that this system was controlling a physical EMS synth with exactly this trapezoidal enevelope shaper.

@hornc hornc closed this as completed in #10 Aug 18, 2022
@hornc hornc closed this as completed in 4e4ea57 Aug 18, 2022
@hornc hornc reopened this Apr 29, 2024
@hornc
Copy link
Owner Author

hornc commented Apr 30, 2024

Updated thoughts on MUSYS envelope control:
(This feels like a blog post buried at the end of a github comment thread where I've been talking to myself for a ridiculous number of years. Maybe I'll reuse this text someday. I hope someone finds this interesting at some point!)

  • The main / only documented examples of E1 usage are via the same NOTE macro (blog and 1973 paper), with multiple ways of using it, but still only via the one macro.
    Both printed/typed examples I have seen miss required . symbols in different locations, but the corrections seem uncontroversial:

    NOTE O1.%A. A1.%B. E1.%B/2+7. T1.%C-1. E1.%B/2+2<7. T1.1. T=T+%C @
    
  • The notable features of the NOTE macro are:

    • 3 arguments: A = note pitch, B = "loudness and envelope", C = duration
      • A is fine (pitch) and uninvolved in envelope shaping. There are other examples of O1/O2 used without an envelope shaper and with just T1 to set duration.
      • B is confusing, how and why are "loudness and envelope" related? In all NOTE usage examples B is limited to 15 and lower, which appears to be a requirement for the amplifier device, and makes sense for A1. The arguments to E1 are functions of this 0-15 amplification value. Is this significant and B represents some kind of amplitude level used in shaping? (spoiler: no)
      • C seems pretty clear: the note will last exactly for C T1. intervals. This is reinforced by the T global variable which accumulates the total duration of all notes generated by the NOTE macro. T is never used in any of the examples, but it makes sense why it might be useful for the composer to track this.

!!! It seems clear my current implementation of envelope shaping is wrong, because the values passed to E1. contribute a significant variation to the note duration, making T useless, and breaking the assertion that the only argument that affects the duration of NOTE is C, which is split into two arguments to T1: C-1, and 1.

Clearly whatever the arguments to an envelope shaper represent, they cannot affect the duration or the timing of the played note, only the envelope.

This makes sense in that if an envelope shaper were turned off, or removed from the signal path, a MUSYS composition would have the same duration, and note transitions would occur un-shaped, but at the same times. Similarly if all E1 statements were removed from the code, the composition would still have the same timings.

EMS envelope shapers and terminology seem a bit confusing and idiosyncratic, and it depends on exactly which bit of gear is being discussed.
EMS envelopes all seem to be some kind of trapezoid, and differ from ADSR envelopes. They have their own terminology and there are at least two flavours of trapezoid, with a different ordering:
Attack, On, Decay, Off (Synthi AKS, see very helpful blogpost: https://djjondent.blogspot.com/2020/10/ems-synthi-e-trapezoidal-envelope.html) or Delay, Attack, On, Decay (Synthi 100, via https://whitefiles.org/rwz/zxe/1971_synthi_100.pdf ), which produce the same kind of trapezoid, but effectively switch the 'Off' from the beginning (Synthi 100 Delay), to the end (AKS Off).

In a MUSYS context, the Synthi 100 seems more relevant, but from digging deeper it seems very dependent on specific configurations, switches, and the whole EMS synth (AKS at least) envelope shaper is complicated with the pretty neat VCA Off control which allows the shaper to re-trigger and act as a signal source. The synths expect a gate trigger from say a keyboard, and have 6 control knobs involved in setting all the parameters... none of this seems directly relevant to MUSYS, and I can't see how to directly represent 6 analog control knobs with two parameters passed sequentially to the E1 device.

However, it seems clear that E1 should produce a trapezoid envelope with only two calls to E1, for a duration set entirely by arguments passed to T1.

The E1 calls are documented as setting attack and decay, which suggests the parameter switches (alternates?) between attack and decay each time it is called.

Roughly quoting from the 1973 MUSYS paper, with inline NOTE macro commands:

select pitch and waveform[O1] ... use an envelope shaper to start the attack cycle [E1] [1ms to 1sec...] during which the amplitude of the note increases from zero to full intensity),
wait for a time [T1] then initiate the decay cycle [E1] (10ms to 10s during which the amplitude decays to zero. [ OFF T1 ]

This sounds like the AKS Attack, On, Decay, Off trapezoid, and does line up with the device commands we see in NOTE, if the first T1 spans Attack + ON, and the second T1 covers Decay + Off.

The inclusion of the specific but different ranges for attack and decay illustrate that whatever the value passed to E1, it is device specific. The Synthi 100 brochure suggests all 4 parts of the trapezoid form can range between 2ms and 20s... if the overall duration is set by the pseudo-device T1 timings, MUSYS doesn't need to care about the exact specifications.

My mistake previously was to assume and desire that, if the argument to E1 was a duration, it should be in the same units as the main timing device T1 -- this seems totally un-justified. T1 and E1 are different devices, and their parameters are not directly related.

The NOTE macro reusing the B amplitude parameter to set envelope durations seems like a feature of NOTE only, and the range limited durations, functions of 0-15, give the NOTE instrument its character (of fast attacks, and mathematically related decays). The amplitude / envelope relationship is entirely due to this specific code, and it implies nothing fundamental about E1 or amplitudes being used to shape the signal.

I'm now going with the theory that the arguments to E1 represent attack and decay durations, limited by the particular range of the specific envelope hardware device and its current configuration. I'm also assuming it can use the full 6bit range of the argument. This is not stated anywhere, but the amplitude control 0–15 is mentioned, and this seems like an exception. It seems odd to span a range of 1–1000ms in only 15 steps. From looking at all the physical synth controls ranging from 0–10 (11 if you are lucky), meaning slow -> fast, less -> more, and the exact units depending on what is plugged in, and the temperature of the room or whatever, there is likely some device specific variability in exactly how this is done. I'm going to go with a log scale to map 0–63 to attack_minattack_max.

Plugging in the possible values arising from B using the 1973 paper's TUNE macro (which in turn uses NOTE) all notes in that tune are split into two fixed duration T1 parts: 300ms + 100ms. Using a linear division of attack 1–1000ms, decay 10–10000ms the arguments to E1 can exceed those 300ms + 100ms durations. Using a basic log scale, they always fit neatly, so the TUNE and NOTE macros are consistent with this type of device implementation.

Here is a Python function to convert a 6 bit device argument n into an attack time in ms with a log control:

def attack_ms(n, min_=1, max_=1000):
    return n**2 * (max_ - min_)/(63**2) + min_

0 -> 1
5 -> 7.29
32 -> 258.74
60 -> 907.12
63 -> 1000

Different devices could have different ranges, different order of Delay/Off, different curves, even be linear, or perhaps re-configurable during a performance. This all seems like a feature of the MUSYS / synth system.

Ironically, this envelope control system seems remarkably close to the simpler Synthi E's two sliders for attack and decay, with the duration set by the gate durations, and specifics determined by mode switches (described https://djjondent.blogspot.com/2020/10/ems-synthi-e-trapezoidal-envelope.html ). Previously I hadn't even considered the Synthi E as relevant to MUSYS. It seems the MUSYS hardware config and interface is its own thing, and relying on specific details of how something works on the Synthi 100 can be misleading.

Now I have to update the existing code to implement this new envelope logic and correct timing, then test the existing code examples still sound like something before getting proper signal paths and correct mixing working for multiple sound sources, their treatments, and across all 6 command buses...

@hornc
Copy link
Owner Author

hornc commented May 7, 2024

Test cases for the above, (current timings @ 131adc2):

Are the timings for the tune macros really for each note to last 4 intervals?
TUNE2 sets T3 (clock rate) to 16 interrupts/sec.
TUNE uses the default (currently set to 100 interrupts/sec), it's not clear how long each note is supposed to last from the paper. The blog does not make use of the TUNE macro.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant