Help needed with a simple Duplex application

Hello, I don’t know what I’m doing. Trying to grasp duplex application programming and started ‘a simple project’ to begin with.

My humble goal is this: I’ve tinkered together a 3-fader touchosc layout for an iPad. Each fader has a set of 5 buttons below the fader. Now, what I want to do is to control currently selected note’s volume, panning and delay column values with these sliders. Don’t know how reasonable that is in the end, but that’s what my ‘simple project’ aims at. I’ve been at it for a couple of nights. Yesterday I got the touchosc layout done, and delved into duplex world. Tonight I’ve gotten the very basics of duplex application working, but I’m still quite lost.

Here’s what I’ve got so far in terms of files.

Touchosc layout: https://www.dropbox.com/s/gh4ryef1ux5uqqm/3faders.touchosc

Duplex controlmap: 3743 3faders.xml

Click to view contents

[xml]


TouchOSC 3faders

KMaki

3 faders with 5 buttons














































































































[/xml]

Duplex configuration file: 3744 3faders.lua

Click to view contents

(Never mind the comments… this was a copy-paste operation… :P)

  
--[[----------------------------------------------------------------------------  
-- Duplex.TouchOSC   
----------------------------------------------------------------------------]]--  
  
-- setup "Mixer + Recorder + Matrix" for this configuration  
  
duplex_configurations:insert {  
  
 -- configuration properties  
 name = "3faders VolPanDel",  
 pinned = true,  
  
 -- device properties  
 device = {  
 class_name = "TouchOSC",  
 display_name = "TouchOSC",  
 device_prefix = nil,  
 device_address = "10.0.0.2",  
 device_port_in = "8001",  
 device_port_out = "8081",  
 control_map = "Controllers/TouchOSC/Controlmaps/3faders.xml",  
 thumbnail = "Controllers/TouchOSC/TouchOSC.bmp",  
 protocol = DEVICE_OSC_PROTOCOL,  
 },  
  
 applications = {  
  
 VolPanDel = {  
  
 mappings = {  
  
 pan_fader = {  
 group_name = "top_fader",  
 index = 1,  
 },  
 pan_button1 = {  
 group_name = "top_buttons",  
 index = 1,  
 },  
 pan_button2 = {  
 group_name = "top_buttons",  
 index = 2,  
 },  
 pan_button3 = {  
 group_name = "top_buttons",  
 index = 3,  
 },  
 pan_button4 = {  
 group_name = "top_buttons",  
 index = 4,  
 },  
 pan_button5 = {  
 group_name = "top_buttons",  
 index = 5,  
 },  
  
 --  
  
 del_fader = {  
 group_name = "mid_fader",  
 index = 1,  
 },  
 del_button1 = {  
 group_name = "mid_buttons",  
 index = 1,  
 },  
 del_button2 = {  
 group_name = "mid_buttons",  
 index = 2,  
 },  
 del_button3 = {  
 group_name = "mid_buttons",  
 index = 3,  
 },  
 del_button4 = {  
 group_name = "mid_buttons",  
 index = 4,  
 },  
 del_button5 = {  
 group_name = "mid_buttons",  
 index = 5,  
 },  
  
 --  
  
 vol_fader = {  
 group_name = "bot_fader",  
 index = 1,  
 },  
 vol_button1 = {  
 group_name = "bot_buttons",  
 index = 1,  
 },  
 vol_button2 = {  
 group_name = "bot_buttons",  
 index = 2,  
 },  
 vol_button3 = {  
 group_name = "bot_buttons",  
 index = 3,  
 },  
 vol_button4 = {  
 group_name = "bot_buttons",  
 index = 4,  
 },  
 vol_button5 = {  
 group_name = "bot_buttons",  
 index = 5,  
 },  
 --  
 },  
 options = {},  
 palette = {},  
 }  
 }  
}  
  
  
  

Duplex application file: 3745 VolPanDel.lua

Click to view contents
  
