From e6c3d7856895a2fccf4266e30c0de4f3d6bfb104 Mon Sep 17 00:00:00 2001
From: m1macrophage <168948267+m1macrophage@users.noreply.github.com>
Date: Sat, 1 Mar 2025 13:09:35 -0800
Subject: [PATCH] linn/linndrum.cpp: Made knobs controllable by pointing
device. (#13433)
---
src/mame/layout/linn_linndrum.lay | 131 ++++++++++++++++++------------
src/mame/linn/linndrum.cpp | 7 +-
2 files changed, 81 insertions(+), 57 deletions(-)
diff --git a/src/mame/layout/linn_linndrum.lay b/src/mame/layout/linn_linndrum.lay
index f755488d13f..71fe129471f 100644
--- a/src/mame/layout/linn_linndrum.lay
+++ b/src/mame/layout/linn_linndrum.lay
@@ -224,7 +224,7 @@ copyright-holders:m1macrophage
-
+
@@ -596,6 +596,15 @@ copyright-holders:m1macrophage
function()
local view = file.views["Default Layout"]
install_slider_callbacks(view)
+
+ local sweep_scale = 1.2
+ add_simplecounter_knob(view, "knob_pot_tempo", "pot_tempo", sweep_scale)
+ add_simplecounter_knob(view, "knob_pot_volume", "pot_volume", sweep_scale)
+ for i = 1, 7 do
+ local knob_input = "pot_tuning_" .. i
+ add_simplecounter_knob(view, "knob_" .. knob_input, knob_input, sweep_scale)
+ end
+
for i = 1, 16 do
local pan_input = "pot_pan_" .. i
add_vertical_slider(view, "slider_" .. pan_input, "slider_knob_" .. pan_input, pan_input)
@@ -605,47 +614,57 @@ copyright-holders:m1macrophage
end)
-----------------------------------------------------------------------
- -- Slider library starts.
+ -- Slider and knob library starts.
-- Can be copied as-is to other layouts.
-----------------------------------------------------------------------
- local sliders = {} -- Stores slider information.
+ local widgets = {} -- Stores slider and knob information.
local pointers = {} -- Tracks pointer state.
-- The knob's Y position must be animated using .
-- The click area's vertical size must exactly span the range of the
-- knob's movement.
function add_vertical_slider(view, clickarea_id, knob_id, port_name)
- local slider = {}
+ table.insert(widgets, {
+ clickarea = get_layout_item(view, clickarea_id),
+ slider_knob = get_layout_item(view, knob_id),
+ field = get_port_field(port_name),
+ is_knob = false })
+ end
- slider.clickarea = view.items[clickarea_id]
- if slider.clickarea == nil then
- emu.print_error("Slider element: '" .. clickarea_id .. "' not found.")
- return
- end
-
- slider.knob = view.items[knob_id]
- if slider.knob == nil then
- emu.print_error("Slider knob element: '" .. knob_id .. "' not found.")
- return
+ -- A sweep between 0 and 100 requires moving the pointer by
+ -- `scale * clickarea.height` pixes.
+ function add_simplecounter_knob(view, clickarea_id, port_name, scale)
+ table.insert(widgets, {
+ clickarea = get_layout_item(view, clickarea_id),
+ field = get_port_field(port_name),
+ is_knob = true,
+ scale = scale })
+ end
+
+ function get_layout_item(view, item_id)
+ local item = view.items[item_id]
+ if item == nil then
+ emu.print_error("Layout element: '" .. item_id .. "' not found.")
end
+ return item
+ end
+ function get_port_field(port_name)
local port = file.device:ioport(port_name)
if port == nil then
emu.print_error("Port: '" .. port_name .. "' not found.")
- return
+ return nil
end
-
- slider.field = nil
+ local field = nil
for k, val in pairs(port.fields) do
- slider.field = val
+ field = val
break
end
- if slider.field == nil then
+ if field == nil then
emu.print_error("Port: '" .. port_name .."' does not seem to be an IPT_ADJUSTER.")
- return
+ return nil
end
-
- table.insert(sliders, slider)
+ return field
end
local function pointer_updated(type, id, dev, x, y, btn, dn, up, cnt)
@@ -655,56 +674,64 @@ copyright-holders:m1macrophage
return
end
- -- If a button was just pressed, find the affected slider, if any.
+ -- If a button was just pressed, find the affected widget, if any.
if dn & 1 ~= 0 then
- for i = 1, #sliders do
- if sliders[i].knob.bounds:includes(x, y) then
+ for i = 1, #widgets do
+ local found, relative
+ if widgets[i].slider_knob and widgets[i].slider_knob.bounds:includes(x, y) then
+ found = true
+ relative = true
+ elseif widgets[i].clickarea.bounds:includes(x, y) then
+ found = true
+ relative = false
+ end
+ if found then
pointers[id] = {
- selected_slider = i,
- relative = true,
+ selected_widget = i,
+ relative = relative,
start_y = y,
- start_value = sliders[i].field.user_value }
- break
- elseif sliders[i].clickarea.bounds:includes(x, y) then
- pointers[id] = {
- selected_slider = i,
- relative = false }
+ start_value = widgets[i].field.user_value }
break
end
end
end
- -- If there is no slider selected by the current pointer, we are done.
+ -- If there is no widget selected by the current pointer, we are done.
if pointers[id] == nil then
return
end
- -- A slider is selected. Update state and, indirectly, slider knob position,
- -- based on the pointer's Y position. It is assumed the attached IO field is
- -- an IPT_ADJUSTER with a range of 0-100 (the default).
+ -- A widget is selected. Update its state based on the pointer's Y
+ -- position. It is assumed the attached IO field is an
+ -- IPT_ADJUSTER with a range of 0-100 (the default).
local pointer = pointers[id]
- local slider = sliders[pointer.selected_slider]
+ local widget = widgets[pointer.selected_widget]
- local knob_half_height = slider.knob.bounds.height / 2
- local min_y = slider.clickarea.bounds.y0 + knob_half_height
- local max_y = slider.clickarea.bounds.y1 - knob_half_height
-
- local new_value = 0
- if pointer.relative then
- -- User clicked on the knob. The new value will depend on how much the
- -- knob was dragged.
- new_value = pointer.start_value - 100 * (y - pointer.start_y) / (max_y - min_y)
+ local new_value
+ if widget.is_knob then
+ local step_y = 100.0 / (widget.scale * widget.clickarea.bounds.height)
+ new_value = pointer.start_value + (pointer.start_y - y) * step_y
else
- -- User clicked elsewhere on the slider. The new value will depend on
- -- the absolute position of the click.
- new_value = 100 - 100 * (y - min_y) / (max_y - min_y)
+ local knob_half_height = widget.slider_knob.bounds.height / 2
+ local min_y = widget.clickarea.bounds.y0 + knob_half_height
+ local max_y = widget.clickarea.bounds.y1 - knob_half_height
+
+ if pointer.relative then
+ -- User clicked on the knob. The new value will depend on how
+ -- much the knob was dragged.
+ new_value = pointer.start_value - 100 * (y - pointer.start_y) / (max_y - min_y)
+ else
+ -- User clicked elsewhere on the slider. The new value will depend on
+ -- the absolute position of the click.
+ new_value = 100 - 100 * (y - min_y) / (max_y - min_y)
+ end
end
new_value = math.floor(new_value + 0.5)
if new_value < 0 then new_value = 0 end
if new_value > 100 then new_value = 100 end
- slider.field.user_value = new_value
+ widget.field.user_value = new_value
end
local function pointer_left(type, id, dev, x, y, up, cnt)
@@ -726,7 +753,7 @@ copyright-holders:m1macrophage
view:set_forget_pointers_callback(forget_pointers)
end
-----------------------------------------------------------------------
- -- Slider library ends.
+ -- Slider and knob library ends.
-----------------------------------------------------------------------
]]>
diff --git a/src/mame/linn/linndrum.cpp b/src/mame/linn/linndrum.cpp
index 608b3cd4a88..50e066e1fe6 100644
--- a/src/mame/linn/linndrum.cpp
+++ b/src/mame/linn/linndrum.cpp
@@ -33,12 +33,9 @@ PCBoards:
Usage:
-The driver includes a (mostly) interactive layout, including buttons, LEDs and
-sliders. The only non-interactive widgets right now are the knobs (such as
-tuning and volume). Those will display their current value, but they can only
-be modified by the Slider Control menu.
+The driver includes an interactive layout.
-Since there is no audio, the driver logs triggers and other info. To see these
+Since there is no audio, the driver logs triggers and other info. To see those,
run the driver with `-log`:
./mame -window linndrum -log