Karya, built on 2018-05-31T02:46:59 (patch 0a1a35479c514820d77330ae8a978975ba22a47a)

Safe HaskellNone




Convert incoming MIDI (and other inputs) to the internal note representation. This has two purposes: note entry, and midi thru.

This module is, in a way, dual to Perform.Midi.Perform. It takes MIDI input to the internal Input representation and back again, while Perform takes the internal representation, in the form of Event, to MIDI output.

The overlapping part is that this module maps Controls to and from MIDI while Play uses Control. They use the same control names, though, so I can reuse code from Control.

One significant difference between Input and MIDI is that MIDI supports two levels of control addressing: note and channel, while Input can only represent note addressing through NoteId. MIDI controls almost all apply at the channel level, but of course these controls all apply at the note level. The result is that a MIDI control that on a keyboard affects the whole channel will only affect the last played note here. When the input is converted back to MIDI it may wind up sharing a channel anyway, at which point the control will go back to being channel global, but if the instrument has multiple channels, I try to distribute between them to keep note_ids on separate channels. This way, multiple channel emitting controls can be mapped to multiple channel using instruments.

This is basically a simplified version of the channel allocation algorithm in Perform.Midi.Perform. It's hard to reuse that algorithm directly because this one has to operate in realtime and can't see which controls the note is going to use.



keyboard_velocity :: Signal.Y Source #

Since the ASCII keyboard isn't pressure sensitive, this is the default velocity. Hopefully it's strong but not so strong as to be hard on the ears.

type InputNn = GenericInput Pitch.NoteNumber Source #

An input with a plain NoteNumber pitch instead of a Pitch.Input.

data GenericInput pitch Source #


NoteOn NoteId pitch Signal.Y

The Input and val (velocity) could be sent separately, but that would make converting this back into midi for thru harder.

NoteOff NoteId Signal.Y 
Control NoteId Score.Control Signal.Y

Controls coming from MIDI are mapped to control names, since this is a superset of MIDI CC numbers, and may include non-MIDI as well. But for MidiThru to map back to a CC number, I need 1:1 mapping between Score.Controls and CC numbers. This is what cc_to_control and control_to_cc provide.

PitchChange NoteId pitch

Pitch could also be a Control, but this way the pitch is typed.

Eq pitch => Eq (GenericInput pitch) # 
Instance details

Defined in Cmd.InputNote


(==) :: GenericInput pitch -> GenericInput pitch -> Bool #

(/=) :: GenericInput pitch -> GenericInput pitch -> Bool #

Show pitch => Show (GenericInput pitch) # 
Instance details

Defined in Cmd.InputNote


showsPrec :: Int -> GenericInput pitch -> ShowS #

show :: GenericInput pitch -> String #

showList :: [GenericInput pitch] -> ShowS #

(Show pitch, Pretty pitch) => Pretty (GenericInput pitch) # 
Instance details

Defined in Cmd.InputNote

multiply_note_id :: Int -> GenericInput x -> GenericInput x Source #

Modify the NodeId so that it won't collide with other NodeIds.

NoteIds are supposed to be unique for each Input. However, in practice they wind up being the MIDI NoteOn Midi.Key, for reasons described in NoteId. So if you want to emit MIDI thru for two notes with the same pitch (e.g. dispatch a single pitch to two instruments), you need to give them different NoteIds. This function multiplies them such that they won't collide.

TODO This is a grody hack. A better solution might be to make NoteId into a (Channel, Int) pair.

newtype NoteId Source #

In theory, NoteId is an arbitrary ID, but in practice it's the same as the initial note on Midi.Key. The reason is that pitch bend needs to know the original key so it knows what the pitch bend is relative to. I could store the original key separately, but it's convenient to put them both into NoteId, and I can't think of any instances where I'd want them to be different.

In addition, when a MIDI NoteOff comes in I have to know what NoteId it applies to. Since MIDI's NoteId is the key number, I have no choice but to use that.


NoteId Int 
Eq NoteId # 
Instance details

Defined in Cmd.InputNote


(==) :: NoteId -> NoteId -> Bool #

(/=) :: NoteId -> NoteId -> Bool #

Ord NoteId # 
Instance details

Defined in Cmd.InputNote

Show NoteId # 
Instance details

Defined in Cmd.InputNote

from midi

newtype ReadDeviceState Source #

Keep track of the state of each Midi.ReadDevice.

data ControlState Source #

The state of one Midi.ReadDevice.

Eq ControlState # 
Instance details

Defined in Cmd.InputNote

Show ControlState # 
Instance details

Defined in Cmd.InputNote

from ascii

from_ascii :: Bool -> Pitch.Pitch -> Input Source #

Create an Input from an ascii keyboard Pitch.

to midi