User Script Examples

Post topics about HALion scripting.
Post Reply
misohoza
Member
Posts: 821
Joined: Sun Oct 05, 2014 12:18 am
Contact:

User Script Examples

Post by misohoza » Wed Feb 15, 2017 12:46 pm

Hi.

What about creating a sticky topic on this forum where users would post just the code of their script and a short description of what it does and how to use it.

Together with the examples provided by Steinberg it would be a great help for people just starting to learn scripting.
Win 10 Home, 64 bit, 8 gb ram,
Cubase Pro 9, Wavelab Pro 9, Halion 6, Dorico,
NI Komplete 10 Ultimate, Ozone 7,
UR 44

User avatar
abject39
Member
Posts: 266
Joined: Sat Jan 17, 2015 8:20 pm
Location: Ventura, Ca
Contact:

Re: User Script Examples

Post by abject39 » Tue Aug 01, 2017 4:18 am

misohoza wrote:
Wed Feb 15, 2017 12:46 pm
Hi.

What about creating a sticky topic on this forum where users would post just the code of their script and a short description of what it does and how to use it.

Together with the examples provided by Steinberg it would be a great help for people just starting to learn scripting.
Not a bad idea at all.
My vision is uncompromising: to transcend my clients dreams by mesmerizing their audience with the world's finest audio arrangements and products.

maggie
Member
Posts: 293
Joined: Fri Nov 01, 2013 1:08 pm
Contact:

Re: User Script Examples

Post by maggie » Tue Aug 01, 2017 10:22 am

+1
Cubase 9.5 pro, Halion 6, Groove Agent 4, Padshop Pro, Tone2 Electra 2, Tone2 Ultraspace, U-He Diva, U-He Presswerk, U-He Hive, Tubeohm Vintage, Virtual CZ, Arturia Solina V, Arturia Analog Lab, Waldorf Nave, Synapse Dune 2, UVI Falcon, UVI Grand Piano Type D, AiR Xpand!2, Steinberg UR22, Arturia Keylab 49 (Black Edition), Intel i7 2600, 16GB RAM, ASUS P8Z68-V/GEN 3, Windows 10 64bit

misohoza
Member
Posts: 821
Joined: Sun Oct 05, 2014 12:18 am
Contact:

Re: User Script Examples

Post by misohoza » Tue Aug 01, 2017 6:13 pm

I see my thread came alive just when I was thinking about deleting the topic. :D

So I'll give it a go with some of my "utility" scripts.

If you want to try them but you get a syntax error when trying to copy and paste the code into Halion download the attachment. I've included these examples as both lua script files and Halion MIDI Module presets (plus two more midi module presets with a simple macro page).
Halion.zip
(17.03 KiB) Downloaded 147 times

Quick Control Setup.

Tries to assign Filter Cutoff and Resonance, Amp Attack and Release (Offsets) and some of the parameters of Reverb, Delay and Modulation effects.
It does remove any already existing quick control assignments of the program.

Code: Select all

program=this.program
zones=this.parent:findZones(true)
effects=program:findEffects(true)

function removeAllQCAssignments(layer)
  for i=1,11 do
    local assignment=layer:getNumQCAssignments(i)
    if assignment>0 then
      for j=assignment,1,-1 do
        layer:removeQCAssignment(i,j)
      end
    end
    layer:setParameter("QuickControl.QC"..i,50)
  end
end

removeAllQCAssignments(program)

function trimRangeQC(layer,qc,index,paramNorm)
  layer:setParameterNormalized("QuickControl.QC"..qc,paramNorm)
  layer:setQCAssignmentMin(qc,index,50-paramNorm*100/2)
  layer:setQCAssignmentMax(qc,index,50+(1-paramNorm)*100/2)
end

function assignQC(layer,qc,element,param,scope,qcName)
  layer:addQCAssignment(qc,element,param,scope)
  layer:setParameter("QuickControl.Name"..qc,qcName)
  local paramNorm=element:getParameterNormalized(param)
  local assignment=layer:getNumQCAssignments(qc)
  trimRangeQC(layer,qc,assignment,paramNorm)