class 'VolPanDel' (Application)  
  
VolPanDel.default_options = {}  
  
-----------  
  
function VolPanDel:__init(process,mappings,options,cfg_name,palette)  
 self.mappings = {  
 pan_fader = {  
 description = "Note panning 0-127",  
 },  
 pan_button1 = {  
 description = "Pan 25%"  
 },  
 pan_button2 = {  
 description = "Pan 25%"  
 },  
 pan_button3 = {  
 description = "Pan 50%"  
 },  
 pan_button4 = {  
 description = "Pan 75%"  
 },  
 pan_button5 = {  
 description = "Pan 100%"  
 },  
 --  
 del_fader = {  
 description = "Note delay 0-255",  
 },  
 del_button1 = {  
 description = "Delay 0%"  
 },  
 del_button2 = {  
 description = "Delay 25%"  
 },  
 del_button3 = {  
 description = "Delay 50%"  
 },  
 del_button4 = {  
 description = "Delay 75%"  
 },  
 del_button5 = {  
 description = "Delay 100%"  
 },  
 --  
 vol_fader = {  
 description = "Note volume 0-127",  
 },  
 vol_button1 = {  
 description = "Volume 0%"  
 },  
 vol_button2 = {  
 description = "Volume 25%"  
 },  
 vol_button3 = {  
 description = "Volume 50%"  
 },  
 vol_button4 = {  
 description = "Volume 75%"  
 },  
 vol_button5 = {  
 description = "Volume 100%"  
 },  
 --  
 }  
  
 Application.__init(self,process,mappings,options,cfg_name,palette)  
  
end  
  
function VolPanDel:start_app()  
 if not Application.start_app(self) then  
 return  
 end  
end  
  
