guitar play should be changed as follows: The chord is played with one hand and a single key with the other hand triggers the guitar tone sequences redefine keys, such that a melody is played by just pressing the keys successively from left to right controller mapping cycle program banks when the same program change is received multiple times trigger an event if a certain sequence of notes is received this way we can switch the MIDI program after a certain bar is completed trigger an event if a certain event occured a given number of times switch arpeggiator pattern according to program change events add a bass tone to a chord some possible heuristics to achieve this: find the largest interval (cyclically) between the notes of the chord, select the upper note of this interval This note will be correct for minor and major chords, and will at least yield a result for every other chord. find an approximate GCD of the frequencies of the chord notes for any tone of the chord, create a list of some subharmonic tones associated with decreasing weights choose the subharmonic tone that gets the largest sum of weights Prelude> let ns = [1..]; dists = takeWhile (>0) $ Data.List.HT.mapAdjacent subtract $ map (round . (12 *) . logBase 2) ns; comb = concat $ zipWith (\n m -> recip n : replicate (m - 1) 0) ns dists Prelude> foldl1 (zipWith (+)) [comb, drop 3 comb, drop 7 comb] This weighting yields the choice of the lower tone out of a quart in a chord manage a database of known chords and associated bass tones http://www.gmth.de/zeitschrift/artikel/446.aspx General thoughts on the design ------------------------------ I think additionally to Causal we need another type like data State s a b = State (a s -> (b,s)) The state 's' could be a dictionary of pressed keys, input 'a' could a MIDI event and output 'b' could be a set of NoteOff or NoteOn events, that reflects changes in the dictionary. There would be two ways to lift it to a Causal stream editor: lift :: State s a b -> T a b trigger :: T a b -> State s a b -> T a (s,b) In @trigger tempo pattern@, the @tempo@ processor might convert incoming tempo controller values into a beat of type @b@. The @pattern@ also reacts to the inputs, and may produce thing of type @b@. Additionally, each output is extended by the current state, where incoming events first alter the current state and then emit the updated state. 'State' could also be named Segmented (or PiecewiseConstant). We can imagine it as an arrow that maintains a piecewise constant signal. 'trigger' could also be called 'sample'. Conversion from (T a b) to (State b a ()) could be called 'scan'. It interprets the output events as updates of a state. Maybe some inspiration of Functional Reactive Programming helps, or we may even use one of the FRP libraries. How about wrapping Events in an Event type analogously to Maybe: data Event a = NoEvent | Event a in order to distinguish between Events and States. Then we need a function in each processor that returns the current value of all states and NoEvent for all events. This can be used in the implementation of 'first'. I assume it is done this way in some FRP implementations, but do not ask me, which ones. Maybe it is better to separate propagation of events from event processing. A note processor could have type T Note Note and then there could be an arrow combinator, that passes non-note events through: liftNote :: T Note Note -> T EventData EventData The note processor could also have type noteProc :: NoteEvent ev => T ev ev class NoteEvent ev where liftNote :: T Note Note -> T ev ev instance NoteEvent Note instance NoteEvent EventData Done (mostly) ------------- stateless map: only send an output event if there was an input event without maintaining a state change channel, program, transposition split stream according to channel, program, pitch merge two streams convert key-press events to controller changes this way we can control the filter frequency of a resonant lowpass or we can control an external analogue synthesizer convert key-press intervals to a gate signal with according velocity this way we can generate an envelope for the resonance of a lowpass or we can control an external analogue synthesizer stateful map: only send an output event if there was an input event while maintaining a state add a bass tone to a chord hold a key or a chord until the next one is played play something on releasing the keys this way we could control Guitar strokes up and down cycle through a set of instruments for each note played This way we can play syllables of a word like To-ma-ten-sa-lat. patternMono: use a separate clock at which events can be scheduled patterns can be implemented by applying a stateful map to a beat stream play tones of current chord upwards, downwards, ping-pong or randomly generate patternMono consisting of the current tone and the tone one octave above it generate repeated keystrokes for the key that is constantly pressed play current chord repeatedly in randomly chosen inversions patterns like parity of ones in binary numbers (cf. my Flip song) record and replay events in a loop generate MIDI controller events according to a function of time generate MIDI controller events by a random patternMono, this may be used to control the cutoff frequency of a resonant filter delay events echo: play a note multiple times with a certain delay and decreasing velocity use the last n played notes for a patternMono with lazy access to a list, we can simulate a queue