mirror of
https://github.com/vsariola/sointu.git
synced 2026-02-02 05:40:15 -05:00
140 lines
3.5 KiB
Go
140 lines
3.5 KiB
Go
package tracker
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
type MIDIModel Model
|
|
|
|
func (m *Model) MIDI() *MIDIModel { return (*MIDIModel)(m) }
|
|
|
|
type (
|
|
midiState struct {
|
|
currentInput MIDIInputDevice
|
|
context MIDIContext
|
|
inputs []MIDIInputDevice
|
|
}
|
|
|
|
MIDIContext interface {
|
|
Inputs(yield func(input MIDIInputDevice) bool)
|
|
Close()
|
|
Support() MIDISupport
|
|
}
|
|
|
|
MIDIInputDevice interface {
|
|
Open() error
|
|
Close() error
|
|
IsOpen() bool
|
|
String() string
|
|
}
|
|
|
|
MIDISupport int
|
|
)
|
|
|
|
const (
|
|
MIDISupportNotCompiled MIDISupport = iota
|
|
MIDISupportNoDriver
|
|
MIDISupported
|
|
)
|
|
|
|
// Refresh
|
|
func (m *MIDIModel) Refresh() Action { return MakeAction((*midiRefresh)(m)) }
|
|
|
|
type midiRefresh MIDIModel
|
|
|
|
func (m *midiRefresh) Do() {
|
|
if m.midi.context == nil {
|
|
return
|
|
}
|
|
m.midi.inputs = m.midi.inputs[:0]
|
|
for i := range m.midi.context.Inputs {
|
|
m.midi.inputs = append(m.midi.inputs, i)
|
|
if m.midi.currentInput != nil && i.String() == m.midi.currentInput.String() {
|
|
m.midi.currentInput.Close()
|
|
m.midi.currentInput = nil
|
|
if err := i.Open(); err != nil {
|
|
(*Model)(m).Alerts().Add(fmt.Sprintf("Failed to reopen MIDI input port: %s", err.Error()), Error)
|
|
continue
|
|
}
|
|
m.midi.currentInput = i
|
|
}
|
|
}
|
|
}
|
|
|
|
// InputDevices can be iterated to get string names of all the MIDI input
|
|
// devices.
|
|
func (m *MIDIModel) Input() Int { return MakeInt((*midiInputDevices)(m)) }
|
|
|
|
type midiInputDevices MIDIModel
|
|
|
|
func (m *midiInputDevices) Value() int {
|
|
if m.midi.currentInput == nil {
|
|
return 0
|
|
}
|
|
for i, d := range m.midi.inputs {
|
|
if d == m.midi.currentInput {
|
|
return i + 1
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
func (m *midiInputDevices) SetValue(val int) bool {
|
|
if val < 0 || val > len(m.midi.inputs) {
|
|
return false
|
|
}
|
|
if m.midi.currentInput != nil {
|
|
if err := m.midi.currentInput.Close(); err != nil {
|
|
(*Model)(m).Alerts().Add(fmt.Sprintf("Failed to close current MIDI input port: %s", err.Error()), Error)
|
|
}
|
|
m.midi.currentInput = nil
|
|
}
|
|
if val == 0 {
|
|
return true
|
|
}
|
|
newInput := m.midi.inputs[val-1]
|
|
if err := newInput.Open(); err != nil {
|
|
(*Model)(m).Alerts().Add(fmt.Sprintf("Failed to open MIDI input port: %s", err.Error()), Error)
|
|
return false
|
|
}
|
|
m.midi.currentInput = newInput
|
|
(*Model)(m).Alerts().Add(fmt.Sprintf("Opened MIDI input port: %s", newInput.String()), Info)
|
|
return true
|
|
}
|
|
func (m *midiInputDevices) Range() RangeInclusive {
|
|
return RangeInclusive{Min: 0, Max: len(m.midi.inputs)}
|
|
}
|
|
func (m *midiInputDevices) StringOf(value int) string {
|
|
if value < 0 || value > len(m.midi.inputs) {
|
|
return ""
|
|
}
|
|
if value == 0 {
|
|
switch m.midi.context.Support() {
|
|
case MIDISupportNotCompiled:
|
|
return "Not compiled"
|
|
case MIDISupportNoDriver:
|
|
return "No driver"
|
|
default:
|
|
return "Closed"
|
|
}
|
|
}
|
|
return m.midi.inputs[value-1].String()
|
|
}
|
|
|
|
// InputtingNotes returns a Bool controlling whether the MIDI events are used
|
|
// just to trigger instruments, or if the note events are used to input notes to
|
|
// the note table.
|
|
func (m *MIDIModel) InputtingNotes() Bool { return MakeBool((*midiInputtingNotes)(m)) }
|
|
|
|
type midiInputtingNotes Model
|
|
|
|
func (m *midiInputtingNotes) Value() bool { return m.broker.mIDIEventsToGUI.Load() }
|
|
func (m *midiInputtingNotes) SetValue(val bool) { m.broker.mIDIEventsToGUI.Store(val) }
|
|
|
|
// NullMIDIContext is a mockup MIDIContext if you don't want to create a real
|
|
// one.
|
|
type NullMIDIContext struct{}
|
|
|
|
func (m NullMIDIContext) Inputs(yield func(input MIDIInputDevice) bool) {}
|
|
func (m NullMIDIContext) Close() {}
|
|
func (m NullMIDIContext) Support() MIDISupport { return MIDISupportNotCompiled }
|