function VolPanDel:_build_app()  
 do --create faders  
 local panf = UISlider(self.display)  
 panf.group_name = self.mappings.pan_fader.group_name  
 panf:set_pos(self.mappings.pan_fader.index)  
 panf.on_change = function(obj)  
 if not self.active then  
 return false  
 end  
 renoise.app():show_status("Pan change")  
 end  
 self:_add_component(panf)  
 self._panf = panf  
  
 local delf = UISlider(self.display)  
 delf.group_name = self.mappings.del_fader.group_name  
 delf:set_pos(self.mappings.del_fader.index)  
 delf.on_change = function(obj)  
 if not self.active then  
 return false  
 end  
 renoise.app():show_status("Delay change")  
 end  
 self:_add_component(delf)  
 self._delf = delf  
  
 local volf = UISlider(self.display)  
 volf.group_name = self.mappings.vol_fader.group_name  
 volf:set_pos(self.mappings.vol_fader.index)  
 volf.on_change = function(obj)  
 if not self.active then  
 return false  
 end  
 renoise.app():show_status("Vol change")  
 end  
 self:_add_component(volf)  
 self._volf = volf  
 end  
  
 --create buttons  
 --PAN  
 local panb1 = UIButton(self.display)  
 panb1.group_name = self.mappings.pan_button1.group_name  
 panb1.on_press = function(msg)  
 if (not self.active) then   
 return false   
 end  
 print("Pan button 1")  
 end  
 self:_add_component(panb1)  
 self._pan_button1 = panb1  
 --  
 local panb2 = UIButton(self.display)  
 panb2.group_name = self.mappings.pan_button2.group_name  
 panb2.on_press = function(msg)  
 if (not self.active) then   
 return false   
 end  
 print("Pan button2")  
 end  
 self:_add_component(panb2)  
 self._pan_button2 = panb2  
 --  
 local panb3 = UIButton(self.display)  
 panb3.group_name = self.mappings.pan_button3.group_name  
 panb3.on_press = function(msg)  
 if (not self.active) then   
 return false   
 end  
 print("Pan button3")  
 end  
 self:_add_component(panb3)  
 self._pan_button3 = panb3  
 --  
 local panb4 = UIButton(self.display)  
 panb4.group_name = self.mappings.pan_button4.group_name  
 panb4.on_press = function(msg)  
 if (not self.active) then   
 return false   
 end  
 print("Pan button4")  
 end  
 self:_add_component(panb4)  
 self._pan_button4 = panb4  
 --  
 local panb5 = UIButton(self.display)  
 panb5.group_name = self.mappings.pan_button5.group_name  
 panb5.on_press = function(msg)  
 if (not self.active) then   
 return false   
 end  
 print("Pan button5")  
 end  
 self:_add_component(panb5)  
 self._pan_button5 = panb5  
 --  
 --VOL  
 local volb1 = UIButton(self.display)  
 volb1.group_name = self.mappings.vol_button1.group_name  
 volb1.on_press = function(msg)  
 if (not self.active) then   
 return false   
 end  
 print("vol button1")  
 end  
 self:_add_component(volb1)  
 self._vol_button1 = volb1  
 --  
 local volb2 = UIButton(self.display)  
 volb2.group_name = self.mappings.vol_button2.group_name  
 volb2.on_press = function(msg)  
 if (not self.active) then   
 return false   
 end  
 print("vol button2")  
 end  
 self:_add_component(volb2)  
 self._vol_button2 = volb2  
 --  
 local volb3 = UIButton(self.display)  
 volb3.group_name = self.mappings.vol_button3.group_name  
 volb3.on_press = function(msg)  
 if (not self.active) then   
 return false   
 end  
 print("vol button3")  
 end  
 self:_add_component(volb3)  
 self._vol_button3 = volb3  
 --  
 local volb4 = UIButton(self.display)  
 volb4.group_name = self.mappings.vol_button4.group_name  
 volb4.on_press = function(msg)  
 if (not self.active) then   
 return false   
 end  
 print("vol button4")  
 end  
 self:_add_component(volb4)  
 self._vol_button4 = volb4  
 --  
 local volb5 = UIButton(self.display)  
 volb5.group_name = self.mappings.vol_button5.group_name  
 volb5.on_press = function(msg)  
 if (not self.active) then   
 return false   
 end  
 print("vol button5")  
 end  
 self:_add_component(volb5)  
 self._vol_button5 = volb5  
 --  
 return true  
end  
  
--[[  
--this gets either 'vol' 'pan' or 'del' value, in 0-1 scale  
function VolPanDel:get_value(val_type)  
 local min  
 local max  
 local value  
  
 if renoise.song().selected_note_column == nil then  
 return nil  
  
 elseif val_type == "vol" then  
 min = 0  
 max = 127  
 value = renoise.song().selected_note_column.volume_value  
 if value == 255 then value = 64 end  
  
 elseif val_type == "pan" then  
 min = 0  
 max = 127  
 value = renoise.song().selected_note_column.panning_value  
 if value == 255 then value = 64 end  
  
 elseif val_type == "del" then  
 local min = 0  
 local max = 255  
 local value = renoise.song().selected_note_column.delay_value  
  
 end  
  
 return value / max --not perfect yet.  
end  
  
--this gets either 'vol' 'pan' or 'del' value, in 0-1 scale  
function VolPanDel:set_value(val_type, value)  
 local min  
 local max  
  
 if renoise.song().selected_note_column == nil then  
 return nil  
  
 elseif val_type == "vol" then  
 min = 0  
 max = 127  
 if value == 255 then value = 64 end  
 renoise.song().selected_note_column.volume_value = max(min(value*max,max),min)  
  
 elseif val_type == "pan" then  
 min = 0  
 max = 127  
 renoise.song().selected_note_column.panning_value = max(min(value*max,max),min)  
  
 elseif val_type == "del" then  
 local min = 0  
 local max = 255  
 renoise.song().selected_note_column.delay_value = max(min(value*max,max),min)  
  
 end  
  
  
 return value / max --not perfect yet.  
end  
--]]  
  
  
  

