2 Questions: calcModulation and Osc sync / Boolean in onNote

Question 1:

I often use short decay pitch or filter envelope drops to add some bite to a synth sound’s attack. To spare the internal zone envelopes for other uses, I made a simple modulation parameter to do the job. There is a problem though.

When playing lower notes, there are noticeable variations in the attack character of successive notes, especially sounds with a longer release. It sounds like the oscillator phase and rapid envelope decay are out of sync (with fixed phase osc). The modulation param also doesn’t take “Key On Del” into account. I’m guessing this has something to do with the execution order of the program tree.

The same thing happens with the standard Env Midi Module.

I’ve tried various ways of delaying the mod param to sync with onNote, but nothing worked. Any ideas?

defineModulation("Quick Decay", false)

modVal = 1
durationMS = 15

function calcModulation()
	if retrigger then
		modVal = 1
		retrigger = false
	end
	rate = getSamplingRate() / 32
	rateVal = 1 / (rate * (durationMS / 1000))
	if modVal <= 0 then
		modVal = 0
	else
		modVal = modVal - rateVal
	end	
	return modVal
end

function onNote(event)
	retrigger = true
	postEvent(event)
end

function onRelease(event)
	postEvent(event)
end

Question 2:

I have a boolean parameter tied to a UI switch with no callback function. It’s only there to retrieve the state of the switch.

As soon as you use the boolean parameter in the onNote function, it changes the values to 0 and 1 instead of false and true. This messes with the shorthand “if boolParam then” syntax, as both become true. Even when the “if statement” is inside an external function and called from onNote, this still happens.

I know this runs in different threads in the Halion engine, but as parameters are variables, this is kind of strange.

Any help with these 2 questions would be much appreciated.

Hi AposMus.

Regarding your second question, can you use an integer parameter instead?
Or maybe an indexed string array with two entries, on and off.

I had similar problems problem with boolean parameters and if statements. In the end I went with the integer option.


Edit: Actually I think it works if you assign the value of the Boolean parameter to a local variable first.
Something like:

defineParameter("Play",nil,true)

function onNote(event)
  local p=this:getParameter("Play")
  if p then postEvent(event) end
end

When playing lower notes, there are noticeable variations in the attack character of successive notes, especially sounds with a longer release. It sounds like the oscillator phase and rapid envelope decay are out of sync (with fixed phase osc). The modulation param also doesn’t take “Key On Del” into account. I’m guessing this has something to do with the execution order of the program tree.

The same thing happens with the standard Env Midi Module.

I’ve tried various ways of delaying the mod param to sync with onNote, but nothing worked. Any ideas?

Having a go at your first question I came up with this. Each note on event should trigger the modulation and also take the Key on delay into account as long as it’s set to ms. Don’t know if that helps.

defineModulation("Quick Decay", false)

modVal = 1
durationMS = 15
zone=this.parent:getZone()

function calcModulation()
  rate=getSamplingRate()/32
  rateVal=1/(rate*(durationMS/1000))
  modVal=modVal-rateVal
  if modVal<0 then
    modVal=0
  end
  return modVal
end

function onNote(event)
  postEvent(event)
 wait(zone:getParameter("VoiceControl.KeyOnDelay"))
  modVal=1
end

Thanks misohoza

With Q1 I did end up using and integer switch, I’m just curious though how a boolean can change to an integer mid script. Also I like a certain conformity in the script, so having to change it for one parameter kind of bugs me.

As for Q2, that is something I already tried, but it doesn’t really work. Delaying the note doesn’t get rid of the attack phase issues, but I’m working on another idea, so might post it when I’m done.

Hi ApoMus,

regarding the “QuickDecay” and calcModulation, I think, you must use note expression, instead.

In general, the modulations from MIDI modules are monophonic. That is, the same modulation value goes to all voices that are still being processed.

If you use changeNoteExpression, you should be able to send the “QuickDecay” with every note and do this polyphonically.

Cheers,

Matthias

Hi AposMus,

regarding the boolean parameter, unfortunately, this is a bug. I created a bug report, so it gets fixed.

Here, is a workaround.

defineParameter("Play",nil,true)
function onNote(event)
    if Play and Play ~= 0 then
        postEvent(event)
    end
end

The workaround from misohoza is fine, too. Thanks @misohoza for posting this.

After the fix Play will keep its boolean values. The workarounds above should still work after we have fixed this problem.

You should not use this statement:

    if Play == 1 then
       postEvent(event)
    end

This will not work anymore after our fix.

Sorry, for the inconvenience this might cause.

Best,

Matthias

Hi Matthias, good to hear from you.

Thanks for the boolean workaround. I’m glad it’s a bug, because I was beginning to doubt my understanding of the scripting language and thought I missed something major in the reference manual.

I eventually defined my switch parameter with integers instead of a boolean, but I’m going change that.

The “QuickDecay” using the changeNoteExpression function is working like a charm. I wouldn’t have thought of that. One just has to keep controller smoothing in mind.

Thanks for the feedback.