aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2016-07-03 16:37:21 +0200
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2016-07-03 16:37:21 +0200
commitef023bd9f0eaa7c50664e89eabc3db539fc38211 (patch)
tree941257f322389a86266b27eeb21ce4434324a118
parentcac2883931aff61dd4d39061ff5aec4edafd0684 (diff)
downloadapplause2-ef023bd9f0eaa7c50664e89eabc3db539fc38211.tar.gz
added InstrumentStream (Stream:instrument)
* allows a stream of note velocities to trigger a note-on and note-off stream. * usually used on a MIDIVelocityStream * allows a single note to be triggered including attack, sustain and decay phases * by letting the note-on and note-off streams depend on the note/velocity stream, the note can use the NOTE ON velocity. * The InstrumentStream constructor will also accept functions on the note_stream, so it is possible to define the note-on/off streams depending on the velocity stream on a single line of source code. * A NOTE OFF velocity is currently not used, though that could be achieved by letting MIDIVelocityStream generate negative numbers for NOTE OFF velocities. * This will only work with a single note (ie. a fixed frequency); when wanting to play polyphony, users will have to mix many different InstrumentStreams, e.g. iota(69, 79):map(function(note) return MIDIVelocityStream(note, 1):instrument(function(v) return InstOn(note, v) end, InstOff(note)) end):fold(function(x,y) return x+y end):ravel()
-rw-r--r--applause.lua58
1 files changed, 58 insertions, 0 deletions
diff --git a/applause.lua b/applause.lua
index 404efef..171bd2d 100644
--- a/applause.lua
+++ b/applause.lua
@@ -1682,6 +1682,64 @@ end
function Stream:ftom() return self:map(ftom) end
+InstrumentStream = DeriveClass(MuxableStream)
+
+InstrumentStream.sig_last_stream = 1
+
+function InstrumentStream:muxableCtor(note_stream, on_stream, off_stream)
+ note_stream = tostream(note_stream):cache()
+
+ if type(on_stream) == "function" then
+ on_stream = on_stream(self.note_stream)
+ else
+ on_stream = tostream(on_stream)
+ end
+ if type(off_stream) == "function" then
+ off_stream = off_stream(self.note_stream)
+ else
+ -- The "off" stream is optional
+ off_stream = off_stream and tostream(off_stream)
+ end
+
+ self.streams = {note_stream, on_stream, off_stream}
+end
+
+function InstrumentStream:tick()
+ local note_tick = self.streams[1]:tick()
+ local on_stream = self.streams[2]
+ local off_stream = self.streams[3]
+ local on_tick
+ local function off_tick() return 0 end
+
+ return function()
+ local note = note_tick()
+ if not note then return end
+
+ if on_tick == nil then -- no note
+ if note == 0 then return off_tick() or 0 end
+
+ -- FIXME: This is not strictly real-time safe
+ on_tick = on_stream:tick()
+ return on_tick() or 0
+ else -- note on
+ if note ~= 0 then return on_tick() or 0 end
+
+ -- FIXME: This is not strictly real-time safe
+ on_tick = nil
+ off_tick = off_stream and off_stream:tick()
+ return off_tick() or 0
+ end
+ end
+end
+
+function InstrumentStream:len()
+ return self.streams[1]:len()
+end
+
+function Stream:instrument(on_stream, off_stream)
+ return InstrumentStream:new(self, on_stream, off_stream)
+end
+
-- primitives
function tostream(v)