mirror of
https://github.com/vsariola/sointu.git
synced 2026-03-20 05:40:17 -04:00
refactor(tracker): use strings to identify MIDI ports
This commit is contained in:
parent
651ceb3cbb
commit
173648fbdb
@ -20,8 +20,7 @@ import (
|
||||
|
||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
|
||||
var memprofile = flag.String("memprofile", "", "write memory profile to `file`")
|
||||
var defaultMidiInput = flag.String("midi-input", "", "connect MIDI input to matching device name")
|
||||
var firstMidiInput = flag.Bool("first-midi-input", false, "connect MIDI input to first device found")
|
||||
var defaultMidiInput = flag.String("midi-input", "", "connect MIDI input to matching device name prefix")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
@ -48,7 +47,17 @@ func main() {
|
||||
broker := tracker.NewBroker()
|
||||
midiContext := cmd.NewMidiContext(broker)
|
||||
defer midiContext.Close()
|
||||
midiContext.TryToOpenBy(*defaultMidiInput, *firstMidiInput)
|
||||
if isFlagPassed("midi-input") {
|
||||
input, ok := tracker.FindMIDIDeviceByPrefix(midiContext, *defaultMidiInput)
|
||||
if ok {
|
||||
err := midiContext.Open(input)
|
||||
if err != nil {
|
||||
log.Printf("failed to open MIDI input '%s': %v", input, err)
|
||||
}
|
||||
} else {
|
||||
log.Printf("no MIDI input device found with prefix '%s'", *defaultMidiInput)
|
||||
}
|
||||
}
|
||||
model := tracker.NewModel(broker, cmd.Synthers, midiContext, recoveryFile)
|
||||
player := tracker.NewPlayer(broker, cmd.Synthers[0])
|
||||
detector := tracker.NewDetector(broker)
|
||||
@ -96,3 +105,13 @@ func main() {
|
||||
}()
|
||||
app.Main()
|
||||
}
|
||||
|
||||
func isFlagPassed(name string) bool {
|
||||
found := false
|
||||
flag.Visit(func(f *flag.Flag) {
|
||||
if f.Name == name {
|
||||
found = true
|
||||
}
|
||||
})
|
||||
return found
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
Reference in New Issue
Block a user