end

function assignSphere()
  assignQC(program,9,zones[1],"CutoffModOffset",program,"Cutoff Offset")
  assignQC(program,10,zones[1],"ResoModOffset",program,"Resonance Offset")
  print("Sphere assigned to Filter Cutoff and Resonance Offset")
end





paramNames={
  {parameter="Filter.Cutoff",     name="Filter Cutoff"},
  {parameter="Filter.Resonance",  name="Resonance"},
  {parameter="DCAAttOffset",      name="Attack"},
  {parameter="DCARelOffset",      name="Release"}
  }


if zones[1] then
  for i=1,4 do
    assignQC(program,i,zones[1],paramNames[i].parameter,program,paramNames[i].name)
    print("QC"..i..": "..paramNames[i].name)
  end
  for i,zone in ipairs(zones) do
    if zone:getParameter("Filter.Type")==0 then
      zone:setParameter("Filter.Type",1)
    end
    if zone:getParameter("ZoneType")==3 then
      print("Filter Cutoff and Resonance have no effect on Organ Zones")
    end
  end
  assignSphere()
else
  print("No Zones Found")
end


effectParameters={
  ["Reverb"]=                 {par={"Predelay","Mix"},          nam={"Predelay","Mix"}},
  ["REVerence"]=              {par={"predelay","mix"},          nam={"Predelay","Mix"}},
  ["Chorus"]=                 {par={"Rate","Depth"},            nam={"Rate","Depth"}},
  ["Flanger"]=                {par={"Rate","Depth"},            nam={"Rate","Depth"}},
  ["Phaser"]=                 {par={"rate","mix"},              nam={"Rate","Mix"}},
  ["Multi Delay"]=            {par={"feedbackoverall","Mix"},   nam={"Feedback","Mix"}},
  ["Studio EQ"]=              {par={"gainlfl","gainhfl"},       nam={"Gain Low","Gain High"}},
  ["Resonator"]=              {par={"CutoffSpread","Mix"},      nam={"Cutoff Spread","Mix"}},
  ["Ring Modulator"]=         {par={"Freq","Mix"},              nam={"Frequency","Mix"}},
  ["Frequency Shifter"]=      {par={"ModCoarse","Mix"},         nam={"Mod Coarse","Mix"}},
  ["Compressor"]=             {par={"ratio","threshold"},       nam={"Ratio","Threshold"}},
}




qc=5
k=0
if effects[1] then
  for i,effect in ipairs(effects) do
    local name=effect.name
    if effectParameters[name] then
      k=k+1
    end
  end
  if k<=2 then
    for i,effect in ipairs(effects) do
      local name=effect.name
      if effectParameters[name] then
       for j=1,2 do
         local parameter=effectParameters[name].par[j]
         local qcName=effect.name.." "..effectParameters[name].nam[j]
         assignQC(program,qc,effect,parameter,program,qcName)
         print("QC"..qc..": "..qcName)
         qc=qc+1
       end
     end
   end
 else
   for i,effect in ipairs(effects) do
     local name=effect.name
     if effectParameters[name] then
       local parameter=effectParameters[name].par[2]
       local qcName=effect.name.." "..effectParameters[name].nam[2]
       assignQC(program,qc,effect,parameter,program,qcName)
       print("QC"..qc..": "..qcName)
       qc=qc+1
       if qc>8 then break end
     end
   end
 end
else
 print("No Effects Found")
end

Modwheel Vibrato

Looks for two empty modulation matrix rows and assigns LFO 1 to pitch.
It does so each time the script is reloaded so you might end up with duplicate assignments.

Code: Select all

zones=this.parent:findZones(true)

function findEmptyRow(zone)
 for j=1,31 do
   local modRow1=zone:getModulationMatrixRow(j)
   local modRow2=zone:getModulationMatrixRow(j+1)
   if modRow1:getSource1()==0 and modRow2:getSource1()==0 then return j end
 end
