Safe Haskell | Safe-Inferred |
---|
Description of a midi-specific instrument, as well as the runtime midi device and channel mapping.
Synopsis
- data Config = Config {
- config_allocation :: ![(Addr, Maybe Voices)]
- config_initialization :: !(Maybe Initialization)
- config_settings :: !Settings
- config_addrs :: Config -> [Addr]
- merge_defaults :: Patch -> Config -> Config
- allocation :: Config :-> [(Addr, Maybe Voices)]
- control_defaults :: Settings :-> Maybe ScoreT.ControlValMap
- initialization :: Config :-> Maybe Initialization
- settings :: Config :-> Settings
- config :: [(Addr, Maybe Voices)] -> Config
- data Initialization
- = Tuning
- | NrpnTuning
- type Addr = (Midi.WriteDevice, Midi.Channel)
- type Voices = Int
- has_flag :: Config -> Flag -> Bool
- type PbRange = (Int, Int)
- data Settings = Settings {
- config_flags :: !(Maybe (Set Flag))
- config_scale :: !(Maybe Scale)
- config_decay :: !(Maybe RealTime)
- config_pitch_bend_range :: !(Maybe PbRange)
- config_control_defaults :: !(Maybe ScoreT.ControlValMap)
- pitch_bend_range :: Settings :-> Maybe PbRange
- decay :: Settings :-> Maybe RealTime
- scale :: Settings :-> Maybe Scale
- flags :: Settings :-> Maybe (Set Flag)
- data Patch = Patch {}
- name :: Patch :-> Text
- control_map :: Patch :-> Control.ControlMap
- initialize :: Patch :-> InitializePatch
- attribute_map :: Patch :-> AttributeMap
- mode_map :: Patch :-> ModeMap
- defaults :: Patch :-> Settings
- patch :: PbRange -> InstT.Name -> Patch
- default_name :: InstT.Name
- data Scale = Scale {
- scale_name :: !Text
- scale_key_to_nn :: !(Unboxed.Vector Double)
- make_scale :: Text -> [(Midi.Key, Pitch.NoteNumber)] -> Scale
- convert_scale :: Scale -> Pitch.NoteNumber -> Maybe Pitch.NoteNumber
- nn_at :: Scale -> Midi.Key -> Maybe Pitch.NoteNumber
- scale_nns :: Maybe AttributeMap -> Scale -> [(Midi.Key, Pitch.NoteNumber)]
- scale_offsets :: Maybe AttributeMap -> Scale -> [Maybe Pitch.NoteNumber]
- scale_tuning :: Maybe AttributeMap -> Scale -> [Maybe (Midi.Key, Pitch.NoteNumber)]
- data Flag
- add_flag :: Flag -> Set Flag -> Set Flag
- remove_flag :: Flag -> Set Flag -> Set Flag
- data InitializePatch
- initialize_midi :: [Midi.ChannelMessage] -> InitializePatch
- type AttributeMap = Common.AttributeMap ([Keyswitch], Maybe Keymap)
- data Keymap
- data Keyswitch
- keyswitches :: [(Attrs.Attributes, [Keyswitch])] -> AttributeMap
- single_keyswitches :: [(Attrs.Attributes, Midi.Key)] -> AttributeMap
- cc_keyswitches :: [(Midi.Control, [(Attrs.Attributes, Midi.ControlValue)])] -> AttributeMap
- cc_keyswitches_permute :: [(Midi.Control, [(Attrs.Attributes, Midi.ControlValue)])] -> AttributeMap
- keymap :: [(Attrs.Attributes, Keymap)] -> AttributeMap
- unpitched_keymap :: [(Attrs.Attributes, Midi.Key)] -> AttributeMap
- keyswitch_on :: Midi.Key -> Keyswitch -> Midi.ChannelMessage
- keyswitch_off :: Keyswitch -> Maybe Midi.ChannelMessage
- newtype ModeMap = ModeMap (Map EnvKey.Key ((ScoreT.Control, Signal.Y), Map Expr.MiniVal (ScoreT.Control, Signal.Y)))
- make_mode_map :: [(EnvKey.Key, [(Expr.MiniVal, (ScoreT.Control, Midi.ControlValue))])] -> ModeMap
- cc_mode_map :: [(EnvKey.Key, Midi.Control, [(Expr.MiniVal, Midi.ControlValue)])] -> (ModeMap, [(Midi.Control, ScoreT.Control)])
Config
Configuration for one MIDI instrument allocation.
Config | |
|
Instances
config_addrs :: Config -> [Addr] Source #
data Initialization Source #
Document what kinds of initialization this instrument needs. Each instrument is initialized once when the score is loaded.
Tuning | Configure tuning with |
NrpnTuning | Configure tuning with |
Instances
type Addr = (Midi.WriteDevice, Midi.Channel) Source #
MIDI instruments are addressed by a (device, channel) pair, allocated in
Config
.
type PbRange = (Int, Int) Source #
Pitchbend range in tempered semitones below and above unity. The first integer should probably be negative.
Settings
This has instrument configuration which has built-in defaults but can also
be modified per score. When the instrument is looked up
(Cmd.resolve_instrument), patch_defaults
is merged with config_settings
via merge_defaults
.
Settings | |
|
Instances
Patch
A Patch has information about one specific instrument. The performance
Instrument
and MIDI config are derived from it, via its
Synth
.
Patch | |
|
patch :: PbRange -> InstT.Name -> Patch Source #
Create a Patch with empty vals, to set them as needed.
default_name :: InstT.Name Source #
This is a convention for the default instrument of a synth. This is useful for softsynths whose patches all generally have the same config.
Scale
Describe the tuning of a MIDI patch.
This is used both to describe a patch tuned to something other than 12TET, and to retune a 12TET patch.
The Scale is used during performance to warp played pitches to the patch's
tuning. The idea is that they will warp to integral Midi.Key
s that won't
need any tuning and can thus all go on a single MIDI channel.
Scale | |
|
make_scale :: Text -> [(Midi.Key, Pitch.NoteNumber)] -> Scale Source #
Fill in non-adjacent MIDI keys by interpolating the neighboring NoteNumbers. This is because a 0 between two notes will prevent pitch slides. Another problem is that the MIDI performer has no notion of instruments that don't support certain key numbers. That could be added but it's simpler to just not have patches like that.
:: Scale | |
-> Pitch.NoteNumber | if you want this pitch |
-> Maybe Pitch.NoteNumber | play this key |
scale_nns :: Maybe AttributeMap -> Scale -> [(Midi.Key, Pitch.NoteNumber)] Source #
Absolute NoteNumber for each Midi.Key
to tune 12TET to this scale.
scale_offsets :: Maybe AttributeMap -> Scale -> [Maybe Pitch.NoteNumber] Source #
Relative NoteNumber offset for each Midi.Key
to tune 12TET to this scale.
scale_tuning :: Maybe AttributeMap -> Scale -> [Maybe (Midi.Key, Pitch.NoteNumber)] Source #
Map the mapped keys through the scale.
Flag
Various instrument flags. Add new ones at the bottom to avoid messing up serialization.
Pressure | Patch uses continuous pressure control, assigned to CC 2 (breath),
instead of trigger velocity. This is used to support the |
HoldKeyswitch | If set, a keysitch has to be held while its note is playing. Otherwise, it will just be tapped before the note starts. |
ResumePlay | When playing from mid-score, scan backwards for the first overlapping notes with this instrument set and resume that note. This way you can play long notes like tambura from the middle. |
UseFinalNoteOff | If there are overlapping notes with the same MIDI key, delay all NoteOffs until the final one. This is for synthesizers which turn the note off on the first one, such as Kontakt. TODO: this is disabled, remove it entirely if I really don't seem to
need it. |
Old_Triggered | Obsolete, don't use. |
InitializePatch
data InitializePatch Source #
Describe how an instrument should be initialized before it can be played.
InitializeMidi ![Midi.Message] | Send these msgs to initialize the patch. It should be a patch change or a sysex. Channel is ignored. |
InitializeMessage !Text | Display this msg to the user and hope they do what it says. |
NoInitialization |
Instances
AttributeMap
type AttributeMap = Common.AttributeMap ([Keyswitch], Maybe Keymap) Source #
This is a specialization of Common.AttributeMap
for MIDI.
You should use a constructor like keyswitches
, which will call
Common.sort_attributes
to make sure there are no overlaps.
A Keymap corresponds to a timbre selected by MIDI key range, rather than keyswitches. Unlike a keyswitch, this doesn't change the state of the MIDI channel, so multiple keymapped notes can coexist, and keymap replaces the pitch of the note.
UnpitchedKeymap !Midi.Key | This ignores the event's pitch and instead emits the given MIDI key. This is appropriate for drumkit style patches, with a separate unpitched timbre on each key. |
PitchedKeymap !Midi.Key !Midi.Key !Midi.Key | The timbre is mapped over the inclusive MIDI key range from low to high, where the pitch of the low end of the range is given by the NoteNumber. So this transposes the event's pitch and clips it to the given range. low, high, nn |
A Keyswitch changes the timbre of a patch, but does so in a channel-global way. So overlapping notes with different keyswitches will be split into different channels, if possible. See NOTE [midi-state].
Keyswitch !Midi.Key | |
ControlSwitch !Midi.Control !Midi.ControlValue | This keyswitch is triggered by a control change. |
Aftertouch !Midi.ControlValue | This is like |
keyswitches :: [(Attrs.Attributes, [Keyswitch])] -> AttributeMap Source #
An AttributeMap with just Keyswitch
es.
single_keyswitches :: [(Attrs.Attributes, Midi.Key)] -> AttributeMap Source #
An AttributeMap with a single Midi.Key keyswitch per Attribute.
cc_keyswitches :: [(Midi.Control, [(Attrs.Attributes, Midi.ControlValue)])] -> AttributeMap Source #
An AttributeMap that uses ControlSwitch
es. Each CC can have attrs at
several values.
cc_keyswitches_permute :: [(Midi.Control, [(Attrs.Attributes, Midi.ControlValue)])] -> AttributeMap Source #
Like cc_keyswitches
, except that all the controls are orthogonal, so
every cross-control combination of attributes is valid.
keymap :: [(Attrs.Attributes, Keymap)] -> AttributeMap Source #
An AttributeMap with just Keymap
s.
unpitched_keymap :: [(Attrs.Attributes, Midi.Key)] -> AttributeMap Source #
An AttributeMap with just unpitched keymaps.
keyswitch_on :: Midi.Key -> Keyswitch -> Midi.ChannelMessage Source #
The MIDI message to activate the given Keyswitch.
ModeMap
The ModeMap is like the AttributeMap
, but it's triggered by the
event Environ, rather than Attributes. This is suitable for modes which
have mutually exclusive settings. See NOTE [midi-state].
make_mode_map :: [(EnvKey.Key, [(Expr.MiniVal, (ScoreT.Control, Midi.ControlValue))])] -> ModeMap Source #
cc_mode_map :: [(EnvKey.Key, Midi.Control, [(Expr.MiniVal, Midi.ControlValue)])] -> (ModeMap, [(Midi.Control, ScoreT.Control)]) Source #
Construct a ModeMap that uses MIDI CC.