SynthMaker

simple decay control

Archive · 2012 27 old posts

From the original SynthMaker forum (2004–2014), with its members’ names and dates.

tester ·

I'm looking for simple decay solution, controlled by manual trigger (i.e. a way of making "dong" sounds with fade/release from max to zero). The decay module in SM toolbox seems to not react to typical triggers in order to activate/reactivate the fading. What I'm missing?

Another thing - would look for non-linear fading envelope plus long fading times (like 30-300 seconds), but I guess I can do that using some graph curves present on the forum, converted to arrays and triggered with counter via dezipper. But I'm looking rather for simple and effective solutions, with no complexity inside and no (known) issues.

trogluddite ·

It is possible to get the schematic that you posted working - there are two things to fix...

1) The envelope will need the "Trigger" property ticking to work with mono/mono4 signals - by default it is only in "automatic mode" for triggering only by messages from the poly voice manager.

2) Green boolean direct into stream boolean doesn't work... There is a fundamental inconsistency in the way that numbers/bools work between green and float - leading to just the kind of unexpected results as you have found. You will already have seen how the green parts will freely convert between float, integer and boolean data types. In green, a boolean false = zero, and boolean true = one. When converting from float/integer, any non-zero value will convert to true. When these green values are connected to a code/assembly box, however, all those data types are automatically turned into float format - so inside the code, a green bool true -> float one, exactly what you would find if you plugged on into a normal "streamin". However Stream boolean is not zero and one - the "false" value has all 32bits turned off (still zero), but "true" has all 32bits turned on - which is not a real number (hence the special connector type). This is handy in code, because bitmasks are used a hell of a lot for any kind of switching and decision making - being able to pass bitmasks directly between modules saves some CPU compared to checking for the value 1 all the time. Connecting a green bool to stream leaves the expected bitmask incomplete, badly interfering with any bitwise "&" operations inside the code.

Fortunately this is also easily overcome - you can convert the green bool into s stream bool with this short code...

streamin GreenBool; streamboolout Out; Out = (GreenBool != 0); //Non-zero to true bitmask.

Now, having said all that - a custom envelope code may still be a better solution. The stock decay is strictly linear, and overcomplex (because of parts required for poly). All we need here is a way to set a value of one when triggered, and a way to iteratively make that number smaller. Here's a nice simple exponential decay...

streamin Trigger; //Green bool will work here streamin Factor; //Decay control (0 ... 1) = (short ... long) streamout Envelope;

float OldTrigger=0; float Small=1e-020;

// Iterate Envelope = Envelope * Factor; //Decay Envelope = Envelope & (Envelope>Small); //Kill de-normals

// Set to one on leading edge of trigger pulse Envelope = Envelope + (1-Envelope) & (Trigger>OldTrigger); OldTrigger = Trigger;

The decay control will need some scaling in green, as it is simply a feedback control, so you'll be needing number closely approaching one for practical decay lengths.

tester ·

1) The envelope will need the "Trigger" property ticking to work with mono/mono4 signals - by default it is only in "automatic mode" for triggering only by messages from the poly voice manager.

I'm still lost? "Trigger property ticking" ? Where and what to change?

I tried second example, but I'm afraid that I don't follow it yet. "Factor" values below 1 are soundless, and =1 just produce continuous (or just verly slow fading) sound.

p.s.: Generally I would need something, that allows to retrig the fade from 1 down - during ongoing fading too.

Help 😉

trogluddite ·

tester wrote: 'm still lost? "Trigger property ticking" ? Where and what to change?

You will need to click the little "P" symbol at the bottom right of the module to open the properties, then check the appropriate box (will be labelled either "Trigger" or "Gate").

tester wrote: I tried second example, but I'm afraid that I don't follow it yet. "Factor" values below 1 are soundless, and =1 just produce continuous (or just verly slow fading) sound.

p.s.: Generally I would need something, that allows to retrig the fade from 1 down - during ongoing fading too

This one will retrigger at any point during the decay - but as I hinted before, you will need a "Factor" very close to 1 - the scaling happens 44100 times a second, so even a ratio of 0.9 will decay to nothing in a fraction of a second. I have used before somewhere a little module for scaling the ratio from a 0-1 knob to give meaningful time - I'll see if I can find it for you and post it up, it will make things much moe manageable.

tester ·