end

function assignModwheelVibrato()
  for i,zone in ipairs(zones) do
    local j=findEmptyRow(zone)
    if j then
      local modRow1=zone:getModulationMatrixRow(j)
      local modRow2=zone:getModulationMatrixRow(j+1)
      modRow1:setSource1(15)
      modRow1:setParameter("Destination.Destination",46)
      modRow1:setParameter("Destination.Depth",41)
      modRow2:setSource1(1)
      modRow2:setParameter("Source1.Polarity",1)
      modRow2:setSource2(15)
      modRow2:setParameter("Destination.Destination",1)
      modRow2:setParameter("Destination.Depth",3)
      print("Zone "..i.." Modulation Row "..j.." and "..j+1)
      print("Modwheel assigned to Vibrato")
    else
      print("No Empty Modulation Row Found")
    end
  end
end

if zones[1] then
  assignModwheelVibrato()
else
  print("No Zones Found")
end

Aftertouch Vibrato

Same as above but with aftertouch.

Code: Select all

zones=this.parent:findZones(true)

function findEmptyRow(zone)
 for j=1,31 do
   local modRow1=zone:getModulationMatrixRow(j)
   local modRow2=zone:getModulationMatrixRow(j+1)
   if modRow1:getSource1()==0 and modRow2:getSource1()==0 then return j end
 end
end

function assignAftertouchVibrato()
  for i,zone in ipairs(zones) do
    local j=findEmptyRow(zone)
    if j then
      local modRow1=zone:getModulationMatrixRow(j)
      local modRow2=zone:getModulationMatrixRow(j+1)
      modRow1:setSource1(16)
      modRow1:setParameter("Destination.Destination",46)
      modRow1:setParameter("Destination.Depth",41)
      modRow2:setSource1(1)
      modRow2:setParameter("Source1.Polarity",1)
      modRow2:setSource2(16)
      modRow2:setParameter("Destination.Destination",1)
      modRow2:setParameter("Destination.Depth",3)
      print("Zone "..i.." Modulation Row "..j.." and "..j+1)
      print("Aftertouch assigned to Vibrato")
    else
      print("No Emty Modulation Row Found")
    end
  end
end

if zones[1] then
  assignAftertouchVibrato()
else
  print("No Zones Found")
end

Reset Modulation Matrix

Code: Select all

zones=this.parent:findZones(true)

function resetModulationMatrix()
  if zones[1] then
    for i,zone in ipairs(zones) do
      for j=1,32,1 do
        local modRow=zone:getModulationMatrixRow(j)
        local defs=modRow.parameterDefinitions
        for k,paremeter in ipairs(defs) do
          modRow:setParameter(paremeter.id,paremeter.default)
        end
      end
    end
    print("Modulation Matrix Has Been Reset")
  else
    print("No Zones Found")
  end
end

resetModulationMatrix()
Win 10 Home, 64 bit, 8 gb ram,
Cubase Pro 9, Wavelab Pro 9, Halion 6, Dorico,
NI Komplete 10 Ultimate, Ozone 7,
UR 44

User avatar
abject39
Member
Posts: 266
Joined: Sat Jan 17, 2015 8:20 pm
Location: Ventura, Ca
Contact:

Re: User Script Examples

Post by abject39 » Sun Aug 06, 2017 1:48 am

Single Pitch knob

1) Insert a new Midi-Module - Object / Lua-Script
2) Edit the Lua-Script and write your code: (i named my synth-zone "Zone1a")

Code: Select all

--Amp and Filter Offsets
zone1=this.parent:getZone("Zone1a")

-- the callback-Function (it is called when you turn the knob in the Macro-Window)
function onO1ChangePitch()

O1_oct, Oct1rest = math.modf(Osc1Coarse / 12) 
Osc1PitFin=Osc1Coarse-(O1_oct*12)

O1_coarse, O1_fine=math.modf(Osc1PitFin)