At the moment I’m just familiarizing myself with the whole Duplex concept, and working to get a connection with A.) touchosc & duplex, and B.) duplex & renoise. Part A.) I think I’ve overcome, because I’ve got the faders kind of working. I was happy when I accomplished that. The duplex virtual control surface gets created all right (ugly at the moment), and the faders are in sync between my controller and renoise. I’ve even got an .on_change function for the faders. Just a placeholder that throws a status message, but at least they’re doing something.

It’s Part B.) I’m having difficulties with. Or rather, the entrails of Duplex are just too vast for me to comprehend.

I’m running into a serious brain melt with the buttons. I’m not quite sure what I’m supposed to do (or what I’m doing right now for that matter), but the problem is that when I press the first button in the top row, I get in response all .on_press functions from all the buttons in the group. This I’m deducing with printouts to terminal. The other buttons are not responding at all. The duplex layout states they are “(unassigned)”. Huh?

What I’d eventually like the buttons to do is to just quickly set the volume/panning/delay to 0%, 25%, 50%, 75% or 100%.

Is there some other on-hands documentation than this post: Creating a simple duplex application, and the duplex docs? I admit I’ve maybe strayed off to areas of tool development reserved to pure genius, but I’d like to give it a shot anyway. I’ve used the post behind the link as a reference with my endeavor. I’ve also skimmed through some existing duplex files.

And. If someone could maybe give a hint on what’s going on with the buttons, I’d appreciate it very much. :)

Hey, thats funny - I purchased an iPad just yesterday, so finally I am able to support/develop stuff for TouchOSC again :slight_smile:

Nothing is “wrong” per se, it’s simply that your application doesn’t tell the buttons where they should be located (set_pos).
It’s not enough to state it in the configuration, you actually need the application to “apply” those settings somehow.

I took your example and modified it a bit: initialization code is now using the new syntax (will only work with recent beta’s),
and the buttons are laid out using the “set_pos” method

[details=“Click to view contents”] class ‘VolPanDel’ (Application)

VolPanDel.default_options = {}
VolPanDel.default_palette = {}

VolPanDel.available_mappings = {
pan_fader = {
description = “Note panning 0-127”,
},
pan_button1 = {
description = “Pan 25%”
},
pan_button2 = {
description = “Pan 25%”
},
pan_button3 = {
description = “Pan 50%”
},
pan_button4 = {
description = “Pan 75%”
},
pan_button5 = {
description = “Pan 100%”
},

del_fader = {
description = “Note delay 0-255”,
},
del_button1 = {
description = “Delay 0%”
},
del_button2 = {
description = “Delay 25%”
},
del_button3 = {
description = “Delay 50%”
},
del_button4 = {
description = “Delay 75%”
},
del_button5 = {
description = “Delay 100%”
},

vol_fader = {
description = “Note volume 0-127”,
},
vol_button1 = {
description = “Volume 0%”
},
vol_button2 = {
description = “Volume 25%”
},
vol_button3 = {
description = “Volume 50%”
},
vol_button4 = {
description = “Volume 75%”
},
vol_button5 = {
description = “Volume 100%”
},

}


function VolPanDel:__init(…)

Application.__init(self,…)

end

function VolPanDel:start_app()
if not Application.start_app(self) then
return
end
end

function VolPanDel:_build_app()
do --create faders
local panf = UISlider(self.display)
panf.group_name = self.mappings.pan_fader.group_name
panf:set_pos(self.mappings.pan_fader.index)
panf.on_change = function(obj)
if not self.active then
return false
end
renoise.app():show_status(“Pan change”)
end
self:_add_component(panf)
self._panf = panf

local delf = UISlider(self.display)
delf.group_name = self.mappings.del_fader.group_name
delf:set_pos(self.mappings.del_fader.index)
delf.on_change = function(obj)
if not self.active then
return false
end
renoise.app():show_status(“Delay change”)
end
self:_add_component(delf)
self._delf = delf

