Documentation ¶
Overview ¶
MIDI package is a midi format parser that parses the content of a midi stream and asyncronously send the data to a provided channel or collect the data into an accessible struct,
Index ¶
- Constants
- Variables
- func DecodeVarint(buf []byte) (x uint32, n int)
- func EncodeVarint(x uint32) []byte
- func FreqToNote(freq float64) int
- func KeyFreq(n string, octave int) float64
- func KeyInt(n string, octave int) int
- func NoteToFreq(note int) float64
- func NoteToName(note int) string
- func Uint24(n uint32) []byte
- type ControlChangeEvent
- type Decoder
- func (d *Decoder) CurrentTrack() *Track
- func (d *Decoder) IDnSize() ([4]byte, uint32, error)
- func (d *Decoder) Parse() error
- func (d *Decoder) Read(dst interface{}) error
- func (d *Decoder) ReadByte() (byte, error)
- func (d *Decoder) Uint24() (uint32, error)
- func (d *Decoder) Uint7() (uint8, error)
- func (d *Decoder) VarLen() (val uint32, readBytes uint32, err error)
- func (d *Decoder) VarLenTxt() (string, uint32, error)
- type Encoder
- type Event
- func Aftertouch(channel, key, vel int) *Event
- func ChannelAfterTouch(channel, vel int) *Event
- func ControlChange(channel, controller, newVal int) *Event
- func CopyrightEvent(txt string) *Event
- func Meta(channel int) *Event
- func NoteOff(channel, key int) *Event
- func NoteOn(channel, key, vel int) *Event
- func PitchWheelChange(channel, int, val int) *Event
- func ProgramChange(channel, controller, newVal int) *Event
- func TempoEvent(bpmF float64) *Event
- type Note
- type SmpteOffset
- type TimeSignature
- type Track
Constants ¶
const ( MetricalTF timeFormat = iota + 1 TimeCodeTF )
const ( SingleTrack uint16 = iota Syncronous Asyncronous )
Variables ¶
var ( // ErrFmtNotSupported is a generic error reporting an unknown format. ErrFmtNotSupported = errors.New("format not supported") // ErrUnexpectedData is a generic error reporting that the parser encountered unexpected data. ErrUnexpectedData = errors.New("unexpected data content") )
var CCNames = map[int]string{}/* 128 elements not displayed */
var CCVals = map[string]int{
"Bank Select": 0,
"Modulation Wheel or Lever": 1,
"Breath Controller": 2,
"Undefined": 3,
"Foot Controller": 4,
"Portamento Time": 5,
"Data Entry MSB": 6,
"Channel Volume": 7,
"Balance": 8,
"Pan": 10,
"Expression Controller": 11,
"Effect Control 1": 12,
"Effect Control 2": 13,
"General Purpose Controller 1": 16,
"General Purpose Controller 2": 17,
"General Purpose Controller 3": 18,
"General Purpose Controller 4": 19,
"Control 0 Bank Select": 32,
"Control 1 Modulation Wheel or Lever": 33,
"Control 2 Breath Controller": 34,
"Control 4 Foot Controller": 36,
"Control 5 Portamento Time": 37,
"Control 6 Data Entry": 38,
"Control 7 Channel Volume": 39,
"Control 8 Balance": 40,
"Control 10 Pan": 42,
"Control 11 Expression Controller": 43,
"Control 12 Effect control 1": 44,
"Control 13 Effect control 2": 45,
"Control 16 General Purpose Controller 1": 48,
"Control 17 General Purpose Controller 2": 49,
"Control 18 General Purpose Controller 3": 50,
"Control 19 General Purpose Controller 4": 51,
"Sustain": 64,
"Portamento": 65,
"Sostenuto": 66,
"Soft Pedal": 66,
"Legato Footswitch": 68,
"Hold 2": 69,
"Sound Variation": 70,
"Timbre/Harmonic Intens.": 71,
"Release Time": 72,
"Attack Time": 73,
"Brightness": 74,
"Decay Time": 75,
"Vibrato Rate": 76,
"Vibrato Depth": 77,
"Vibrato Delay": 78,
"General Purpose Controller 5": 80,
"General Purpose Controller 6": 81,
"General Purpose Controller 7": 82,
"General Purpose Controller 8": 83,
"Portamento Control": 84,
"High Resolution Velocity Prefix": 88,
"Effects 1 Depth": 91,
"Effects 2 Depth": 92,
"Effects 3 Depth": 93,
"Effects 4 Depth": 94,
"Effects 5 Depth": 95,
"Data Increment": 96,
"Data Decrement": 97,
"All Sound Off": 120,
"Reset All Controllers": 121,
"Local Control": 122,
"All Notes Off": 123,
"Omni Mode Off": 124,
"Omni Mode On": 125,
"Mono Mode On": 126,
"Poly Mode On": 127,
}
var EventByteMap = map[string]byte{
"NoteOff": 0x8,
"NoteOn": 0x9,
"AfterTouch": 0xA,
"ControlChange": 0xB,
"ProgramChange": 0xC,
"ChannelAfterTouch": 0xD,
"PitchWheelChange": 0xE,
"Meta": 0xF,
}
EventByteMap takes an event name and returns its equivalent MIDI byte
var EventMap = map[byte]string{
0x8: "NoteOff",
0x9: "NoteOn",
0xA: "AfterTouch",
0xB: "ControlChange",
0xC: "ProgramChange",
0xD: "ChannelAfterTouch",
0xE: "PitchWheelChange",
0xF: "Meta",
}
EventMap takes a event byte and returns its matching event name. http://www.midi.org/techspecs/midimessages.php
var Notes = []string{"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}
Functions ¶
func DecodeVarint ¶
DecodeVarint reads a varint-encoded integer from the slice. It returns the integer and the number of bytes consumed, or zero if there is not enough.
func EncodeVarint ¶
EncodeVarint returns the varint encoding of x.
func FreqToNote ¶
FreqToNote reports the associated midi node for a given frequency.
func KeyFreq ¶
KeyFreq returns the frequency for the given key/octave combo https://en.wikipedia.org/wiki/MIDI_Tuning_Standard#Frequency_values
func NoteToFreq ¶
NoteToFreq returns the frequency of the passed midi note.
func NoteToName ¶
NoteToName converts a midi note value into its English name
Types ¶
type ControlChangeEvent ¶
type Decoder ¶
type Decoder struct { Ch chan *Track /* Format describes the tracks format 0 - single-track Format 0 file has a header chunk followed by one track chunk. It is the most interchangable representation of data. It is very useful for a simple single-track player in a program which needs to make synthesizers make sounds, but which is primarily concerened with something else such as mixers or sound effect boxes. It is very desirable to be able to produce such a format, even if your program is track-based, in order to work with these simple programs. On the other hand, perhaps someone will write a format conversion from format 1 to format 0 which might be so easy to use in some setting that it would save you the trouble of putting it into your program. Synchronous multiple tracks means that the tracks will all be vertically synchronous, or in other words, they all start at the same time, and so can represent different parts in one song. 1 - multiple tracks, synchronous Asynchronous multiple tracks do not necessarily start at the same time, and can be completely asynchronous. 2 - multiple tracks, asynchronous */ Format uint16 // NumTracks represents the number of tracks in the midi file NumTracks uint16 TicksPerQuarterNote uint16 TimeFormat timeFormat Tracks []*Track // contains filtered or unexported fields }
Decoder Format documented there: http://www.music.mcgill.ca/~ich/classes/mumt306/midiformat.pdf <Header Chunk> = <chunk type><length><format><ntrks><division> Division, specifies the meaning of the delta-times. It has two formats, one for metrical time, and one for time-code-based time: +---+-----------------------------------------+ | 0 | ticks per quarter-note | ==============================================| | 1 | negative SMPTE format | ticks per frame| +---+-----------------------+-----------------+ |15 |14 8 |7 0 | If bit 15 of <division> is zero, the bits 14 thru 0 represent the number of delta time "ticks" which make up a quarter-note. For instance, if division is 96, then a time interval of an eighth-note between two events in the file would be 48. If bit 15 of <division> is a one, delta times in a file correspond to subdivisions of a second, in a way consistent with SMPTE and MIDI Time Code. Bits 14 thru 8 contain one of the four values -24, -25, -29, or -30, corresponding to the four standard SMPTE and MIDI Time Code formats (-29 corresponds to 30 drop frome), and represents the number of frames per second. These negative numbers are stored in two's compliment form. The second byte (stored positive) is the resolution within a frame: typical values may be 4 (MIDI Time Code resolution), 8, 10, 80 (bit resolution), or 100. This stream allows exact specifications of time-code-based tracks, but also allows milisecond-based tracks by specifying 25|frames/sec and a resolution of 40 units per frame. If the events in a file are stored with a bit resolution of thirty-framel time code, the division word would be E250 hex.
func NewDecoder ¶
func (*Decoder) CurrentTrack ¶
func (*Decoder) Read ¶
read reads n bytes from the parser's reader and stores them into the provided dst, which must be a pointer to a fixed-size value.
type Encoder ¶
type Encoder struct { /* Format describes the tracks format 0 - single-track Format 0 file has a header chunk followed by one track chunk. It is the most interchangable representation of data. It is very useful for a simple single-track player in a program which needs to make synthesizers make sounds, but which is primarily concerened with something else such as mixers or sound effect boxes. It is very desirable to be able to produce such a format, even if your program is track-based, in order to work with these simple programs. On the other hand, perhaps someone will write a format conversion from format 1 to format 0 which might be so easy to use in some setting that it would save you the trouble of putting it into your program. Synchronous multiple tracks means that the tracks will all be vertically synchronous, or in other words, they all start at the same time, and so can represent different parts in one song. 1 - multiple tracks, synchronous Asynchronous multiple tracks do not necessarily start at the same time, and can be completely asynchronous. 2 - multiple tracks, asynchronous */ Format uint16 // NumTracks represents the number of tracks in the midi file NumTracks uint16 // resolution for delta timing TicksPerQuarterNote uint16 TimeFormat timeFormat Tracks []*Track // contains filtered or unexported fields }
func NewEncoder ¶
func NewEncoder(w io.WriteSeeker, format uint16, ppqn uint16) *Encoder
type Event ¶
type Event struct { TimeDelta uint32 MsgType uint8 MsgChan uint8 Note uint8 Velocity uint8 Pressure uint8 Controller uint8 NewValue uint8 NewProgram uint8 Channel uint8 AbsPitchBend uint16 RelPitchBend int16 // Meta Cmd uint8 SeqNum uint16 Text string Copyright string SeqTrackName string InstrumentName string Lyric string Marker string CuePoint string MsPerQuartNote uint32 Bpm uint32 TimeSignature *TimeSignature // A positive value for the key specifies the number of sharps and a negative value specifies the number of flats. Key int32 //-7 to +7 // A value of 0 for the scale specifies a major key and a value of 1 specifies a minor key. Scale uint32 // 0 or 1 // SmpteOffset *SmpteOffset }
Event <event> = <MIDI event> | <sysex event> | <meta-event> <MIDI event> is any MIDI channel message. Running status is used: status bytes of MIDI channel messages may be omitted if the preceding event is a MIDI channel message with the same status. The first event in each MTrk chunk must specifyy status. Delta-time is not considered an event itself: it is an integral part of the syntax for an MTrk event. Notice that running status occurs across delta-times. See http://www.indiana.edu/~emusic/etext/MIDI/chapter3_MIDI4.shtml
func Aftertouch ¶
AfterTouch returns a pointer to a new aftertouch event
func ChannelAfterTouch ¶
ChannelAfterTouch is a global aftertouch with a value from 0 to 127
func ControlChange ¶
ControlChange sets a new value for a given controller The controller number is between 0-119. The new controller value is between 0-127.
func CopyrightEvent ¶
CopyrightEvent returns a copyright event with the passed string in it.
func NoteOff ¶
NoteOff returns a pointer to a new event of type NoteOff (without the delta timing data)
func NoteOn ¶
NoteOn returns a pointer to a new event of type NoteOn (without the delta timing data)
func PitchWheelChange ¶
PitchWheelChange is sent to indicate a change in the pitch bender. The possible value goes between 0 and 16383 where 8192 is the center.
func ProgramChange ¶
ProgramChange sets a new value the same way as ControlChange but implements Mode control and special message by using reserved controller numbers 120-127.
func TempoEvent ¶
TempoEvent returns a new tempo event of the passed value.
func (*Event) Encode ¶
Encode converts an Event into a slice of bytes ready to be written to a file.
type TimeSignature ¶
type TimeSignature struct { Numerator uint8 Denominator uint8 ClocksPerTick uint8 ThirtySecondNotesPerQuarter uint8 }
Time signature FF 58 04 nn dd cc bb Time Signature The time signature is expressed as four numbers. nn and dd represent the numerator and denominator of the time signature as it would be notated. The denominator is a negative power of two: 2 represents a quarter-note, 3 represents an eighth-note, etc. The cc parameter expresses the number of MIDI clocks in a metronome click. The bb parameter expresses the number of notated 32nd-notes in a MIDI quarter-note (24 MIDI clocks). This was added because there are already multiple programs which allow a user to specify that what MIDI thinks of as a quarter-note (24 clocks) is to be notated as, or related to in terms of, something else.
func (*TimeSignature) String ¶
func (ts *TimeSignature) String() string