Bass Coupler Lua Script

Discussion of all things related to MOTU's awesome MachFive software sampler.

Moderator: James Steele

Post Reply
nnebeel
Posts: 2
Joined: Fri Nov 15, 2013 3:46 pm
Primary DAW OS: Windows

Bass Coupler Lua Script

Post by nnebeel »

Hello! I just finished coding a bass coupler script for MachFive 3. It works so well, I thought I'd share it. It will be useful for our community orchestra/choir performance of Handel's The Messiah in December.

Code: Select all

--[[
Bass Coupler
Version 1.0 coded 11/15/2013
Especially for MachFive 3
---------------------------------
Coded by nnebeel in 12 hours of straight coding
Buy me a meal!
https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=S3Q3MWXAD7RSG

Apply this script to a part to cause only the lowest note to play. A Split Point knob is available. Notes above the split point will not play. This script is especially useful as a bass coupler during live organ performance with a single MIDI keyboard:

Part 1 (without a script)
	Organ voice, which is generally centered on 8' (native) pitch
Part 2 (same input channel as part 1, but with Bass Coupler script)
	Pedal voice, which is generally centered on 16' (8vb) pitch

As you perform, all notes will be played in part 1, but only the bottom note will be played in part 2.

Note: to better accommodate pianists' nonlegato touch, some organ bass couplers do not support legato chord changes. This script allows legato chord changes, which might take some getting used to for pianists (but is worth it in the long run).
]]

print("Buy me a meal! https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=S3Q3MWXAD7RSG")
local limit = Knob("Split Point", 127, 0, 127, true)
local heldNotes = {}

function findLow(array)
	if #array == 0 then
		return nil, nil, nil
	else
		local tempNote = 128
		local tempLoc = 128
		for i, v in ipairs(array) do
			if v.note < tempNote then
				tempNote = v.note
				tempVel = v.velocity
				tempLoc = i
			end
		end
		return tempLoc, tempNote, tempVel
	end
end

function findNote(array, note)
	if #array == 0 then
		print("Error: array does not exist. Cannot find note " .. note)
		return false
	else
		for i, v in ipairs(array) do
			if v.note == note then
				return i
			end
		end
		print("Error: note " .. note .. " not found in array")
		return false
	end
end

function limitTest(a, vel)
	if a <= limit.value then
		return vel
	else
		return 0
	end
end

function onEvent(e)
	-- NOTE OFF
	if e.type == Event.NoteOff then
		local lowLoc, lowNote, lowVel = findLow(heldNotes)
		-- delete the note from the table
		table.remove(heldNotes, findNote(heldNotes, e.note))
		if e.note == lowNote then
			if #heldNotes > 0 then
				--find and release new low note
				lowLoc, lowNote, lowVel = findLow(heldNotes)
				heldNotes[lowLoc].type = Event.NoteOff
				postEvent(heldNotes[lowLoc])
				--play new low note
				local tempVel = heldNotes[lowLoc].velocity
				heldNotes[lowLoc].velocity = limitTest(e.note, e.velocity)
				heldNotes[lowLoc].type = Event.NoteOn
				postEvent(heldNotes[lowLoc])
				heldNotes[lowLoc].velocity = tempVel
			end
		end
		--post event
		postEvent(e)
	-- NOTE ON
	elseif e.type == Event.NoteOn then
		local lowLoc, lowNote, lowVel = findLow(heldNotes)
		--add the new  note to the table
		table.insert(heldNotes, e)
		local tempVel = e.velocity		
		if lowLoc == nil then
			--play the new note
			e.velocity = limitTest(e.note, e.velocity)
		elseif e.note < lowNote then
			--release the old low note
			heldNotes[lowLoc].type = Event.NoteOff
			postEvent(heldNotes[lowLoc])
			--play the new note
			e.velocity = limitTest(e.note, e.velocity)
		else			
			--insert note into table
			e.velocity = 0
		end		
		--post event		
		postEvent(e)
		e.velocity = tempVel
	end
end
Enjoy! Any feedback is welcome!
nnebeel
Posts: 2
Joined: Fri Nov 15, 2013 3:46 pm
Primary DAW OS: Windows

Re: Bass Coupler Lua Script

Post by nnebeel »

Is anybody having trouble changing voices while this script is enabled? I might need to add a couple of lines of code at the end.
Post Reply