
-- set up values used by the handler functions

local nrpnScale = 1.0/16383.0
local ccScale = 1.0/127.0
local paramID_Pitch 			= getParameterID( "Pitch" )
local paramID_DelaySliderMin 	= getParameterID( "Delay Slider Min" )
local paramID_DelaySliderMax 	= getParameterID( "Delay Slider Max" )
local paramID_DelayTime 		= getParameterID( "Delay Time" )
local paramID_Beats				= getParameterID( "Beats" )
local paramID_BeatDivisor		= getParameterID( "Beat Divisor" )
local paramID_FilterCutoff		= getParameterID( "Filter Cutoff" )
local paramID_FilterLFOSpeed	= getParameterID( "Filter LFO Speed" )
local paramID_PitchLFOSpeed		= getParameterID( "Pitch LFO Speed" )
local ccMap = {
	[5] = getParameterID( "Master feedback" ),
	[14] = getParameterID( "Monoize Input" ),
	[15] = getParameterID( "Initial Pan" ),
	[18] = getParameterID( "Pitch" ),
	[19] = getParameterID( "PitchInertia" ),
	[20] = getParameterID( "Dry Level" ),
	[21] = getParameterID( "Effect Level" ),
	[22] = getParameterID( "Input Level" ),
	[23] = getParameterID( "L->L time" ),
	[24] = getParameterID( "L->R time" ),
	[25] = getParameterID( "R->L time" ),
	[26] = getParameterID( "R->R time" ),
	[27] = getParameterID( "Filter LFO Speed" ),
	[28] = getParameterID( "Filter LFO Depth" ),
	[29] = getParameterID( "Pitch LFO Depth" ),
	[31] = getParameterID( "Host Sync" ),
	[32] = getParameterID( "Triplet" ),
	[33] = getParameterID( "Beats" ),
	[34] = getParameterID( "Beat Divisor" ),
	[70] = getParameterID( "R->L feedback" ),
	[71] = getParameterID( "Filter Q" ),
	[72] = getParameterID( "R->R feedback" ),
	[73] = getParameterID( "L->L feedback" ),
	[74] = getParameterID( "Filter Cutoff" ),
	[75] = getParameterID( "L->R feedback" ),
	[76] = getParameterID( "Pitch LFO Speed" ),
	[78] = getParameterID( "Trigger" ),
	[79] = getParameterID( "Saturation" ),
	[80] = getParameterID( "Saturation Shape" ),
	[81] = getParameterID( "Saturation On/Off" ),
	[85] = getParameterID( "Filter Type" ),
	[86] = getParameterID( "Freeze Loop" ),
	[87] = getParameterID( "Tap Tempo" ),
	[88] = getParameterID( "Pause Clock" ),
	[89] = getParameterID( "Reverse" ),
	[92] = getParameterID( "Tap Record" ),
	[96] = getParameterID( "Env Attack" ),
	[97] = getParameterID( "Env Release" ),
	[100] = getParameterID( "Clear Loop" ),
	[101] = getParameterID( "Punch In Quantize" ),
	[102] = getParameterID( "Punch Out Quantize" ),
	[103] = getParameterID( "Punch Out Type" ),
	[104] = getParameterID( "Punch In Set Input Level" ),
	[105] = getParameterID( "Punch Out Set Input Level" ),
	[106] = getParameterID( "Auto Clear After Fade" ),
	[107] = getParameterID( "Env Gate" ),
	[108] = getParameterID( "Env Override" ),
	[109] = getParameterID( "Delay Inertia Mode" ),
	[110] = getParameterID( "Delay Inertia Fade Time" ),
	[111] = getParameterID( "Digital Mode" ),
	[112] = getParameterID( "Stop" ),
	[114] = getParameterID( "Tape Read Mode" ),
	[115] = getParameterID( "Sync Group Mode" ),
	[116] = getParameterID( "Sync Group Number" ),
	[117] = getParameterID( "Freeze Mode" ),
	[118] = getParameterID( "Low Cut Freq" ),
	[119] = getParameterID( "Low Cut Amount" ),
	[120] = getParameterID( "High Cut Freq" ),
	[121] = getParameterID( "High Cut Amount" ),
	[122] = getParameterID( "Crunch" ),
	[123] = getParameterID( "Drive" ),
	[124] = getParameterID( "Post Gain" ),
}
local nrpnMap = {
	[128] = getParameterID( "Delay Slider Min" ),
	[129] = getParameterID( "Delay Slider Max" ),
	[130] = getParameterID( "Delay Time" ),
}

-- define the handler functions

-- set the pitch via note on messages
local function handleNoteOn( channel, noteNumber, velocity )
	if not prefRxAllChannels then
		if channel ~= 2 then
			return
		end
	end
	-- the pitch is centred on middle C (note number 60)
	local pitch = noteNumber - 60
	if pitch >= -12 and pitch <= 12 then
		setParameter( paramID_Pitch, pitch )
	end
end

-- set most parameters via CC messages
local function handleCC( channel, cc, value )
	if not prefRxAllChannels then
		if channel ~= 1 then
			return
		end
	end
	-- look up the cc in the table
	local param = ccMap[ cc ]
	if param then
		local minv, maxv = getParameterMinMax( param )
		-- scale the value
		if param == paramID_Pitch then
			if value <= 64 then
				value = value / 128.0
			else
				value = 0.5 + ( value - 64 ) * ( 0.5/63.0 )
			end
		elseif param == paramID_Beats or param == paramID_BeatDivisor then
			value = value
		else
			value = value * ccScale
		end
		-- offset the value
		if param == paramID_FilterCutoff or param == paramID_FilterLFOSpeed or param == paramID_PitchLFOSpeed then
			-- log2( x ) == log( x ) / log( 2 ) == log( x ) * 1.4426950409
			value = minv * math.pow( 2.0, math.log( maxv/minv ) * 1.4426950409 * value )
		elseif param == paramID_Beats then
			value = value + 1
		elseif param == paramID_BeatDivisor then
			value = value
		else
			value = minv + value * ( maxv - minv )
		end
		setParameter( param, value )
	end
end

-- set parameters via NRPN messages
local function handleNRPN( channel, nrpn, value )
	if not prefRxAllChannels then
		if channel ~= 1 then
			return
		end
	end
	-- look up the nrpn in the table
	local param = nrpnMap[ nrpn ]
	if param then
		local minv, maxv = getParameterMinMax( param )
		setParameter( param, minv + nrpnScale * value * ( maxv - minv ) )
	end
end

-- set the delay slider
-- value has been scaled to 0.0-1.0 range
local function handleDelaySlider( channel, value )
	if not prefRxAllChannels then
		if channel ~= 1 then
			return
		end
	end
	-- calculate the delay value from the slider settings
	local minv = getParameter( paramID_DelaySliderMin )
	local maxv = getParameter( paramID_DelaySliderMax )
	setParameter( paramID_DelayTime, minv + value * ( maxv - minv ) )
end

-- set up the MIDI events we're interested in

requestAllNoteOn( handleNoteOn )
requestAllCC( handleCC )
requestAllNRPN( handleNRPN )
requestCC( 12, function( channel, cc, value ) handleDelaySlider( channel, value * ccScale ) end )
requestNRPN( 131, function( channel, nrpn, value ) handleDelaySlider( channel, value * nrpnScale ) end )