Ah - my english failed. 🙂

cyto ·

You can use this formula for finding the appropriate factor:

(endValue/beginValue)^(1/samples)

if you are always going to be decaying from 1, than obviously it is endValue^(1/samples).

In trog's above example, the endValue is 1e-020, so a one second decay at 44100kHZ, would need a factor of .9989562888. (or 1e-020^(1/44100)). Hope that helps.

-cyto

trogluddite ·

tester wrote: Ah - my english failed. 🙂

It is phenomenally more successful than my zero knowledge of Polish!

cyto wrote: (endValue/beginValue)^(1/samples)

Thankyou Martin, I had a feeling it wasn't anything too complicated.

I also found the scaler from the old schematic that I used - very similar power function, but I think this one was scaled for a different end value. My end value of 1e-20 in the code is just an arbitrary very small number to eliminate de-normals - it is way below the threshold of hearing, so the "audible" part of the envelope may seem a bit short when calculating to that end point. The equation used in my schematic is...

e ^ ( (-1000 / SampleRate ) / MilliSeconds) ...where e is Euler's number (about 2.71828).

That seems to give a fairly natural feel to the scale of the knob. As an exponential decay, it's kind of hard to say what the most appropriate end point would be anyway - but experimenting with that equation, I found that a decay of around 20-30sec is the maximum possible before you reach "saturation" of the float number (resulting in no decay). However that could easily be extended by hopping the code - the decay time would multiply linearly with the hopping factor, so decay times of hours could easily be achieved.

The schematic with that scaler module in is this Complex Integrator. (module "exp") - the schematic is a kind of combination sin/cos oscillator (quadrature) and envelope, all in one.

cyto ·

trogluddite wrote: Thankyou Martin, I had a feeling it wasn't anything too complicated.

I also found the scaler from the old schematic that I used - very similar power function, but I think this one was scaled for a different end value. My end value of 1e-20 in the code is just an arbitrary very small number to eliminate de-normals - it is way below the threshold of hearing, so the "audible" part of the envelope may seem a bit short when calculating to that end point. The equation used in my schematic is...

e ^ ( (-1000 / SampleRate ) / MilliSeconds) ...where e is Euler's number (about 2.71828).

He he. I know there are a lot of "Martins" on this board, but I am not one of them 😉 Though, I understand the confusion, because I (umm) borrow a lot of martinvicanek's work. Regarding the Euler approach: I have used this myself in the past for certain exponential envelopes but I believe that to be fully workable, you need to incorporate a "feedback arm" into the mix. Generally, I have used the coefficient 2PI*normFrequency (which involves a intermediate calculation to put the time period into terms of Hertz) and then have used the transfer function out=in(1-coeff)+out(coeff) where in is the starting value (one in this case). (This is from memory, BTW, have not tested - i may have gotten the mults mixed up). In that case, you're essentially using a simple LPF to achieve the envelope. I think in tester's case, where you just need a simple exponential decay, this may be overkill, but there are certainly cases where you are moving between different values where this may be more appropriate. I guess it all depends on the situation.

-cyto (Brad)

tester ·

I just want to make an approximate simulator of unusual instrument made of bronze alloys (bowl) that fades veeeery slowly after being hit (usually >30 seconds). For example one of my own units (2kg, c.a. 30cm diameter) fades for about 5 minutes after 1 hit 😉. Not too cheap business anyway. Such instrument is "made" of several frequency bands, which fade differently however. What I need - is a manual control of that fading times. Fading type is between linear to a little bit indented (exp), so it would be good to have some control over that too (I guess - simple input with range "from/to" would be enough).

trogluddite ·

cyto wrote: He he. I know there are a lot of "Martins" on this board, but I am not one of them

He he, sorry mate - I got myself all confused during the search for that schematic - it was an interesting journey via a many great schematics of yours and martin's (I blame it on all those imaginary numbers - they always made my head hurt!).

tester wrote: unusual instrument

I'd love to hear a sample of that! Just last week, I was watching a rather odd band (Volcano the bear) who use both conventional and home-made instruments. A section of their set was nothing more than each of the two performers hitting large metal "goblets" - and what a sound! One alone had a beautiful tone - but they played with the goblets in such a way to make constantly changing inter-modulations and beat frequencies from the two tones. The amount of control they had over this was amazing - I have never heard anything using detuned synth oscillators that comes close to that experience. Such long sounds will ideally fit the use of code hopping - with the nice side effect of much lower CPU load too - so the ability to control many envelopes simultaneously. and to have a bit more complexity in the code for extra features (e.g. linear vs. exponential control etc.). Near bed time now, but I have a few idea I may tinker with tomorrow...