local volf = UISlider(self.display)
volf.group_name = self.mappings.vol_fader.group_name
volf:set_pos(self.mappings.vol_fader.index)
volf.on_change = function(obj)
if not self.active then
return false
end
renoise.app():show_status(“Vol change”)
end
self:_add_component(volf)
self._volf = volf
end

–create buttons
–PAN
local panb1 = UIButton(self.display)
panb1.group_name = self.mappings.pan_button1.group_name
panb1:set_pos(self.mappings.pan_button1.index)
panb1.on_press = function(msg)
if (not self.active) then
return false
end
print(“Pan button 1”)
end
self:_add_component(panb1)
self._pan_button1 = panb1

local panb2 = UIButton(self.display)
panb2.group_name = self.mappings.pan_button2.group_name
panb2:set_pos(self.mappings.pan_button2.index)
panb2.on_press = function(msg)
if (not self.active) then
return false
end
print(“Pan button2”)
end
self:_add_component(panb2)
self._pan_button2 = panb2

local panb3 = UIButton(self.display)
panb3.group_name = self.mappings.pan_button3.group_name
panb3:set_pos(self.mappings.pan_button3.index)
panb3.on_press = function(msg)
if (not self.active) then
return false
end
print(“Pan button3”)
end
self:_add_component(panb3)
self._pan_button3 = panb3

local panb4 = UIButton(self.display)
panb4.group_name = self.mappings.pan_button4.group_name
panb4:set_pos(self.mappings.pan_button4.index)
panb4.on_press = function(msg)
if (not self.active) then
return false
end
print(“Pan button4”)
end
self:_add_component(panb4)
self._pan_button4 = panb4

local panb5 = UIButton(self.display)
panb5.group_name = self.mappings.pan_button5.group_name
panb5:set_pos(self.mappings.pan_button5.index)
panb5.on_press = function(msg)
if (not self.active) then
return false
end
print(“Pan button5”)
end
self:_add_component(panb5)
self._pan_button5 = panb5

–VOL
local volb1 = UIButton(self.display)
volb1.group_name = self.mappings.vol_button1.group_name
volb1:set_pos(self.mappings.pan_button2.index)
volb1.on_press = function(msg)
if (not self.active) then
return false
end
print(“vol button1”)
end
self:_add_component(volb1)
self._vol_button1 = volb1

local volb2 = UIButton(self.display)
volb2.group_name = self.mappings.vol_button2.group_name
volb2.on_press = function(msg)
if (not self.active) then
return false
end
print(“vol button2”)
end
self:_add_component(volb2)
self._vol_button2 = volb2

local volb3 = UIButton(self.display)
volb3.group_name = self.mappings.vol_button3.group_name
volb3.on_press = function(msg)
if (not self.active) then
return false
end
print(“vol button3”)
end
self:_add_component(volb3)
self._vol_button3 = volb3

local volb4 = UIButton(self.display)
volb4.group_name = self.mappings.vol_button4.group_name
volb4.on_press = function(msg)
if (not self.active) then
return false
end
print(“vol button4”)
end
self:_add_component(volb4)
self._vol_button4 = volb4

local volb5 = UIButton(self.display)
volb5.group_name = self.mappings.vol_button5.group_name
volb5.on_press = function(msg)
if (not self.active) then
return false
end
print(“vol button5”)
end
self:_add_component(volb5)
self._vol_button5 = volb5

return true
end

