“Toggle” mode for note playback?

Hello,

Is there a built-in parameter or functionality in HALion to enable a “toggle” mode for note playback? Specifically, I would like a note to behave as follows:

  • When I press and release the note, the loop continues to play.
  • If I press the same note again, the loop stops.

Is this possible using HALion’s existing features, or would it require scripting?

I have looked inside HALion and in the manual but I can’t find it.

Thank you!

You could try something like this:

noteIds = {}

function onNote(e)
	if noteIds[e.note] then
		releaseVoice(noteIds[e.note])
		noteIds[e.note] = nil
	else
		noteIds[e.note] = playNote(e.note, e.velocity, 0)
	end
end

function onRelease(e)
	-- do nothing
end
3 Likes

Thanks, it works great! In my UI, I’ve set up an animation that pulses on the beat while the loop is playing. It works perfectly when the loop is set to “Continuous” because pressing the note again stops both the loop and the animation. However, when the loop is set to “No Loop,” I can’t find a way to stop the animation when the loop reaches the end and stops playing.

Is there a function or method to detect when the loop ends and stops playing that I can use to stop the animation too? I’ve searched through the HALion Developer Resource but couldn’t find anything. Any ideas or suggestions?

Not that I know of. You could try checking the playback position. Do you have a single zone? I tried to detect the loop end using onIdle callback and amp envelope playback position. But maybe there is a better way to do it.

noteIds = {}
zone = this.parent:getZone()
watchEnd = false

function onNote(e)
	if noteIds[e.note] then
		releaseVoice(noteIds[e.note])
		noteIds[e.note] = nil
	else
		noteIds[e.note] = playNote(e.note, e.velocity, 0)
		if zone:getParameter("SampleOsc.SustainLoopModeA") == 0 then		
			watchEnd = true
		end		
	end
end

function onRelease(e)
	-- do nothing
end

function onIdle()
	if watchEnd == true and zone:getParameter("Amp Env.PlaybackPos") == 0 then
		watchEnd = false
		print("Finished")
	end
end
1 Like

“Thanks, this works! Now I’m trying to figure out how to make a loop in ‘toggle’ mode and synchronized with the host tempo stop automatically when the host playback stops. I tried using the isPlaying function, but it doesn’t seem to work. Is there a better approach to achieve this?”

How did you use the isPlaying?

I tried like this but I am not sure how much this would affect performance.

noteIds = {}
zone = this.parent:getZone()
watchEnd = false
playing = false

function onNote(e)
	if noteIds[e.note] then
		releaseVoice(noteIds[e.note])
		noteIds[e.note] = nil
	else
		noteIds[e.note] = playNote(e.note, e.velocity, 0)
		if zone:getParameter("SampleOsc.SustainLoopModeA") == 0 then		
			watchEnd = true
		end		
	end
end

function onRelease(e)
	-- do nothing
end

function releaseAllVoices()
	for note, id in pairs(noteIds) do
		releaseVoice(id)
		noteIds[note] = nil
	end
end

function onIdle()
	if watchEnd == true and zone:getParameter("Amp Env.PlaybackPos") == 0 then
		watchEnd = false
		print("Finished")
	end
	if isPlaying() ~= playing then
		playing = isPlaying()
		if playing == false then
			print("Playback stopped")
			runSync(releaseAllVoices)
		end
	end
end
1 Like