tester ·

Regarding singing (not crystal which are different type of) bowls I go in three directions. Record live sessions, sample instruments and make soundspaces, or - process the pre-made soundspaces. The results: check this playlist for example (all except APR and some last from the bottom; but the APR is another interesting story for which I'd like to create proper filters in SM if possible instead of using offline CE processing) or visit bandcamp. Some are better with headphones.

cyto ·

hey tester,

see if this example is close to what you want...

You can change it's "profile" by inputting the midpoint value of the decay (in dBFS). Also you can enter in a hop value to save CPU resources (make sure you make the appropriate change to the code). You should be able to get extremely long decays, because this uses a 'counter' instead of a mult factor. Anyway, see if you like it 😉

-cyto

tester ·

I check it tomorrow. Exhausted 🙂 Too much SM thinking. But from what you write - this should be it. Thanks.

tester ·

Okay, just tested, and this is it. But now things get a little bit more complicated. Cyto - could you add something to the code that would allow to set very short and smooth transition on retrig? Sizes in miliseconds (<5 ms I guess). The thing is - when envelope is retriggered, then transition tends to produce noticable "digital click". I'd like to make it more like analog soft hit, and I guess this is the direction (correct me if I'm wrong).

p.s.: when duplicated many times in the schematic (like 4x12) - SM becomes unstable and crashes often (I'm thinking to reach a target with c.a. 10x30 different envelopes) - to which part of the code could it be related? Is it possible to make some performance improvement by producing envelopes based on one main theme? (i.e. ratio based time lenght, so results of main code would be just scaled somehow?)

cyto ·

tester wrote: Okay, just tested, and this is it. But now things get a little bit more complicated. Cyto - could you add something to the code that would allow to set very short and smooth transition on retrig? Sizes in miliseconds (<5 ms I guess). The thing is - when envelope is retriggered, then transition tends to produce noticable "digital click". I'd like to make it more like analog soft hit, and I guess this is the direction (correct me if I'm wrong).

Okay, that's no problem. Here's a new version. It's exactly the same as the first except I just put a simple little lowpass filter on the output to smooth the transitions. Notice that I had to put it outside of the "hop" routine. Something like this wouldn't work inside the routine because of the inherent "jaggedness" of the "hopping". The good news, though, is you could conceivably make the hop value even larger because the LPF will smooth out any of the pronounced "steps" that the larger value would introduce. You can adjust the nominal transition time to your tastes.