–[[
–this gets either ‘vol’ ‘pan’ or ‘del’ value, in 0-1 scale
function VolPanDel:get_value(val_type)
local min
local max
local value

if renoise.song().selected_note_column == nil then
return nil

elseif val_type == “vol” then
min = 0
max = 127
value = renoise.song().selected_note_column.volume_value
if value == 255 then value = 64 end

elseif val_type == “pan” then
min = 0
max = 127
value = renoise.song().selected_note_column.panning_value
if value == 255 then value = 64 end

elseif val_type == “del” then
local min = 0
local max = 255
local value = renoise.song().selected_note_column.delay_value

end

return value / max --not perfect yet.
end

–this gets either ‘vol’ ‘pan’ or ‘del’ value, in 0-1 scale
function VolPanDel:set_value(val_type, value)
local min
local max

if renoise.song().selected_note_column == nil then
return nil

elseif val_type == “vol” then
min = 0
max = 127
if value == 255 then value = 64 end
renoise.song().selected_note_column.volume_value = max(min(value*max,max),min)

elseif val_type == “pan” then
min = 0
max = 127
renoise.song().selected_note_column.panning_value = max(min(value*max,max),min)

elseif val_type == “del” then
local min = 0
local max = 255
renoise.song().selected_note_column.delay_value = max(min(value*max,max),min)

end

return value / max --not perfect yet.
end
–]]

[/details]

Ag! So THAT’s what the set_pos was for. Ok, I think I’ll get this train rolling again. Muchos Gracias! :)

–EDIT:

Beautiful! Numbers rolling on the editor now. B) Now must still get the faders to update on line change etc…

Well. But here’s the application now: 3748 VolPanDel.lua

Click to view contents
  
class 'VolPanDel' (Application)  
  
  
  
VolPanDel.default_options = {}  
  
VolPanDel.default_palette = {}  
  
  
  
VolPanDel.available_mappings = {  
  
 pan_fader = {  
 description = "Note panning 0-127",  
 },  
  
 pan_button1 = {  
 description = "Pan 0%"  
 },  
  
 pan_button2 = {  
 description = "Pan 25%"  
 },  
  
 pan_button3 = {  
 description = "Pan 50%"  
 },  
  
 pan_button4 = {  
 description = "Pan 75%"  
 },  
  
 pan_button5 = {  
 description = "Pan 100%"  
 },  
  
 --  
  
 del_fader = {  
 description = "Note delay 0-255",  
 },  
  
 del_button1 = {  
 description = "Delay 0%"  
 },  
  
 del_button2 = {  
 description = "Delay 25%"  
 },  
  
 del_button3 = {  
 description = "Delay 50%"  
 },  
  
 del_button4 = {  
 description = "Delay 75%"  
 },  
  
 del_button5 = {  
 description = "Delay 100%"  
 },  
  
 --  
  
 vol_fader = {  
 description = "Note volume 0-127",  
 },  
  
 vol_button1 = {  
 description = "Volume 0%"  
 },  
  
 vol_button2 = {  
 description = "Volume 25%"  
 },  
  
 vol_button3 = {  
 description = "Volume 50%"  
 },  
  
 vol_button4 = {  
 description = "Volume 75%"  
 },  
  
 vol_button5 = {  
 description = "Volume 100%"  
 },  
  
 --  
  
}  
  
  
  
  
  
-----------  
  
  
  
function VolPanDel:__init(...)  
  
 Application.__init(self,...)  
  
end  
  
  
  
function VolPanDel:start_app()  
  
 if not Application.start_app(self) then  
 return  
 end  
  
end  
  
  
  