-- this are the parameter in the layer (only OSC 1 & 2 activated)
zone1:setParameter("Osc 1.Octave", O1_oct)
zone1:setParameter("Osc 2.Octave", O1_oct)


zone1:setParameter("Osc 1.Coarse", O1_coarse) 
zone1:setParameter("Osc 2.Coarse", O1_coarse)


zone1:setParameter("Osc 1.Fine", O1_fine*100) 
zone1:setParameter("Osc 2.Fine", O1_fine*100)

end

-- This it the function/variable that can be linked with the Macro-Designer Extended when you select the luascript and look under PARAMSLIST

defineParameter("Osc1Pitch","Osc1Pitch",0,-36,36,onO1ChangePitch)

2) copy this little programm (please excuse my bad "hacking") in in the Lua-Script

3) Create a Big Knob on the MaroDesigner-Page

4) Open up "Maco Page Designer Extended", select the Lua-Script and right click on the new variable Osc1Pitch.
5) Select Connect to Macro Page
6) rightclick on the Knob and select Connect to Parameter "Lua.Script...Osc1Pitch"
Last edited by abject39 on Mon Aug 21, 2017 6:17 am, edited 1 time in total.
My vision is uncompromising: to transcend my clients dreams by mesmerizing their audience with the world's finest audio arrangements and products.

User avatar
Tekknovator
New Member
Posts: 20
Joined: Mon Aug 07, 2017 6:18 pm
Contact:

Re: User Script Examples

Post by Tekknovator » Fri Aug 11, 2017 5:19 pm

Great Idea!
I thought it might be even better to have this in a code management system and created a Git-Hub repository.
If you guys don't mind it would be cool if you check in there. It is my first Git-Hub project, so please be patient with me ;) Also I have nothing to upload yet because my code is not ready for prime time. But I thought I can help the community by creating that repository and take care of it:

https://github.com/tekkzoo/halion-script-collection

What do you think?

AposMus
Junior Member
Posts: 179
Joined: Fri Nov 14, 2014 11:41 am
Contact:

Re: User Script Examples

Post by AposMus » Tue Aug 22, 2017 8:59 pm

findZones() search filter:

It's mentioned in the dev resources that findZones(), findLayers() etc. can include a function for to filter results. They don't really expand on the implementation and didn't mention that it needs to be an anonymous function. I tried a named function but couldn't get it to work, the parameter doesn't get passed to the function during the call.

Also, you have to include the recursive boolean otherwise the function isn't recognised.

Using the filter can save a lot of memory, because now you have a table with only the relevant zone objects instead of all zones objects.

A simple filter to find sample zones:

Code: Select all

zones = this.parent:findZones(true, function(result) 
	if result:getParameter("ZoneType") == 1 then return true end
end)
If you do need an external reusable function, call it from within the anonymous function: (finds sample and grain zones)

Code: Select all

function filterFunc(result)
	zoneType = result:getParameter("ZoneType")
	if zoneType == 1 or zoneType == 2 then return true end
end

zones = this.parent:findZones(true, function(zone)
		if filterFunc(zone) then return true end
	end)

zoneTypes = {[0] = "Synth", "Sample", "Grain"}

for i, zoneFilt in ipairs(zones) do
	local zoneType = zoneTypes[zoneFilt:getParameter("ZoneType")]
	print(zoneType, zoneFilt.name)
end
Last edited by AposMus on Mon Oct 02, 2017 7:36 am, edited 1 time in total.
Cubase Pro 8.5.2
Halion 6
HSO
Padshop Pro
Dark Planet
Windows 7 64bit, AMD Phenom IIx6 1055t, 8GB Ram, Gigabyte GA-880G-UD3H F2, Nvidia GeForce GTS450
https://dewetvanderspuy.co.za/

User avatar
Tekknovator
New Member
Posts: 20
Joined: Mon Aug 07, 2017 6:18 pm
Contact:

Re: User Script Examples

Post by Tekknovator » Sun Sep 03, 2017 12:34 am

Hi,

My first contribution here is actually a ruby script that creates a little halion lua snippet.

