aboutsummaryrefslogtreecommitdiffhomepage
path: root/applause.lua
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2017-01-26 06:54:31 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2017-01-26 07:29:42 +0100
commit11cf581231a2fc587f6120a95adaa0f2c472332f (patch)
treef92ca55c92c339fe6218a566df57dcfc3d16c0f7 /applause.lua
parent6a584fdae9fedad214538e81c8347dd75d64febc (diff)
downloadapplause2-11cf581231a2fc587f6120a95adaa0f2c472332f.tar.gz
revised MIDI support
* introduced MIDIStream which provides a raw stream of MIDI messages (mangled into a single integer). * MIDIVelocityStream has been replaced by MIDIStream:mvelocity() * MIDICCStream has been replaced by MIDIStream:CC() * MIDIStreams can be directly passed to DSSIStreams
Diffstat (limited to 'applause.lua')
-rw-r--r--applause.lua154
1 files changed, 59 insertions, 95 deletions
diff --git a/applause.lua b/applause.lua
index 91507fa..1b1701a 100644
--- a/applause.lua
+++ b/applause.lua
@@ -83,9 +83,9 @@ enum applause_audio_state {
enum applause_audio_state applause_push_sample(int output_port_id,
double sample_double);
-int applause_midi_velocity_getvalue(int note, int channel);
-int applause_midi_note_getvalue(int channel);
-int applause_midi_cc_getvalue(int control, int channel);
+typedef uint32_t applause_midi_sample;
+
+applause_midi_sample applause_pull_midi_sample(void);
]]
-- Sample rate
@@ -1642,113 +1642,58 @@ end
--
-- MIDI Support
+-- NOTE: The MIDIStream is defined at the very end, since
+-- we need to use primitives not yet defined
--
--- Velocity of NOTE ON for a specific note on a channel
-MIDIVelocityStream = DeriveClass(Stream)
+-- Last value of a specific control channel
+function Stream:CC(control, channel)
+ channel = channel or 0
-function MIDIVelocityStream:ctor(note, channel)
- -- `note` may be a note name like "A4"
- self.note = type(note) == "string" and ntom(note) or note
- assert(0 <= self.note and self.note <= 127,
- "MIDI note out of range (0 <= x <= 127)")
+ 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 value = 0
+ local band, rshift = bit.band, bit.rshift
- self.channel = channel or 1
- assert(1 <= self.channel and self.channel <= 16,
- "MIDI channel out of range (1 <= x <= 16)")
+ return self:map(function(sample)
+ value = band(sample, 0xFFFF) == filter and
+ rshift(sample, 16) or value
+ return value
+ end)
end
--- This is for calling from external code (e.g. from
--- streams supporting MIDI natively)
-function MIDIVelocityStream.getValue(note, channel)
+-- Velocity of NOTE ON for a specific note on a channel
+function Stream:mvelocity(note, channel)
-- `note` may be a note name like "A4"
note = type(note) == "string" and ntom(note) or note
- -- NOTE: The native function assert() for invalid
- -- notes or channels to avoid segfaults
+ channel = channel or 0
+
assert(0 <= note and note <= 127,
"MIDI note out of range (0 <= x <= 127)")
- assert(1 <= channel and channel <= 16,
- "MIDI channel out of range (1 <= x <= 16)")
-
- return C.applause_midi_velocity_getvalue(note, channel)
-end
-
-function MIDIVelocityStream:gtick()
- local note = self.note
- local channel = self.channel
+ assert(0 <= channel and channel <= 15,
+ "MIDI channel out of range (0 <= x <= 15)")
- return function()
- return C.applause_midi_velocity_getvalue(note, channel)
- end
-end
-
--- Stream of integer words representing the last MIDI note
--- triggered on a channel with its corresponding velocity
--- (of the NOTE ON message).
--- The MIDI note is the lower byte and the velocity the
--- upper byte of the word.
-MIDINoteStream = DeriveClass(Stream)
-
-function MIDINoteStream:ctor(channel)
- self.channel = channel or 1
- assert(1 <= self.channel and self.channel <= 16,
- "MIDI channel out of range (1 <= x <= 16)")
-end
-
--- This is for calling from external code (e.g. from
--- streams supporting MIDI natively)
-function MIDINoteStream.getValue(channel)
- -- NOTE: The native function assert() for invalid
- -- notes or channels to avoid segfaults
- assert(1 <= channel and channel <= 16,
- "MIDI channel out of range (1 <= x <= 16)")
-
- return C.applause_midi_note_getvalue(channel)
-end
-
-function MIDINoteStream:gtick()
- local channel = self.channel
-
- return function()
- return C.applause_midi_note_getvalue(channel)
- end
-end
-
-MIDICCStream = DeriveClass(Stream)
-
-function MIDICCStream:ctor(control, channel)
- self.control = control
- self.channel = channel or 1
-
- assert(0 <= self.control and self.control <= 127,
- "MIDI control number out of range (0 <= x <= 127)")
- assert(1 <= self.channel and self.channel <= 16,
- "MIDI channel out of range (1 <= x <= 16)")
-end
-
--- This is for calling from external code (e.g. from
--- streams supporting MIDI natively)
-function MIDICCStream.getValue(control, channel)
- -- NOTE: The native function assert() for invalid
- -- notes or channels to avoid segfaults
- assert(0 <= control and control <= 127,
- "MIDI control number out of range (0 <= x <= 127)")
- assert(1 <= channel and channel <= 16,
- "MIDI channel out of range (1 <= x <= 16)")
-
- return C.applause_midi_cc_getvalue(control, channel)
-end
-
-function MIDICCStream:gtick()
- local control = self.control
- local channel = self.channel
+ local on_filter = bit.bor(0x90, channel, bit.lshift(note, 8))
+ local off_filter = bit.bor(0x80, channel, bit.lshift(note, 8))
+ local value = 0
+ local band, rshift = bit.band, bit.rshift
- return function()
- return C.applause_midi_cc_getvalue(control, channel)
- end
+ return self:map(function(sample)
+ value = band(sample, 0xFFFF) == on_filter and
+ rshift(sample, 16) or
+ band(sample, 0xFFFF) == off_filter and
+ 0 or value
+ return value
+ end)
end
+--
-- MIDI primitives
+--
do
local band = bit.band
@@ -2334,3 +2279,22 @@ Client.__gc = Client.kill
-- so they react to reload()
--
dofile "dssi.lua"
+
+--
+-- See above, MIDIStream depends on tostream() and other
+-- primitives.
+--
+do
+ local class = DeriveClass(Stream)
+
+ function class:gtick()
+ return C.applause_pull_midi_sample
+ end
+
+ -- FIXME: Since a sample must only be pulled once
+ -- per tick, so MIDIStream can be reused, it must
+ -- always be cached.
+ -- Perhaps it's easier to peek into the ring buffer
+ -- advance the read pointer per tick.
+ MIDIStream = class:cache()
+end