diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2016-07-03 16:37:21 +0200 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2016-07-03 16:37:21 +0200 |
commit | ef023bd9f0eaa7c50664e89eabc3db539fc38211 (patch) | |
tree | 941257f322389a86266b27eeb21ce4434324a118 | |
parent | cac2883931aff61dd4d39061ff5aec4edafd0684 (diff) | |
download | applause2-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.lua | 58 |
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) |