Karya, built on 2020-11-26T21:03:17 (patch 23b5be2d53a9e8e7d6136cda5aae2849abe5cded)
Safe HaskellNone



Functions for instrument cmds. This is called CUtil because there is also Derive.Instrument.DUtil and they are usually imported together.

I need a better name than "Util" for everything.


eval call

data Thru Source #

Select the flavor of thru to use when inserting an expression. This selects either expr_midi_thru or expr_im_thru.

insert_expr Source #


:: Cmd.M m 
=> Thru

Evaluate the expression and emit MIDI thru.

-> Cmd.NoteEntryMap DeriveT.Expr 
-> Cmd.Handler m 

Create a custom kbd entry cmd that inserts tracklang expressions at the insertion point. Since this shadows the default note entry cmd, it has to handle thru on its own.

expr_midi_thru :: Cmd.M m => UiMsg.KbdState -> DeriveT.Expr -> m () Source #

Emit MIDI thru for an arbitrary expresison.

This is more accurate and principled than what the usual kbd entry cmds do, since it reuses the deriver and performer directly, while they recreate the performer in an ad-hoc way, e.g. in Cmd.MidiThru. However, this allows them to play chords and is thus more suitable for pitched instruments. Actually, what MidiThru recreates is the channel allocation part of the performer, ultimately becasue the performer's allocator doesn't work in real time. Still, perhaps it would be possible to integrate them better than I have.

expr_to_midi :: Cmd.M m => BlockId -> TrackId -> TrackTime -> DeriveT.Expr -> m [Midi.WriteMessage] Source #

Call a note call and return the MIDI msgs it produces.


keyswitches :: Cmd.M m => [(Char, Expr.Symbol, Midi.Key)] -> Cmd.Handler m Source #

Create a Cmd to set keyswitches.

This simply sets the note text for subsequent notes, and also configures the instrument to play in the given keyswitch.

TODO this just emits keyswitches for every addr and emits them redundantly. This is simpler but it would be more correct to use WriteDeviceState to emit them only when needed. However, it's more complicated because then I need a current attrs (Map Instrument Attrs) along with current note text, so MidiThru can use the attrs to find the keyswitch.

TODO if I can pull the current or previous note out of the derive then I could use that to play an example note. Wait until I have a "play current line" framework up for that.


simple_drum :: Thru -> Maybe ScoreT.Control -> [(Drums.Stroke, Midi.Key)] -> MidiInst.Patch -> MidiInst.Patch Source #

Create an unpitched drum instrument. This is an instrument with an enumeration of symbols and no pitch or duration. Each key maps to its own symbol.


drum_code Source #


:: Thru 
-> Maybe ScoreT.Control

If given, this control indicates semitone offsets above or below the natural pitch. Actual pitched drums which are tuned to a definite note should use pitched_drum_patch and a pitch track.

-> [Drums.Stroke] 
-> MidiInst.Code 

Construct code from drum strokes. This is both the deriver calls to interpret the stroke names, and the cmds to enter them.


type KeyswitchRange = ([Patch.Keyswitch], Midi.Key, Midi.Key, Midi.Key) Source #

(keyswitch, low, high, root_pitch). The root pitch is the pitch at the bottom of the key range, and winds up in Patch.PitchedKeymap.

make_keymap Source #


:: Maybe Midi.Key

Keyswitches start here. If not given, this patch doesn't use keyswitches.

-> Midi.Key

notes start here

-> Midi.Key

each sound is mapped over this range

-> Midi.Key

the pitch of the bottom note of each range

-> [[Attrs.Attributes]] 
-> Map Attrs.Attributes KeyswitchRange 

Make a KeyswitchRange for each grouped Attributes set. Attributes in the same group get the same range and are differentiated by keyswitch.

make_keymap2 :: Maybe Midi.Key -> Midi.Key -> Midi.Key -> Midi.Key -> Midi.Key -> [[Attrs.Attributes]] -> Map Attrs.Attributes KeyswitchRange Source #

This is like make_keymap, except with the arguments rearranged to more closely match the sample utils I use.

make_cc_keymap Source #


:: Midi.Key

notes start here

-> Midi.Key

each sound is mapped over this range

-> Midi.Key

the pitch of the bottom note of each range

-> [[Attrs.Attributes]] 
-> Map Attrs.Attributes KeyswitchRange 

This is like make_keymap, except that attributes are differentiated by a Patch.ControlSwitch. CCs start at 102, and only groups of size >1 get a CC. Since each group is controlled by its own CC number, you can then select each variation independently. This means any set of variations can be played simultaneously, which is not true for keyswitches.

pitched_drum_patch :: PitchedStrokes -> MidiInst.Patch -> MidiInst.Patch Source #

Annotate a Patch with an Patch.AttributeMap from the given PitchedStrokes.

drum_pitched_strokes Source #


:: [Drums.Stroke] 
-> Map Attrs.Attributes KeyswitchRange 
-> (PitchedStrokes, ([Drums.Stroke], [Attrs.Attributes]))

Also return the strokes with no mapping (so they can't be played), and keymap ranges with no corresponding strokes (so there is no call to play them).

Make PitchedStrokes by pairing each Drums.Stroke with its KeyswitchRange.

drum_calls Source #


:: Maybe ([Attrs.Attributes], Pitch.NoteNumber)

If Just, only strokes which are a superset of one of these move with the pitch, otherwise the stay at the given NoteNumber. If Nothing, all strokes move with the pitch.

-> Maybe ScoreT.Control 
-> [Drums.Stroke] 
-> [(Expr.Symbol, Generator Note)] 

Create 0 duration calls from the given drum strokes.

This should probably go in DUtil, but that would make it depend on Cmd.Instrument.Drums.


resolve_strokes Source #


:: Signal.Y 
-> Map Attrs.Attributes KeyswitchRange 
-> [(Char, Expr.Symbol, Attrs.Attributes, Drums.Group)]

(key_binding, emits_text, call_attributes, stop_group)

-> (PitchedStrokes, [Text])

also return errors

Given a map describing how Attributes are mapped to the MIDI key range, take a key binding to a PitchedStrokes. The reason these are separate is that the map describes how a particular patch maps attributes, while the key binding describes the capabilities of the instrument itself.

If a mapping has Attrs.soft, it's looked up without the soft, but gets the given dynamic.