tester wrote: p.s.: when duplicated many times in the schematic (like 4x12) - SM becomes unstable and crashes often (I'm thinking to reach a target with c.a. 10x30 different envelopes) - to which part of the code could it be related? Is it possible to make some performance improvement by producing envelopes based on one main theme? (i.e. ratio based time lenght, so results of main code would be just scaled somehow?)

Hmmm. I'm not sure about this one. My first guess would be that maybe having the same module copied so many times might cause some issues with SM trying to accommodate the same variable names over and over. But this is just a guess. There really isn't anything out-of-the-ordinary going on in the code. It's pretty straightforward. I think that ultimately, the solution will involve incorporating all of the envelopes into one block of assembly. That way, we can take advantage of "interleaving" the hop routines and we can "share" values between them. When you figure out what configuration you ultimately would like, e-mail me a "wish-list" and I'll see what I can do. If you lost my e-mail address, just PM me.

-cyto

tester ·

For simulating single unit - c.a. 10-16 independent envelopes are required (envelopes per one click/trigger - this number is static). For making a soundscape created from sets - c.a. 30-40 independent units are required (thus - triggered envelope sets), depending on simulation complexity (this number is dynamic). So I guess, maximum reserve/margin for unexpected ideas - would be a matrix of 16x48 envelopes, but minimum are required 10x32 envelopes. I hope this info helps in organizing code.

Second thing to figure out here will be some efficient and stable sine generator (I just started to explore this thread) with phase offset node and optional resync/reset for other experiments (I mention that, because I don't know how to include these nodes), 2 x total amount of envelopes. SM sine is just too much CPU consuming. Phase offsets are the key for many wonderful (and painful) things in sound creation 😉

Everything else should be achievable with primitives, I guess.

Regarding stability of SM you might be right, because I experienced such crashes before, and noticed that they probably had to do with code boxes.

tester ·

Just tested the modified version of fade control, and this is perfect for my simulations, thanks. Regarding stability issues, I noticed interesting thing. There seem to be no such problem when duplicating sine oscillators made with asm/code boxes. After duplicating dozens of them (performance tests - heaviest simulations will take c.a. 60-90% od C2D 2GHz CPUas far I can see) - nothing happens, everything works fine. So my guess is, that SM has some problem only with certain operations performed in asm/code box (exported exe seems to be more stable than schematic).

trogluddite ·

Don't know if it will help much, but here is an assembly optimised version of Cyto's envelope (the algorithm is identical)...

It eliminates a "temp" variable or two, and makes better use of registers to avoid so many reads/writes to memory (variables). Using assembly also allows for hops to be "staggered" so that not all modules call the hop routine on the same sample. Just change the value in the commented code line ("cmp eax,0;") to any other 0...255 integer - this sets which sample of the hop "loop" is executed. The way that caching and branch prediction work in modern CPU's is very complex, so whether the ASM will allow greater stability or significantly lower CPU is not certain - but I thought it might be worth a try to squeeze the maximum efficiency out of the code to see if it makes a difference.

I must admit, I have never encountered this same instability problem, even with my largest schematics (oddly, I have a problem where the very smallest schematics crash my audio driver!!). The fact that many modules are identical should make no difference, as variables (memory footprints) are always local to each module - though in theory, greater numbers of hopped modules will make the CPU's caching and branch prediction have to work a lot harder, with some impact on performance. It's also possible that SM has an upper limit on the memory space available for variables etc. In that case, I would expect crashing immediately after copy/pasting new parts, rather than in the middle of a "run-time" session.

If your schematic is designed to use mono rather than poly signals, the best performance enhancement will be to use mono4 - you will then only need 25% of the modules, with significant CPU savings. Although there is some overhead from the need to "pack" parameters, this will be largely offset by much more efficient use of the CPU cache and branch prediction for the hop "jumps" commands. - and packing can also be hopped with some simple assembly routines (I will post these in my "Toolkit" when it is ready).

tester ·

Thanks for mod.

Maybe you right, that this has to do with audio driver? I don't know. With my previous app, I had initially similar hang problems inside SM, but never on exported exe. I usually did tests on exported exe, so this is maybe the case (right now I'm experimenting live, in order to hear - what can I expect).

With mono4 you mean for mixing outputs with envelopes and outside the modules, yes? Because everything else will have separate frequency/phase and gain/mix control, just parametric (ratio based) but independent. The major concept here is to express real/subtle but signifficant nuances that appear in the sound of an instrument (or set of them).

trogluddite ·

I think that the independence of mono4 channels is maybe greater than you think (apologies if I have misread). When the oscillator/envelope etc. is used with mono4, you get effectively four independent modules. The only thing explicitly shared is the order of program instructions. Parameter values can be completely independent for each of the four channels. This is why the "value & (comparison)" technique must be used for switching operations etc. - it preserves the processing order in a way that using branching (if/then, goto etc.) would not. As the "&" bitmask is itself an "four way independent" parameter, this allows each channel to still have independent switching,triggering etc. If you have a chain of code/asm modules which is repeated (e.g. every ocillator has its own envelope), then the mono4 "bus" of parameters can often be passed directly without conversion back to mono. This example is probably clearer than my words...

The two alternative designs in the example are functionally identical - four chains, each of two modules, with zero "crosstalk" between each of the four paths.

Note though, that is it possible in assembly (not in code), to use (abuse!) the four channels in ways which do not use this normal SM "standard" - but this is pretty rare, and most people will make it very clear when a module is not suitable for mono4 or poly operation. There are also a handful of exceptions with SM stock primitives - e.g. a wavetable oscillator has mono4 independent frequency/phase etc. but all four channels must share a single "mem" wavetable.

tester ·

I see. So, to clarify - my scenario here is following. Let say, that I have 4 freqs which are sent to 4 sine units. 4 phase offsets are sent to these 4 units too. 4 outputs have independent gain and mix control. After that (not before, yes?) - I can put them into mono4. Then mix the mono4 with common envelope for that set. And send to main output. If main output receives multiple mono4 units, then all ID-1 will be mixed with other ID-1, 2 with 2, 3 with 3, 4 with 4. And if there will be some amplitude modulation added to output (mono4 part), then the similar goes there (1-1, 2-2, 3-3, 4-4). Am I correct?

I have it still in my head yet, so sorry for no osm 😉

p.s.: is it my impression or your modification on decay has different fade times than custom parameter (visually behaves as if it was much slower fade)?

trogluddite ·

tester wrote: Am I correct?

Yes, that sounds pretty much right - in effect, we are just mimicking the way that SM uses the individual channels to create poly voices. Couple of other things that may help when distributing parameters...

- If you put a "green" value directly into a mono4, the value is received by all four channels. This saves having to use a "Pack" when you really do want all four channels to see the same value (e.g. common sample rate etc.).

- If you have a blue mono signal that needs to be sent to all four channels of a mono4, the usual way is to feed the mono into all four inputs of a Packer. However, there is a short assembly block that will do this using much less CPU...

monoin In; streamout Out; movaps xmm0,In; shufps xmm0,xmm0,0; //Broadcast channel [0] to all channels. movaps Out,xmm0;

tester wrote: modification on decay has different fade

It should behave identically to Cyto's original, so possibly I made a slight error when converting to assembly - I'll double-check the code to see if I did anything silly.

tester ·

I'm looking at your small code, and... is there a way to transmit green/blue to a single specific channel that is inside a mono4 pack?

trogluddite ·

tester wrote: is there a way to transmit green/blue to a single specific channel that is inside a mono4 pack?

There is now... 😉

tester ·

Well - it should simplify some things, thanks. Just from curiosity - SM oscillators when receiving mono4 streams - they react only to the first channel, yes?

cyto ·

tester wrote: Well - it should simplify some things, thanks. Just from curiosity - SM oscillators when receiving mono4 streams - they react only to the first channel, yes?

No, they can generate 4 separate oscillations. I think you project will certainly benefit from exploiting this fact. It sounds like you are going to have many, many oscillators running independently and if you use all four SSE channels, you can effectively cut the CPU to 25% of just using mono streams. I'll work up an expanded envelope (as promised) soon. I need to get through one exam early this week and then I'll have some time to devote to it. I am confident that by using a combination of "interleaved" hops in the envelope calculations and judicious packing of the SSE channels, your project will run very efficiently. And if you're using the sine oscillators from the other active thread, we can integrate those as well into the hopping/packing scheme.

-cyto

PS. Trog, thanks for the optimization. Looks great! 🙂

tester ·

Hi cyto,

Yeah, many oscillators indeed. One hit on this percussive instrument = more than 10 envelopes activated per pairs/triads of sine oscillators. But the instrument needs also a buffer (i.e. few hits = few waves of sound interfering with each other) and each hit should rather get a separate set of oscillators (probably very slightly detuned plus parametric phase offsets) and envelopes (in the future - affected also by input feedback). Plus - a space made of a few units - a real challange, but doable I think. Some simplifications can be done of course (via envelope retrig during ongoing fade for example), but a lot of independent sound must be mixed in order to get the subtleness of a real instrument and scenario.

Good luck with your exam!

Wrote something here? To have a post removed or your name hidden, write to [email protected].

Before your first post

A few rules keep this a friendly place. You agree to them once.

Shown next to what you post, here and in the app. It doesn’t have to be your real name: 3–24 lower-case letters, digits or _ (capitals become lower case, spaces become _).

    Then your post goes up straight away.

    Delete this reply?

    Open it in SynthMaker?

    It goes on the track you’re editing there, in place of that track’s sound, and into My sounds. Your other tracks stay as they are.

    Want to keep that track’s sound? Start a new song in SynthMaker first (Song › New song), then open this.

    Report this reply?

    Only the developer reads reports. The person isn’t told who reported them.

    What’s wrong with it?

    Block this person?

    You won’t see their posts and replies here any more. They aren’t told, and you can unblock them at any time.

    People you’ve blocked

    Their posts and replies are hidden from you. Unblock someone to see them again.

    The community rules

    A few rules keep this a friendly place. Everyone agrees to them once, before their first post.