Lua Automation to MIDI script

Hey folks,

i am currently working on livesets for several events, which includes tesla coils making lightnings controlled by MIDI. These tesla coils are controlled via MIDI information i send out from Ardour. Unfortunately it is not very easy/intuitive to use a blank midi track as a midi source for this project. So i was thinking about making a DSP lua script to do this. I am a complete beginner and am still overwhelmed even after watching x42’s new lecture.
Can someone help me out with a simple lua script which i can then customize to my needs?

The plugin would need to output midi. (CC Values and Programmchange)

I would need some sliders which i can rename and are associated to midi cc values.
e.g. one slider labeled Attack, assigned to cc 100.

And also one slider for sending programmchange values.

So i basically need a tool to create automations for cc values and Programmchange and convert them into midi which i can send to the tesla coils later.

Any help or hints are apreciated! :slight_smile:

1 Like

Cool!

Forgive me if you are already aware, but there is a standard called DMX512 which is used for live music shows, theatre, and DJ’s. There is hardware which can accept MIDI data and control DMX512 specifically compatible lights, or interface with other standards.

There are a number of affordable controllers which output MIDI data which is great to sync with an audio track, or even live performances. So Ardour would be great for the MIDI storage and replay component.

Sorry I can’t provide any detail, haven’t done it. Got curious when I started reading about someones extensive Holiday display.

Sounds like you’ve got some special hardware to interface!

Good luck and let us know about your ultimate success.

2 Likes

This should be a decent basis to start from: https://github.com/jean-emmanuel/lua_scripts/blob/master/midi_cc_generator.lua.

2 Likes

DMX is a great shout and, if the tesla coil hardware isn’t already built for MIDI, I would consider making it work with DMX instead. It’ might be a better fit. I think it depends whether it’s musical data going to them, or simple control data.

Irrespective, for show control, it might be worth looking at QLC+

QLC+ is a show lighting/effects console application especially designed to run this sort of show, and to work with DMX devices. It’s primarily used for lighting rigs but will handle anything that supports DMX512.

It also supports MIDI, OSC, and some other protocols. You can use it, for example. to consume a MIDI beat clock and synchronise DMX lighting to it, or to control MIDI devices, like the Tesla coils.

As it works with both MIDI and DMX, something like QLC+ would make it easy to supplement the show with other lighting and practical effects (e.g. smoke machines, lasers).

Relatively cheap DMX USB interfaces can be used with it, and you can run it headless on a Raspberry Pi with a tablet for the cues.

I’ve used DMX a fair bit, as I used to do sound and lightning for some local bands and shows. I also have a small DMX rig here at home.

Cheers,

Keith

2 Likes

Amazing! This is allready a huge step forward! A lot of things in there i would not have thought to be necessary!
Thank you so much! :slight_smile:

Could you also give me a hint on how to add a programm change?

So i got given a little synthesizer which accepts midi information and can give out an audio signal to rehearse and also an optical signal which directly controlls the tesla coils.
They are more of an instrument then a lightshow effect. This synthesizer box has several patches like fm, am or drum sounds which are then recreated by the lightnings.
The system is allready built so i do not have influence on how to controll it really. Using MIDI is pretty convenient as musicians usually know how to use that. :smiley:

1 Like

I will definetly have a look at qlc+ sometime anyhow! Thanks for the recommendation!

1 Like

Nevermind, deepseek solved it for me!
Thanks again! :slight_smile:

could you share what it is?

Sure! This is what i ended up with.
This is allready with more or less correct labels for each slider. :slight_smile:

ardour {
	["type"]    = "dsp",
	name        = "MIDI CC Generator",
	category    = "Utility",
	license     = "GNU/GPL v3",
	author      = "Jean-Emmanuel Doucet",
	description = [[MIDI CC Generator - Exposes all CC as faders and inline controls]]
}

local state = {}
local params = {}

