aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2023-09-29 01:31:28 +0300
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2023-09-29 01:31:28 +0300
commit1a6ad201df8ef071cc394d4c915d7d54e187ba51 (patch)
tree3cd62b1a8d505c5f11541375421478a65203fa4b
parent132dd6354c0d264b4fa2000aac02c9bffc88278a (diff)
downloadapplause2-1a6ad201df8ef071cc394d4c915d7d54e187ba51.tar.gz
added Stream:CCrel() for interpreting relative CC controllers (for instance encoders)
* currently, this does only support two's complement encoding of signed 7-bit integers
-rw-r--r--midi.lua55
1 files changed, 51 insertions, 4 deletions
diff --git a/midi.lua b/midi.lua
index 252bbfa..4b02d01 100644
--- a/midi.lua
+++ b/midi.lua
@@ -55,10 +55,13 @@ end
-- @treturn Stream Stream of numbers between [-1,+1].
-- @see MIDIStream
-- @usage Stream.SinOsc(440):gain(MIDIStream:CC(0):scale()):play()
--- @fixme Most MIDI software appears to use origin 1 channels and control ids.
+-- @todo MIDI defines standart controller names.
+-- Perhaps we want to support these by passing strings.
+-- @fixme Most MIDI software appears to use origin 1 channels.
-- @fixme Is there actually any reason to keep Stream:CC instead of Stream:CC14?
-- Stream:CC14 will be slightly slower in case of MIDI events, but those are rare.
--- Or are there any controllers that will use controller ids >= 0x20 for other purposes?
+-- Or are there any controllers that will use controller ids where bit 0x20 is set for other purposes?
+-- Unfortunately, we cannot be sure of it.
function Stream:CC(control, channel)
channel = channel or 0
@@ -80,10 +83,52 @@ function Stream:CC(control, channel)
end)
end
+--- Filter out last value of a specific relative MIDI control channel.
+-- This remembers the last value and is therefore a stream, representing the controller state.
+-- It will currently only work if the CC values are two's complement signed values.
+-- It is usually applied on @{MIDIStream}.
+-- @within Class Stream
+-- @int control Controller number between [0,127].
+-- @int[opt=0] channel MIDI channel between [0,15].
+-- @number[opt=1000] resolution
+-- The device resolution, ie. the number of steps between [-1,+1].
+-- The larger this value, the longer it takes to move from the minimum to the maximum position.
+-- @treturn Stream Stream of numbers between [-1,+1].
+-- @see MIDIStream
+-- @see Stream:evrel
+-- @usage Stream.SinOsc(440):gain(MIDIStream:CCrel(0):scale()):play()
+-- @todo MIDI defines standart controller names.
+-- Perhaps we want to support these by passing strings.
+-- @fixme Most MIDI software appears to use origin 1 channels.
+function Stream:CCrel(control, channel, resolution)
+ channel = channel or 0
+ resolution = (resolution or 1000)/2
+
+ assert(0 <= control and control <= 127,
+ "MIDI control number out of range (0 <= x <= 127)")
+ assert(0 <= channel and channel <= 15,
+ "MIDI channel out of range (0 <= x <= 15)")
+
+ local filter = bit.bor(0xB0, channel, bit.lshift(control, 8))
+ local band, rshift = bit.band, bit.rshift
+ local min, max = math.min, math.max
+ local int8_ct = ffi.typeof('int8_t')
+
+ return self:scan(function(last, sample)
+ last = last or -1
+ local sample_masked = band(sample, 0xFFFF)
+ if sample_masked == filter then
+ local rel = tonumber(int8_ct(band(rshift(sample, 16-1), 0xFE)) / 2)
+ return min(max(last+rel/resolution, -1), 1)
+ end
+ return last
+ end)
+end
+
--- Filter out last value of a specific **14-bit** MIDI control channel, scaled to [-1,+1].
-- This remembers the last value and is therefore a stream, representing the controller state.
-- It is usually applied on @{MIDIStream}.
--- In contrast to @{Stream.CC}, this supports 14-bit controllers where the
+-- In contrast to @{Stream:CC}, this supports 14-bit controllers where the
-- least-significant byte is sent on controller with offset 0x20.
-- @within Class Stream
-- @int control Controller number between [0,127].
@@ -92,7 +137,9 @@ end
-- @see MIDIStream
-- @see Stream:CC
-- @usage Stream.SinOsc(440):gain(MIDIStream:CC14(0):scale()):play()
--- @fixme Most MIDI software appears to use origin 1 channels and control ids.
+-- @todo MIDI defines standart controller names.
+-- Perhaps we want to support these by passing strings.
+-- @fixme Most MIDI software appears to use origin 1 channels.
function Stream:CC14(control, channel)
channel = channel or 0