First of all the problem it solves:
Problem 1: HALion
-I wanted to switch samples of a zone using a dropdown on my macropage. But I did not want to load layers or change presets or anything that could potentially contain the path information.
- The workarround is using a table with filename/path pairs. Like this:

Code: Select all

sampleSearchPath = "/Users/myUser/Documents/Steinberg/HALion/Recordings/"

builtInSamples = {
    { name = "Growlar-A#5.wav", path = sampleSearchPath.."Growlar-A#5.wav"},
    { name = "Growlar-A#5.wav", path = sampleSearchPath.."Growlar-A#5.wav"},
    { name = "Growlar-A5.wav", path = sampleSearchPath.."Growlar-A5.wav"},
    { name = "Growlar-F#5.wav", path = sampleSearchPath.."Growlar-F#5.wav"},
    { name = "Growlar-G#5.wav", path = sampleSearchPath.."Growlar-G#5.wav"},
    { name = "Growlar-G5.wav", path = sampleSearchPath.."Growlar-G5.wav"},
}
- Creating such a table is time intensive, so created a dumb little script to do that for me.
Problem 2: LUA
Halion script is restricted to halion. I could not find a way to access the filesystem because io and os are not available.
I used ruby because io and os are *witch* to use for what I do and ruby is perfect for file and text stuff. Also i did not want to use popen because ls is not available on windows per default(unless you use linux subsystem to run lua).

The tool is available here:
https://github.com/tekkzoo/halion-scrip ... Creator.rb

I only tested this on mac because ruby is preinstalled here. If you have ruby installed on windows it should work there as well, please let me know.

Code: Select all

usage: 
 ruby HALionFileListCreator.rb "[path of directory with samples]" "[outputfilename.lua]" 
 example: 
 ruby HALionFileListCreator.rb "/user/Documents/Steinberg/HALion/Recordings/" "/user/myBuiltinSamples.lua"

AposMus
Junior Member
Posts: 179
Joined: Fri Nov 14, 2014 11:41 am
Contact:

Re: User Script Examples

Post by AposMus » Mon Oct 02, 2017 7:35 am

Changing a parameter to non-automatable:

I'm busy with a script which has quite a large number of parameters. It occurred to me that some of the parameters would be better off not generating automation.

I really wasn't looking forward to redoing all those parameters by named arguments. To be honest, creating a large number of named argument parameters can get tedious even if you do it from the get go, so I thought of doing this:

Code: Select all

function defineNonAuto(...)
	local nonAutoDef = {}
	local tableLength = #{...}
	local argFour = ({...})[4]
	
	nonAutoDef.name 		= 	({...})[1]
	nonAutoDef.longName		= 	({...})[2]
	nonAutoDef.default 		= 	({...})[3]
	nonAutoDef.onChanged	= 	({...})[tableLength]
	nonAutoDef.automatable 	= 	false
	
	if type(argFour) == "table" then 
		nonAutoDef.strings = argFour
	
	elseif type(argFour) == "number" then
		nonAutoDef.min = argFour
		nonAutoDef.max = ({...})[5]
		
		if tableLength == 7 then
			nonAutoDef.increment = ({...})[6]
		end
	end
	
	defineParameter(nonAutoDef)
end
Now you can simply change:

Code: Select all

defineParameter("myParam", nil, 0, 0, 100, 1, onChangeFunc)
to

Code: Select all

defineNonAuto("myParam", nil, 0, 0, 100, 1, onChangeFunc)
Just paste it in your script and you're good to go.

It works for all parameter types, takes account of the optional increment value and works fine with callbacks taking arguments declared inside anonymous functions.
Cubase Pro 8.5.2
Halion 6
HSO
Padshop Pro
Dark Planet
Windows 7 64bit, AMD Phenom IIx6 1055t, 8GB Ram, Gigabyte GA-880G-UD3H F2, Nvidia GeForce GTS450
https://dewetvanderspuy.co.za/

