Open hornc opened 3 years ago
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.
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.
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):
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
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:
T
and E
values for the second pair, and it seems too long for the provided example :shrug: 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.
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.
To test before closing:
Both of these examples would not have been possible under #7
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
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.
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:
!!! 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 _attackmin–_attackmax.
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...
Test cases for the above, (current timings @ 131adc2df07c8b37563e6274a53db1ced6fccbb4):
https://github.com/hornc/musysim/blob/master/examples/note.musys should produce a sound duration = 15 intervals, 0.15s (currently 0.34s)
./musysim.py examples/note.musys; ./sofkasim.py -d | ny
https://github.com/hornc/musysim/blob/master/examples/tune.musys 5 * 4 intervals @ 100 interrupts/sec = 0.2s (currently 1.19s)
./musysim.py examples/tune.musys; ./sofkasim.py -d | ny
https://github.com/hornc/musysim/blob/master/examples/tune2.musys 5 * 4 intervals @ 16 interrupts/sec = 1.25s (currently 7.438s)
./musysim.py examples/tune2.musys; ./sofkasim.py -d | ny
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.
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
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:
the original syntax (from a blog post) does not have the
.
separators which are required by MUSYS.