feat(tracker): ability to bind MIDI controllers to parameters

Closes #152
This commit is contained in:
5684185+vsariola@users.noreply.github.com
2026-01-31 23:18:14 +02:00
parent 6e8acc8f9b
commit f2ef57a845
15 changed files with 311 additions and 55 deletions

View File

@ -2,7 +2,6 @@ package tracker
import (
"sync"
"sync/atomic"
"time"
"github.com/vsariola/sointu"
@ -33,24 +32,22 @@ type (
// case <-time.After(3 * time.Second):
// }
Broker struct {
ToModel chan MsgToModel
ToPlayer chan any // TODO: consider using a sum type here, for a bit more type safety. See: https://www.jerf.org/iri/post/2917/
ToDetector chan MsgToDetector
ToGUI chan any
ToSpecAn chan MsgToSpecAn
ToModel chan MsgToModel
ToPlayer chan any // TODO: consider using a sum type here, for a bit more type safety. See: https://www.jerf.org/iri/post/2917/
ToDetector chan MsgToDetector
ToGUI chan any
ToSpecAn chan MsgToSpecAn
ToMIDIRouter chan any
CloseDetector chan struct{}
CloseGUI chan struct{}
CloseSpecAn chan struct{}
CloseDetector chan struct{}
CloseGUI chan struct{}
CloseSpecAn chan struct{}
CloseMIDIRouter chan struct{}
FinishedGUI chan struct{}
FinishedDetector chan struct{}
FinishedSpecAn chan struct{}
// mIDIEventsToGUI is true if all MIDI events should be sent to the GUI,
// for inputting notes to tracks. If false, they should be sent to the
// player instead.
mIDIEventsToGUI atomic.Bool
FinishedGUI chan struct{}
FinishedDetector chan struct{}
FinishedSpecAn chan struct{}
FinishedMIDIRouter chan struct{}
bufferPool sync.Pool
spectrumPool sync.Pool
@ -114,29 +111,25 @@ const (
func NewBroker() *Broker {
return &Broker{
ToPlayer: make(chan any, 1024),
ToModel: make(chan MsgToModel, 1024),
ToDetector: make(chan MsgToDetector, 1024),
ToGUI: make(chan any, 1024),
ToSpecAn: make(chan MsgToSpecAn, 1024),
CloseDetector: make(chan struct{}, 1),
CloseGUI: make(chan struct{}, 1),
CloseSpecAn: make(chan struct{}, 1),
FinishedGUI: make(chan struct{}),
FinishedDetector: make(chan struct{}),
FinishedSpecAn: make(chan struct{}),
bufferPool: sync.Pool{New: func() any { return &sointu.AudioBuffer{} }},
spectrumPool: sync.Pool{New: func() any { return &Spectrum{} }},
ToPlayer: make(chan any, 1024),
ToModel: make(chan MsgToModel, 1024),
ToDetector: make(chan MsgToDetector, 1024),
ToGUI: make(chan any, 1024),
ToMIDIRouter: make(chan any, 1024),
ToSpecAn: make(chan MsgToSpecAn, 1024),
CloseDetector: make(chan struct{}, 1),
CloseGUI: make(chan struct{}, 1),
CloseSpecAn: make(chan struct{}, 1),
CloseMIDIRouter: make(chan struct{}, 1),
FinishedGUI: make(chan struct{}),
FinishedDetector: make(chan struct{}),
FinishedSpecAn: make(chan struct{}),
FinishedMIDIRouter: make(chan struct{}),
bufferPool: sync.Pool{New: func() any { return &sointu.AudioBuffer{} }},
spectrumPool: sync.Pool{New: func() any { return &Spectrum{} }},
}
}
func (b *Broker) MIDIChannel() chan<- any {
if b.mIDIEventsToGUI.Load() {
return b.ToGUI
}
return b.ToPlayer
}
// GetAudioBuffer returns an audio buffer from the buffer pool. The buffer is
// guaranteed to be empty. After using the buffer, it should be returned to the
// pool with PutAudioBuffer.