misohoza
Member
Posts: 821
Joined: Sun Oct 05, 2014 12:18 am
Contact:

Re: User Script Examples

Post by misohoza » Tue Dec 12, 2017 12:09 am

Key Switch

Midi module preset with a simple macropage.
Key Switch Midi Module.zip
(2.22 KiB) Downloaded 61 times

Code: Select all

layers = this.parent:findLayers()

defineParameter("DefaultSwitch", nil, this.parent:getParameterDefinition("LowKey"), function() getLayerNames() end)

function getLayerNames()
  layerNames = {}
  keySwitches = {}
  keyColor = getKeySwitches()
  for i, layer in ipairs(layers) do
    layerNames[i] = layer.name
    keySwitches[DefaultSwitch + i - 1] = i
    keyColor[i] = {name = layer.name, keyMin = DefaultSwitch + i - 1}
  end
end

getLayerNames()

defineParameter("LayerSelect", nil, 1, layerNames)


function isKeyswitch(event)
  if keySwitches[event.note] then
    LayerSelect = keySwitches[event.note]
    return true
  else
    return false
  end
end


function onNote(event)
  if not isKeyswitch(event) then
    playNote(event.note, event.velocity, -1, layers[LayerSelect])
  end
end

Image
Win 10 Home, 64 bit, 8 gb ram,
Cubase Pro 9, Wavelab Pro 9, Halion 6, Dorico,
NI Komplete 10 Ultimate, Ozone 7,
UR 44

misohoza
Member
Posts: 821
Joined: Sun Oct 05, 2014 12:18 am
Contact:

Re: User Script Examples

Post by misohoza » Mon Mar 19, 2018 12:57 am

Midi Monitor

Midi module preset.

Program needs to have at least one zone. Doesn't pick up Program Change messages.
Midi Monitor.zip
(2.03 KiB) Downloaded 38 times

Code: Select all

numberOfLines = 10
emptyLine = 1

for i = 1, numberOfLines do
  defineParameter("Line"..i, nil, "")
end

defineParameter("Reset", nil, false, function() resetResults() end)

function resetResults()
  if Reset then
    for i = 1, numberOfLines do
      _G["Line"..i] = ""
    end
    emptyLine = 1
    Reset = false
  end
end


function printLine(info)
  if emptyLine <= numberOfLines then
    _G["Line"..emptyLine] = info
    emptyLine = emptyLine + 1
  else
    for i = 1, numberOfLines - 1 do
      _G["Line"..i] = _G["Line"..i + 1]
    end
    _G["Line"..numberOfLines] = info
  end
end

function onNote(e)
  postEvent(e)
  printLine("Note On:   "..e.note.."   Velocity:   "..e.velocity)
end

function onRelease(e)
  postEvent(e)
  printLine("Note Off:   "..e.note.."   Velocity:   "..e.velocity)
end

function onController(e)
  postEvent(e)
  if e.controller==129 then
    printLine("Pitchbend:   "..e.value)
  else
    printLine("Controller:   "..e.controller.."   Value:   "..e.value)
  end
end


function onAfterTouch(e)
  postEvent(e)
  printLine("Aftertouch:   "..e.value)
end
Image
Win 10 Home, 64 bit, 8 gb ram,
Cubase Pro 9, Wavelab Pro 9, Halion 6, Dorico,
NI Komplete 10 Ultimate, Ozone 7,
UR 44

misohoza
Member
Posts: 821
Joined: Sun Oct 05, 2014 12:18 am
Contact:

Re: User Script Examples

Post by misohoza » Wed May 09, 2018 11:55 pm

Strummer

Midi module preset.

Attempt to create an arpeggiator that simulates strumming.
Doesn't come with any patterns or presets. You need to save a user preset first for the preset browser to work.
Strummer.zip
(4.77 KiB) Downloaded 24 times

Code: Select all

for i = 1, 16 do
  defineParameter("Step"..i, nil, 0, {[0]="Off", "Down", "Up", "Mute"})
  defineParameter("Velocity"..i, nil, 100, 0, 127, 1)
