Skip to main content
Glama
emicklei

melrōse musical expression player

by emicklei
note_midi.go2.13 kB
package core import ( "errors" "time" ) // noteMidiOffsets maps a tone index (C=0) to the number of semitones on the scale var noteMidiOffsets = []int{0, 2, 4, 5, 7, 9, 11} const ( // maps a tone to an index (C=0) nonRestNoteNames = "CDEFGAB" ) var noteNameToOffset = map[string]int{ "C": 0, "D": 2, "E": 4, "F": 5, "G": 7, "A": 9, "B": 11, } func (n Note) MIDI() int { // http://en.wikipedia.org/wiki/Musical_Note // C4 = 60 (scientific pitch notation) if !n.IsHearable() { return 0 } nameOffset := noteNameToOffset[n.Name] return ((1 + n.Octave) * 12) + nameOffset + n.Accidental } func DurationToFraction(bpm float64, d time.Duration) float32 { one := WholeNoteDuration(bpm) abs := func(i int) int { if i < 0 { return -i } return i } numbers := []struct { fraction float32 ms int }{ {1.0, int(one)}, {0.5, int(one / time.Duration(2))}, {0.25, int(one / time.Duration(4))}, {0.125, int(one / time.Duration(8))}, {0.0625, int(one / time.Duration(16))}, } millis := int(d) distance := abs(numbers[0].ms - millis) idx := 0 for c := 1; c < len(numbers); c++ { cdistance := abs(numbers[c].ms - millis) if cdistance < distance { idx = c distance = cdistance } } return numbers[idx].fraction } func MIDItoNote(fraction float32, nr int, vel int) (Note, error) { if fraction < 0 { return Rest4, errors.New("MIDI fraction cannot be < 0") } if nr < 0 || nr > 127 { return Rest4, errors.New("MIDI number must be in [0..127]") } if vel < 0 || vel > 127 { return Rest4, errors.New("MIDI velocity must be in [0..127]") } name, octave, accidental := MIDIToNoteParts(nr) return MakeNote(name, octave, fraction, accidental, false, vel), nil } func MIDIToNoteParts(nr int) (name string, octave int, accidental int) { octave = (nr / 12) - 1 nrIndex := nr - ((octave + 1) * 12) var offsetIndex, offset int for o, each := range noteMidiOffsets { if each >= nrIndex { offsetIndex = o offset = each break } } accidental = 0 if nrIndex != offset { accidental = -1 } return string(nonRestNoteNames[offsetIndex]), octave, accidental }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/emicklei/melrose'

If you have feedback or need assistance with the MCP directory API, please join our Discord server