-- expose all 128 CCs
--for i = 1, 128 do
--	params[i] = { ["type"] = "input", cc = i - 1, name = "CC" .. (i - 1), doc="Set to -1 to bypass", min = -1, max = 127,  default = -1, integer = true }
--end

-- or comment above loop and manually define which CCs should be exposed:
params[2] = { ["type"] = "input", cc = 102, name = "Attack", doc="Set to -1 to bypass", min = -1, max = 127,  default = -1, integer = true }
params[3] = { ["type"] = "input", cc = 103, name = "Deacay", doc="Set to -1 to bypass", min = -1, max = 127,  default = -1, integer = true }
params[4] = { ["type"] = "input", cc = 104, name = "Sustain", doc="Set to -1 to bypass", min = -1, max = 127,  default = -1, integer = true }
params[5] = { ["type"] = "input", cc = 105, name = "Release", doc="Set to -1 to bypass", min = -1, max = 127,  default = -1, integer = true }
params[6] = { ["type"] = "input", cc = 10, name = "Pan", doc="Set to -1 to bypass", min = -1, max = 127,  default = -1, integer = true }
params[7] = { ["type"] = "input", cc = 7, name = "Volume", doc="Set to -1 to bypass", min = -1, max = 127,  default = -1, integer = true }
params[8] = { ["type"] = "input", cc = 106, name = "Mod1", doc="Set to -1 to bypass", min = -1, max = 127,  default = -1, integer = true }
params[9] = { ["type"] = "input", cc = 107, name = "Mod2", doc="Set to -1 to bypass", min = -1, max = 127,  default = -1, integer = true }
params[10] = { ["type"] = "input", cc = 123, name = "Panic", doc="Set to -1 to bypass", min = -1, max = 127,  default = -1, integer = true }




-- Add Program Change parameter
params[1] = { ["type"] = "input", name = "Program Change", doc="Set to -1 to bypass, 0-127 for program change", min = -1, max = 20, default = -1, integer = true }

for i = 1, #params do
	state[i] = -1
end

function dsp_ioconfig ()
	return { { midi_in = 1, midi_out = 1, audio_in = 0, audio_out = 0}, }
end

function dsp_params ()
	return params
end

function dsp_run (_, _, n_samples)
	assert (type(midiin) == "table")
	assert (type(midiout) == "table")

	local ctrl = CtrlPorts:array ()
	local m = 1

	-- handle Program Change separately
	local pc_param_index = 1  -- index of our Program Change parameter
	if ctrl[pc_param_index] ~= -1 and ctrl[pc_param_index] ~= state[pc_param_index] then
		local pc_value = math.floor(ctrl[pc_param_index] + 0.5)
		midiout[m] = {}
		midiout[m]["time"] = 1
		midiout[m]["data"] = { 0xC0, pc_value }  -- 0xC0 is Program Change status byte
		m = m + 1
		state[pc_param_index] = pc_value
	end

	-- inject midi cc (skip the Program Change parameter)
	for i, param in ipairs(params) do
		if i ~= pc_param_index then
			-- only send once per cycle if value has changed
			if ctrl[i] == -1 then
				-- reset cc to zero when sliding to -1 quickly
				if state[i] > 0 then
					midiout[m] = {}
					midiout[m]["time"] = 1
					midiout[m]["data"] = { 0xb0, param["cc"], 0 }
					m = m + 1
				end
				state[i] = -1
			else
				-- round cc value in case of automation
				local rctrl = math.floor(ctrl[i] + 0.5)
				if rctrl ~= state[i] then
					midiout[m] = {}
					midiout[m]["time"] = 1
					midiout[m]["data"] = { 0xb0, param["cc"], rctrl }
					m = m + 1
					state[i] = rctrl
				end
			end
		end
	end

	-- forward incoming midi
	-- From MIDI LFO @ Ardour Team
	local i = 1
	for ts = 1, n_samples do
		if i <= #midiin then
			while midiin[i]["time"] == ts do
				midiout[m] = midiin[i]
				i = i + 1
				m = m + 1
				if i > #midiin then break end
			end
		end
	end
end

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.