How to manage a multitype envelope in your preset

Hi, this may be useful to someone somewhere.

In a Waldorf Micro Q synth, one has multiple envelope modes:

  • ADSR : classical four stage
  • ALDSDSR : 7 stage envelope with an additional attack level, breakpoint and double decay
  • One Shot : as an ADSR, but the Sustain has become a breakpoint
  • 2 looping envelopes

Normally I use the envelope controls to set the values of the envelopes directly and then deal with the ‘special’ stages in an bit of an awkward way, but this time I choose not to: the envelope control is merely used to visualize the varying envelope shapes, not to control it.
That gave me the opportunity to differentiate between the usable controls themselves and their visualizing counterparts.

What are the benefits?

  • only showing the controls that matter to the chosen envelope
  • rearranging the controls in a sensible way, and providing them with meaningful names
  • blue control colors are used to indicate what part of the envelope is looping when holding the keys. No need to memorize which parts of the envelopes are within the looping cycle.
  • graphically : what you see is what you get

Here’s how the initial design looks like:

  • Slim fader controls are used for time stages, the large ones for level stages.
  • Upper right is the graph (visuals only, doesn’t do anything)
  • Lower right is the option list to select the desired envelope.

In the case of the micro Q, the following parameter numbers appear in ENV1 (= filter):

  • stages 1-7: 199..205. They all have a “showStage” function assigned to them.
  • graphics: 4199..4205 except L4 that has 9999 and message type “None” as it is not in use
  • filter env mode = 1196 (controlling the real param 196 but that is another story). This has a “setEG” function assigned.
  • do remark the graphic elements are exactly 4000 apart from their original controls.

The other 3 envelopes have the same distances between parameters but are 12, 24 and 36 higher in their numbering.

The code for function “showStage” :

function showStage(valueObject,value) ---show EG sustain level into  DX7 style EG graph
  local message = valueObject:getMessage ()
  local paramNum = message:getParameterNumber() -- 202 = Fil, 214 = Amp, 226 = Env3, 238 = Env4
  local envNum = math.floor((paramNum-199)/12)+1 -- 1 = Fil.. 4 = Env4
  local stageNum = (paramNum+1-199)%12 -- 1 = attack...7 = release
  local envMode = parameterMap.get(deviceId, PT_VIRTUAL,1196+(envNum-1)*12) -- 0 = ADSR.. 4 = Loop All
  if stageNum%2 == 0 then parameterMap.set (deviceId, PT_VIRTUAL, paramNum+4000, value) -- level controls
    else parameterMap.set (deviceId, PT_VIRTUAL, paramNum+4000, 127-value) -- time controls
  end
  if envMode == 0 and stageNum == 4 then --  ADSR copy sustain to L2
    parameterMap.set (deviceId, PT_VIRTUAL, paramNum+4000+2, value)
  elseif envMode == 2 and stageNum == 7 then --   one-shot copy release to R3
    parameterMap.set (deviceId, PT_VIRTUAL, paramNum+4000-2, 127-value)
    parameterMap.set (deviceId, PT_VIRTUAL, paramNum+4000, 127)   -- fix R4 to 127
  end
end

Two remarks here:

  • as the 8 stage graph in the E1 is showing rates rather than times, the values shown equal 127-value of the parameter value stored.
  • for good representation:
    • L3 must be set to L2 for an ADSR,
    • R3 must show the release for a One-Shot, and R4 should not be used

The code for function “setEG” :