function VolPanDel:_build_app()  
  
 do --create faders  
 local panf = UISlider(self.display)  
 panf.group_name = self.mappings.pan_fader.group_name  
 panf:set_pos(self.mappings.pan_fader.index)  
 panf.on_change = function(obj)  
  
 if not self.active then  
 return false  
 end  
  
 --renoise.app():show_status("Pan change")  
 self:set_value("pan", self._panf.value)  
  
 end  
  
 self:_add_component(panf)  
 self._panf = panf  
  
 --  
  
 local delf = UISlider(self.display)  
 delf.group_name = self.mappings.del_fader.group_name  
 delf:set_pos(self.mappings.del_fader.index)  
 delf.on_change = function(obj)  
  
 if not self.active then  
 return false  
 end  
  
 --renoise.app():show_status("Delay change")  
 self:set_value("del", self._delf.value)  
  
 end  
  
 self:_add_component(delf)  
 self._delf = delf  
  
 --  
  
 local volf = UISlider(self.display)  
 volf.group_name = self.mappings.vol_fader.group_name  
 volf:set_pos(self.mappings.vol_fader.index)  
 volf.on_change = function(obj)  
  
 if not self.active then  
 return false  
 end  
  
 --renoise.app():show_status("Vol change")  
 self:set_value("vol", self._volf.value)  
  
 end  
  
 self:_add_component(volf)  
  
 self._volf = volf  
 end  
  
 do --create buttons  
 --PAN  
 for index = 1, 5 do  
 local c = UIButton(self.display)  
 local c_name = "pan_button"..index   
 c.group_name = self.mappings[c_name].group_name  
 c:set_pos(self.mappings[c_name].index)  
 c.on_press = function(msg)  
 if (not self.active) then   
 return false   
 end  
  
 --print(c_name)  
 self:set_value("pan", ( (index-1) * 0.25 ) )  
  
 end  
 self:_add_component(c)  
 self[c_name] = c  
 end  
 --VOL  
 for index = 1, 5 do  
 local c = UIButton(self.display)  
 local c_name = "vol_button"..index   
 c.group_name = self.mappings[c_name].group_name  
 c:set_pos(self.mappings[c_name].index)  
 c.on_press = function(msg)  
 if (not self.active) then   
 return false   
 end  
 --print(c_name)  
 self:set_value("vol", ( (index-1) * 0.25 ) )  
 end  
 self:_add_component(c)  
 self[c_name] = c  
 end  
 --DEL  
 for index = 1, 5 do  
 local c = UIButton(self.display)  
 local c_name = "del_button"..index   
 c.group_name = self.mappings[c_name].group_name  
 c:set_pos(self.mappings[c_name].index)  
 c.on_press = function(msg)  
 if (not self.active) then   
 return false   
 end  
 --print(c_name)  
 self:set_value("del", ( (index-1) * 0.25 ) )  
 end  
 self:_add_component(c)  
 self[c_name] = c  
 end  
 end  
  
 return true  
  
end  
  
  
  
  
  
function VolPanDel:get_value(val_type)  
 --this gets either 'vol' 'pan' or 'del' value, in 0-1 scale  
 local min  
 local max  
 local value  
  
 if renoise.song().selected_note_column == nil then  
 return nil  
  
 elseif val_type == "vol" then  
 min = 0  
 max = 127  
 value = renoise.song().selected_note_column.volume_value  
 if value == 255 then value = 64 end  
  
 elseif val_type == "pan" then  
 min = 0  
 max = 127  
 value = renoise.song().selected_note_column.panning_value  
 if value == 255 then value = 64 end  
  
 elseif val_type == "del" then  
 local min = 0  
 local max = 255  
 local value = renoise.song().selected_note_column.delay_value  
  
 end  
  
 return value / max  
  
end  
  
  
  
  
function VolPanDel:set_value(val_type, value)  
 --this gets either 'vol' 'pan' or 'del' value, in 0-1 scale  
 local min  
 local max  
  
 if renoise.song().selected_note_column == nil then  
 return nil  
  
 elseif val_type == "vol" then  
 min = 0  
 max = 127  
 if value == 255 then value = 64 end  
 --other checks!  
 renoise.song().selected_note_column.volume_value = math.max(math.min(value*max,max),min)  
  
 elseif val_type == "pan" then  
 min = 0  
 max = 127  
 renoise.song().selected_note_column.panning_value = math.max(math.min(value*max,max),min)  
  
 elseif val_type == "del" then  
 local min = 0  
 local max = 255  
 renoise.song().selected_note_column.delay_value = math.max(math.min(value*max,max),min)  
  
 end  
  
 return true  
  
end  
  
  

Yay! This can only mean one thing: the control-velocity-through-accelerometer-z-feature is coming! Hooray! Hooray!

;)