Karya, built on Mon Jul 24 11:39:07 PDT 2017 (patch 33511aca01257b76b88de7c7a2763b7a965c084e)

Safe HaskellNone

Cmd.Instrument.CUtil

Contents

Description

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.

Synopsis

Documentation

type Call = Text Source #

Text of the event to create.

eval call

insert_expr :: Cmd.M m => Map Char BaseTypes.Expr -> Msg.Msg -> m Cmd.Status Source #

Create a custom kbd entry cmd that inserts tracklang expressions at the insertion point. It also attempts to evaluate the expression to produce MIDI thru.

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 -> BaseTypes.Expr -> m [Midi.WriteMessage] Source #

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

keyswitch

keyswitches :: Cmd.M m => [(Char, Expr.Symbol, Midi.Key)] -> Msg.Msg -> m Cmd.Status 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.

drums

simple_drum :: Maybe Control -> [(Drums.Note, 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.

code

drum_code Source #

Arguments

:: Maybe 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.Note] 
-> MidiInst.Code 

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

patch

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 #

Arguments

:: 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 #

Arguments

:: 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 :: PitchedNotes -> MidiInst.Patch -> MidiInst.Patch Source #

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

drum_pitched_notes Source #

Arguments

:: [Drums.Note] 
-> Map Attrs.Attributes KeyswitchRange 
-> (PitchedNotes, ([Drums.Note], [Attrs.Attributes]))

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

Make PitchedNotes by pairing each Drums.Note with its KeyswitchRange.

drum_calls Source #

Arguments

:: 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 Control 
-> [Drums.Note] 
-> [(Expr.Symbol, Generator Note)] 

Create 0 duration calls from the given drum notes.

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

util

resolve_strokes Source #

Arguments

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

(key_binding, emits_text, call_attributes, stop_group)

-> (PitchedNotes, [Text])

also return errors

Given a map describing how Attributes are mapped to the MIDI key range, take a key binding to a PitchedNotes. 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.