Documentation
¶
Overview ¶
Package midi allows you to listen to incoming MIDI messages.
Warning! This is not a feature-complete MIDI implementation. MIDI system messages are ignored with the exception of CLOCK, START, and STOP messages.
Example ¶
If you already have a main event loop, do this:
// Launch the MIDI reader thread and get the channel it uses to deliver incoming messages midiMessageChan := midi.GetMidiMessageStream("/dev/midi1") // Create a persistent object which knows the current MIDI state // This includes the current volumes of all notes (will be 0 for non-playing notes) // and the current value of all controllers. midiState := midi.MidiState{} // Your main event loop for { // Nonblockingly get all the MIDI messages that have come in since we last checked // and use them to update the MIDI state midiState.UpdateStateFromChannel(midiMessageChan) // Do things with the MIDI data if midiState.KeyVolumes[60] > 0 { fmt.Println("Key 60 is held down right now") } }
For more details on MIDI:
http://www.midi.org/techspecs/midimessages.php
https://en.wikipedia.org/wiki/MIDI_timecode#Quarter-frame_messages
Index ¶
Constants ¶
const ( LPD8_PAD1 byte = 36 + iota LPD8_PAD2 byte = 36 + iota LPD8_PAD3 byte = 36 + iota LPD8_PAD4 byte = 36 + iota LPD8_PAD5 byte = 36 + iota LPD8_PAD6 byte = 36 + iota LPD8_PAD7 byte = 36 + iota LPD8_PAD8 byte = 36 + iota )
AKAI LPD8 pad notes
const ( LPD8_KNOB1 byte = 1 + iota LPD8_KNOB2 byte = 1 + iota LPD8_KNOB3 byte = 1 + iota LPD8_KNOB4 byte = 1 + iota LPD8_KNOB5 byte = 1 + iota LPD8_KNOB6 byte = 1 + iota LPD8_KNOB7 byte = 1 + iota LPD8_KNOB8 byte = 1 + iota )
AKAI LPD8 knob controllers
const ( NOTE_OFF byte = 0x80 NOTE_ON byte = 0x90 AFTERTOUCH byte = 0xa0 CONTROLLER byte = 0xb0 PROGRAM_CHANGE byte = 0xc0 CHANNEL_PRESSURE byte = 0xd0 PITCH_BEND byte = 0xe0 SYSTEM byte = 0xf0 )
kinds of MIDI messages
const ( CLOCK byte = 8 START byte = 10 STOP byte = 12 )
special channel numbers for SYSTEM messages
const RETRY_WAIT = 2 // seconds to wait before retrying opening midi device file
Variables ¶
This section is empty.
Functions ¶
func GetMidiMessageStream ¶
func GetMidiMessageStream(path string) chan *MidiMessage
Start some threads which will read and parse incoming MIDI messages in the background. Return a channel which emits pointers to MidiMessage structs. "path" should be the path to the midi device, e.g. "/dev/midi1". If the path can't be opened, it will keep retrying once a second forever until it succeeds.
func MidiStreamParserThread ¶
func MidiStreamParserThread(inCh chan byte, outCh chan *MidiMessage)
Read a stream of raw MIDI bytes on inCh, parse them into *MidiMessage structs, and send over outCh. It accepts CLOCK, START, and STOP system messages but other system messages are ignored.
Types ¶
type MidiMessage ¶
type MidiMessage struct { Kind byte // one of the constants above Channel byte // either a channel number of one of the special channel constants CLOCK, START, STOP Key byte // key, controller, instrument, or pitch bend lsb Value byte // velocity, touch, controller value, channel pressure, or pitch bend msb }
func GetAvailableMidiMessages ¶
func GetAvailableMidiMessages(midiMessageChan chan *MidiMessage) []*MidiMessage
Pull all the available MidiMessages out of the channel without blocking. Requires a channel with a buffer length greater than zero. This can deadlock if used by more than one goroutine at a time pulling on the same channel.
func (*MidiMessage) String ¶
func (m *MidiMessage) String() string
Convert the MidiMessage to a human-readable string so it can be printed
type MidiState ¶
type MidiState struct { KeyVolumes [128]byte // values from 0 to 127 ControllerValues [128]byte // values from 0 to 127 RecentMidiMessages []*MidiMessage // midi messages from the most recent call to UpdateStateXXX() }
Keeps track of the current state of the keys and controllers.
func (*MidiState) UpdateStateFromChannel ¶
func (midiState *MidiState) UpdateStateFromChannel(midiMessageChan chan *MidiMessage)
Given a channel of MidiMessages, read all the messages that are available right now and update the MidiState object. Requires a channel that has a buffer length greater than zero.
func (*MidiState) UpdateStateFromSlice ¶
func (midiState *MidiState) UpdateStateFromSlice(midiMessages []*MidiMessage)
Given a slice of MidiMessages, update the MidiState object. Note that the MidiState object will keep a pointer to the midiMessages object you provide here (as MidiState.RecentMidiMessages).