PSdH:HHM ꣸C̭6VIAZ LuaHarmony AZLU --[[ Simple harmonizer AZ, 2017 ]]-- local Scale = { Label = "Scale", Type = "Key", Value = 0, Min = 0, Max = 11 } local IsMajor = { Label = "Major scale", Type = "Bool", Value = false } local HarmonyType = { Label = "T-2, T-1, T+1, T+2", Type = "Int", Value = 0, Min = 0, Max = 3 } local KeepMelody = { Label = "Keep melody", Type = "Bool", Value = true } GUI = { Scale, IsMajor, HarmonyType, KeepMelody } local floor = math.floor -- from absolute note n (0 = c0 ) and root for scale ( 0 = c ) -- calculate octave and shift in that octave, so n = root + octave*12 + shift -- return base = root + octave*12 and shift function Normal( n, root ) n = n - root return root + floor( n / 12 )*12, n % 12 end -- For major , harmony tones in notes are 0, 4, 7 -- For minor , harmony tones in notes are 0, 3, 7 -- For both functions: -- integer n : absolute note number -- return integer harmony tone from basic triad function NextT( n ) local base, shift base, shift = Normal( n, Scale.Value ) if IsMajor.Value then if shift < 4 then return base + 4 end else if shift < 3 then return base + 3 end end if shift < 7 then return base + 7 end -- 0 in next octave return base + 12 end function PreviousT( n ) local base, shift base, shift = Normal( n, Scale.Value ) if shift > 7 then return base + 7 end if IsMajor.Value then if shift > 4 then return base + 4 end else if shift > 3 then return base + 3 end end if shift > 0 then return base end -- 7 in previous octave return base - 5 end -- Avoid hanging notes if we change parameters during playing local active = MfxOffNotes.new() function OnInput(pqIn, pqOut) for i,e in ipairs(pqIn) do e = active.move( e, pqOut ) -- process Note release correctly if e and e.Vel then -- Process Note and Note On only (Off processed by active) local t = e:copy() local tKey if HarmonyType.Value == 0 then tKey = PreviousT( t.Key ) -- T-1 tKey = PreviousT( tKey ) -- T-2 elseif HarmonyType.Value == 1 then tKey = PreviousT( t.Key ) -- T-1 elseif HarmonyType.Value == 2 then tKey = NextT( t.Key ) -- T+1 else -- HarmonyType.Value == 3 tKey = NextT( t.Key ) -- T+1 tKey = NextT( t.Key ) -- T+2 end if tKey >= 0 and tKey < 128 then -- is harmony inside note range ? t.Key = tKey active.add(t, e) pqOut.add(t) end if KeepMelody.Value then active.add(e, e) pqOut.add(e) end else pqOut.add(e) -- all other events end end end OnEvents = function ( From, To, pqIn, pqOut) OnInput(pqIn, pqOut) end