end

defineParameter("StrumSpeed", nil, 10, 1, 40, 1)
defineParameter("BeatDiv", nil, 1, {"1/8", "1/16"})
defineParameter("numberOfSteps", nil, 8, 1, 16, 1)
defineParameter{
  name = "currentStep",
  default = 0,
  min = 0,
  max = 16,
  persistent = false,
  automatable = false,
  readOnly = true
  }

function checkTimeSignature()
  num, denom = getTimeSignature()
  if num > 0 then
    numberOfSteps = num*2
  else
    numberOfSteps = 8
  end
end

defineSlotLocal("noteBuffer")
defineSlotLocal("arpRunning")
defineSlotLocal("arpeggioNotes")
defineSlotLocal("heldNotes")

noteBuffer = {}
heldNotes = {}
arpRunning = false

function sortNotes()
  arpeggioNotes = {}
  for note, velocity in pairs(noteBuffer) do
    arpeggioNotes[#arpeggioNotes+1] = note
  end
  table.sort(arpeggioNotes)
end

function waitForBeat()
  if not isPlaying() then
    return 1
  else
    checkTimeSignature()
    local position = getBeatTimeInBar()
    if position == 0 then
      return 1
    else
      local b, f = math.modf(position)
      waitBeat(1-f)
      local beatfactor = 2*BeatDiv
      local step = beatfactor*math.ceil(position) + 1
      if step > numberOfSteps then
        step = 1
      end      
      return step
    end
  end
end

function waitForNextBeat()
  local position = getBeatTimeInBar()
  local b, f = math.modf(position)
  waitBeat(1-f)
end

function strumDown(velocity)
  local i = 1
  while arpeggioNotes[i] do
    if heldNotes[i] then
      releaseVoice(heldNotes[i])
    end
    local id = playNote(arpeggioNotes[i], velocity, 0)
    heldNotes[i] = id
    wait(StrumSpeed)
    i = i + 1
  end
end

function strumUp(velocity)
  local i = #arpeggioNotes
  while arpeggioNotes[i] do
    if heldNotes[i] then
      releaseVoice(heldNotes[i])
    end
    local id = playNote(arpeggioNotes[i], velocity, 0)
    heldNotes[i] = id
    wait(StrumSpeed)
    i = i - 1
  end
end

function strumMute()
  local i = 1
  while arpeggioNotes[i] do
    if heldNotes[i] then
      releaseVoice(heldNotes[i])
    end
    heldNotes[i] = nil
    i = i + 1
  end
end

function playStrum()
  arpRunning = true
  currentStep = waitForBeat()
  while arpeggioNotes[1] do
    local beatfactor = 2*BeatDiv
    local beat = getBeatDuration()/beatfactor
    local step = _G["Step"..currentStep]
    local velocity = _G["Velocity"..currentStep]
    if step == 1 then strumDown(velocity) end
    if step == 2 then strumUp(velocity) end
    if step == 3 then strumMute() end

    if isPlaying() and currentStep%beatfactor == 0 then
      checkTimeSignature()
      waitForNextBeat()
    else
      if step == 0 or step == 3 then
        wait(beat)
      else
        wait(beat-StrumSpeed*#arpeggioNotes)
      end
    end

    currentStep = currentStep + 1
    if currentStep > numberOfSteps then
      currentStep = 1
    end
  end
  arpRunning = false
  currentStep = 0
end

function onNote(event)
  noteBuffer[event.note] = event.velocity
  sortNotes()
  if arpRunning == false then
    playStrum()
  end
end

function onRelease(event)
  noteBuffer[event.note] = nil
  sortNotes()
  postEvent(event)
end
Image
Win 10 Home, 64 bit, 8 gb ram,
Cubase Pro 9, Wavelab Pro 9, Halion 6, Dorico,
NI Komplete 10 Ultimate, Ozone 7,
UR 44

Post Reply

Return to “Halion Scripting”

Who is online

Users browsing this forum: No registered users and 2 guests