function setEG(valueObject, value) ---- hides the non used controls of envelope
  local message = valueObject:getMessage ()
  local paramNum = message:getParameterNumber()
  local egNum = 1 
  if paramNum == 1208 then egNum = 2 elseif  paramNum == 1220 then egNum = 3 elseif  paramNum == 1232 then egNum = 4 end -- 1 = Filter, 2 = Amp, 3 = Env3, 4 = Env
   -- Data typical per envelope ---------------------------------
  local egCol ={ORANGE,WHITE,182*65536+250*256+194,35*65536+255*256+146} -- colors for each envelope
  local defCol = egCol[egNum]
     -- egStages = {"r1","l1","r2","l2","r3","l3","r4"} -- the 7 stages as used in the graph
  local egCtls = {{338,339,340,341,344,345,346},{351,352,353,354,357,358,359},{364,365,366,367,370,371,372},{375,376,377,378,381,382,383}} -- ctl numbers R1,L1,R2..R4
  local stagePar = {{4199,4200,4201,4202,4203,4204,4205},{4211,4212,4213,4214,4215,4216,4217},{4223,4224,4225,4226,4227,4228,4229},{4235,4236,4237,4238,4239,4240,4241}} -- virtual par of each stage in the EG graph
  local egColor = {{defCol,defCol,defCol,BLUE,defCol,defCol,defCol},{defCol,defCol,defCol,defCol,defCol,BLUE,defCol},
    {defCol,defCol,defCol,defCol,defCol,defCol,defCol}, {defCol,defCol,BLUE,BLUE,BLUE,BLUE,defCol},{BLUE,BLUE,BLUE,BLUE,BLUE,BLUE,BLUE}} -- ctrl colors
  local offsetAndPage = {{0,4},{12,4},{24,4},{24,9}} -- indicates start slot offset and page of each EG
  -- Date typical per Envelope Mode -----------------------------
  local egSlots = {{1,0,2,3,0,0,4},{1,2,3,4,8,9,10},{1,0,2,3,0,0,4},{1,2,3,4,8,9,10}} -- relative slot position or hide
  local egNames = {{"Attack",127,"Decay","Sustain",127,"Sustain","Release"}, -- ADSR
        {"Attack","Attack Level","Decay","Breakpoint","Decay2","Sustain","Release"}, -- ALDSDSR
        {"Attack",127,"Decay","Breakpoint",63,0,"Release"}, -- One-Shot
        {"Attack","Attack Level","Decay","Breakpoint","Decay2","Breakpoint2","Release"}} -- Loop S1S2 + Loop All
  local egType = math.min(value+1,4)
  local position = 0
  local control = controls.get(egCtls[1][1])
  for i = 1,7 do
    control = controls.get(egCtls[egNum][i])
    if egSlots[egType][i] then position = egSlots[egType][i] else position = 0 end 
    if position == 0 then 
      control:setVisible (false)
      if type(egNames[egType][i]) == "number" then -- set a fixed value
        parameterMap.set(deviceId, PT_VIRTUAL,stagePar[egNum][i],egNames[value+1][i])
      end
    else -- visible control
      control:setSlot(egSlots[egType][i]+offsetAndPage[egNum][1], offsetAndPage[egNum][2])
      control:setName (egNames[egType][i])
      control:setColor (egColor[value+1][i])
      control:setVisible (true)
    end
  end

  if egType == 1  then -- ADSR
    parameterMap.set (deviceId, PT_VIRTUAL, 4204+(egNum-1)*12, parameterMap.get (deviceId, PT_VIRTUAL,202+(egNum-1)*12)) -- sync sustain
    parameterMap.set (deviceId, PT_VIRTUAL, 4205+(egNum-1)*12, 127 - parameterMap.get (deviceId, PT_VIRTUAL,205+(egNum-1)*12)) -- set release
  elseif egType == 3 then --  one-shot
    parameterMap.set (deviceId, PT_VIRTUAL, 4203+(egNum-1)*12, 127 - parameterMap.get (deviceId, PT_VIRTUAL,205+(egNum-1)*12)) -- - set decay 2 to release
    parameterMap.set (deviceId, PT_VIRTUAL, 4205+(egNum-1)*12, 127) -- - set release in graph to 0
  else 
    parameterMap.set (deviceId, PT_VIRTUAL, 4203+(egNum-1)*12, 127 - parameterMap.get (deviceId, PT_VIRTUAL,203+(egNum-1)*12)) -- set decay 2
    parameterMap.set (deviceId, PT_VIRTUAL, 4204+(egNum-1)*12, parameterMap.get (deviceId, PT_VIRTUAL,204+(egNum-1)*12)) -- set sustain 2
    parameterMap.set (deviceId, PT_VIRTUAL, 4205+(egNum-1)*12, 127 - parameterMap.get (deviceId, PT_VIRTUAL,205+(egNum-1)*12)) -- set release
 
  end
end

some remarks here:

  • egCtls is a table containing the control numbers of the controls. they will differ in another preset.
  • stagePar is a table containing the parameter numbers of the graphic elements. Allthough I could easily have calculated them instead of listing, I prefer listing them so it becomes easier to reuse the code in a different synth context.
  • egColor table contains for each egType the info whether the original EG color is to be shown, or whether the stage is to be colored in BLUE (looping part)
  • egSlots table dictates per egType in what (relative) slot the stage is to be shown or, if 0, is to be hidden
  • egNames table dictates per egType whant name the stage should get, or if a number, with what constant that stage (that will be hidden) will be shown
  • at the end, some values are copied to other stages for a correct visualisation:
    • sustain2 must be set to sustain for an ADSR,
    • decay2 must be set to release for a one-shot, and the release stage itself in the graph is not to be shown.
    • In all other cases decay2, sustain2 and release must be set against the controlled parameters.

If you want to test it out yourself, check out this preset using page ‘Env 1-3’

3 Likes