refactor(tracker): use strings to identify MIDI ports

This commit is contained in:
5684185+vsariola@users.noreply.github.com
2026-01-23 23:48:16 +02:00
parent 651ceb3cbb
commit 173648fbdb
5 changed files with 72 additions and 63 deletions

View File

@ -620,16 +620,16 @@ func (m *Model) ShowLicense() Action { return MakeAction((*showLicense)(m)) }
func (m *showLicense) Do() { m.dialog = License }
type selectMidiInput struct {
Item MIDIDevice
Item string
*Model
}
func (m *Model) SelectMidiInput(item MIDIDevice) Action {
func (m *Model) SelectMidiInput(item string) Action {
return MakeAction(selectMidiInput{Item: item, Model: m})
}
func (s selectMidiInput) Do() {
m := s.Model
if err := s.Item.Open(); err == nil {
if err := s.Model.MIDI.Open(s.Item); err == nil {
message := fmt.Sprintf("Opened MIDI device: %s", s.Item)
m.Alerts().Add(message, Info)
} else {

View File

@ -480,7 +480,7 @@ func NewMenuBar(tr *Tracker) *MenuBar {
}
for input := range tr.MIDI.InputDevices {
ret.midiMenuItems = append(ret.midiMenuItems,
MenuItem(tr.SelectMidiInput(input), input.String(), "", icons.ImageControlPoint),
MenuItem(tr.SelectMidiInput(input), input, "", icons.ImageControlPoint),
)
}
return ret

View File

@ -9,7 +9,6 @@ import "C"
import (
"errors"
"fmt"
"strings"
"github.com/vsariola/sointu/tracker"
"gitlab.com/gomidi/midi/v2"
@ -23,14 +22,9 @@ type (
currentIn drivers.In
broker *tracker.Broker
}
RTMIDIDevice struct {
context *RTMIDIContext
in drivers.In
}
)
func (m *RTMIDIContext) InputDevices(yield func(tracker.MIDIDevice) bool) {
func (m *RTMIDIContext) InputDevices(yield func(string) bool) {
if m.driver == nil {
return
}
@ -38,9 +32,8 @@ func (m *RTMIDIContext) InputDevices(yield func(tracker.MIDIDevice) bool) {
if err != nil {
return
}
for i := 0; i < len(ins); i++ {
device := RTMIDIDevice{context: m, in: ins[i]}
if !yield(device) {
for _, in := range ins {
if !yield(in.String()) {
break
}
}
@ -56,34 +49,43 @@ func NewContext(broker *tracker.Broker) *RTMIDIContext {
}
// Open an input device while closing the currently open if necessary.
func (m RTMIDIDevice) Open() error {
if m.context.currentIn == m.in {
func (m *RTMIDIContext) Open(name string) error {
if m.currentIn != nil && m.currentIn.String() == name {
return nil
}
if m.context.driver == nil {
if m.driver == nil {
return errors.New("no driver available")
}
if m.context.HasDeviceOpen() {
m.context.currentIn.Close()
if m.IsOpen() {
m.currentIn.Close()
}
m.context.currentIn = m.in
err := m.in.Open()
m.currentIn = nil
ins, err := m.driver.Ins()
if err != nil {
m.context.currentIn = nil
return fmt.Errorf("opening MIDI input failed: %W", err)
return fmt.Errorf("retrieving MIDI inputs failed: %w", err)
}
_, err = midi.ListenTo(m.in, m.context.HandleMessage)
for _, in := range ins {
if in.String() == name {
m.currentIn = in
}
}
if m.currentIn == nil {
return fmt.Errorf("MIDI input device not found: %s", name)
}
err = m.currentIn.Open()
if err != nil {
m.in.Close()
m.context.currentIn = nil
m.currentIn = nil
return fmt.Errorf("opening MIDI input failed: %w", err)
}
_, err = midi.ListenTo(m.currentIn, m.HandleMessage)
if err != nil {
m.currentIn.Close()
m.currentIn = nil
return fmt.Errorf("listening to MIDI input failed: %w", err)
}
return nil
}
func (d RTMIDIDevice) String() string {
return d.in.String()
}
func (m *RTMIDIContext) HandleMessage(msg midi.Message, timestampms int32) {
var channel, key, velocity uint8
if msg.GetNoteOn(&channel, &key, &velocity) {
@ -109,23 +111,6 @@ func (c *RTMIDIContext) Close() {
c.driver.Close()
}
func (c *RTMIDIContext) HasDeviceOpen() bool {
func (c *RTMIDIContext) IsOpen() bool {
return c.currentIn != nil && c.currentIn.IsOpen()
}
func (c *RTMIDIContext) TryToOpenBy(namePrefix string, takeFirst bool) {
if namePrefix == "" && !takeFirst {
return
}
for input := range c.InputDevices {
if takeFirst || strings.HasPrefix(input.String(), namePrefix) {
input.Open()
return
}
}
if takeFirst {
fmt.Errorf("Could not find any MIDI Input.\n")
} else {
fmt.Errorf("Could not find any default MIDI Input starting with \"%s\".\n", namePrefix)
}
}

View File

@ -6,6 +6,7 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/vsariola/sointu"
)
@ -126,19 +127,14 @@ type (
Dialog int
MIDIContext interface {
InputDevices(yield func(MIDIDevice) bool)
InputDevices(yield func(string) bool)
Open(name string) error
Close()
HasDeviceOpen() bool
TryToOpenBy(name string, first bool)
IsOpen() bool
}
NullMIDIContext struct{}
MIDIDevice interface {
String() string
Open() error
}
InstrumentTab int
)
@ -221,6 +217,15 @@ func NewModel(broker *Broker, synthers []sointu.Synther, midiContext MIDIContext
return m
}
func FindMIDIDeviceByPrefix(c MIDIContext, prefix string) (input string, ok bool) {
for input := range c.InputDevices {
if strings.HasPrefix(input, prefix) {
return input, true
}
}
return "", false
}
func (m *Model) change(kind string, t ChangeType, severity ChangeSeverity) func() {
if m.changeLevel == 0 {
m.changeType = NoChange
@ -434,10 +439,10 @@ func (d *modelData) Copy() modelData {
return ret
}
func (m NullMIDIContext) InputDevices(yield func(MIDIDevice) bool) {}
func (m NullMIDIContext) Close() {}
func (m NullMIDIContext) HasDeviceOpen() bool { return false }
func (m NullMIDIContext) TryToOpenBy(name string, first bool) {}
func (m NullMIDIContext) InputDevices(yield func(string) bool) {}
func (m NullMIDIContext) Open(name string) error { return nil }
func (m NullMIDIContext) Close() {}
func (m NullMIDIContext) IsOpen() bool { return false }
func (m *Model) resetSong() {
m.d.Song = defaultSong.Copy()