tracker

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 12, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Overview

Package tracker contains the data model for the Sointu tracker GUI.

The tracker package defines the Model struct, which holds the entire application state, including the song data, instruments, effects, and large part of the UI state.

The GUI does not modify the Model data directly, rather, there are types Action, Bool, Int, String, List and Table which can be used to manipulate the model data in a controlled way. For example, model.ShowLicense() returns an Action to show the license to the user, which can be executed with model.ShowLicense().Do().

The various Actions and other data manipulation methods are grouped based on their functionalities. For example, model.Instrument() groups all the ways to manipulate the instrument(s). Similarly, model.Play() groups all the ways to start and stop playback.

The method naming aims at API fluency. For example, model.Play().FromBeginning() returns an Action to start playing the song from the beginning. Similarly, model.Instrument().Add() returns an Action to add a new instrument to the song and model.Instrument().List() returns a List of all the instruments.

Index

Constants

View Source
const (
	NoDialog = iota
	SaveAsExplorer
	NewSongChanges
	NewSongSaveExplorer
	OpenSongChanges
	OpenSongSaveExplorer
	OpenSongOpenExplorer
	Export
	ExportFloatExplorer
	ExportInt16Explorer
	QuitChanges
	QuitSaveExplorer
	License
	DeleteUserPresetDialog
	OverwriteUserPresetDialog
)
View Source
const (
	BuiltinPresets presetKindEnum = -1
	AllPresets     presetKindEnum = 0
	UserPresets    presetKindEnum = 1
)
View Source
const (
	SpecSpeedMin = -3
	SpecSpeedMax = 3
)
View Source
const (
	SpecResolutionMin = -3
	SpecResolutionMax = 3
)
View Source
const MAX_INTEGRATED_DATA = 10 * 60 * 60 // 1 hour of samples at 10 Hz (100 ms per sample)
View Source
const MAX_MIDI_CHANNELS = 16
View Source
const MAX_SIGNAL_AMPLITUDE = 1e12

In the detector, we clamp the signal levels to +-MAX_SIGNAL_AMPLITUDE to avoid Inf results. This is 240 dBFS. max float32 is about 3.4e38, so squaring the amplitude values gives 1e24, and adding 4410 of those together (when taking the mean) gives a value < 1e37, which is still < max float32.

Variables

View Source
var ErrInvalidRows = errors.New("rows per beat and rows per pattern must be greater than 1")
View Source
var ErrNotFinished = errors.New("the recording was not finished")
View Source
var GmDlsEntries = []GmDlsEntry{}/* 495 elements not displayed */

GmDlsEntries is a list of all samples in the gm.dls file. Do not modify during runtime.

Functions

func Insert added in v0.5.0

func Insert[T any, S ~[]T](slice S, index int, inserted ...T) (ret S, ok bool)

Insert inserts elements into a slice at the given index. If the index is out of bounds, the function returns false.

func RemoveUnusedUnitParameters added in v0.5.0

func RemoveUnusedUnitParameters(instr *sointu.Instrument) bool

RemoveUnusedUnitParameters removes any parameters from the instrument that are not valid for the unit type. It returns true if any parameters were removed.

func TimeoutReceive added in v0.5.0

func TimeoutReceive[T any](c <-chan T, t time.Duration) (v T, ok bool)

TimeoutReceive is a helper function to block until a value is received from a channel, or timing out after t. ok will be false if the timeout occurred or if the channel is closed.

func TrySend added in v0.5.0

func TrySend[T any](c chan<- T, v T) bool

TrySend is a helper function to send a value to a channel if it is not full. It is guaranteed to be non-blocking. Return true if the value was sent, false otherwise.

func VoiceSlice added in v0.5.0

func VoiceSlice[T any, S ~[]T, P sointu.NumVoicerPointer[T]](slice S, ranges ...Range) (ret S, ok bool)

VoiceSlice works similar to the Slice function, but takes a slice of NumVoicer:s and treats it as a "virtual slice", with element repeated by the number of voices it has. NumVoicer interface is implemented at least by sointu.Tracks and sointu.Instruments. For example, if parameter "slice" has three elements, returning GetNumVoices 2, 1, and 3, the VoiceSlice thinks of this as a virtual slice of 6 elements [0,0,1,2,2,2]. Then, the "ranges" parameter are slicing ranges to this virtual slice. Continuing with the example, if "ranges" was [2,5), the virtual slice would be [1,2,2], and the function would return a slice with two elements: first with NumVoices 1 and second with NumVoices 2. If multiple ranges are given, multiple virtual slices are concatenated. However, when doing so, splitting an element is not allowed. In the previous example, if the ranges were [1,3) and [0,1), the resulting concatenated virtual slice would be [0,1,0], and here the 0 element would be split. This is to avoid accidentally making shallow copies of reference types.

Types

type Action added in v0.4.0

type Action struct {
	// contains filtered or unexported fields
}

Action describes a user action that can be performed on the model, which can be initiated by calling the Do() method. It is usually initiated by a button press or a menu item. Action advertises whether it is enabled, so UI can e.g. gray out buttons when the underlying action is not allowed. The underlying Doer can optionally implement the Enabler interface to decide if the action is enabled or not; if it does not implement the Enabler interface, the action is always allowed.

func MakeAction added in v0.5.0

func MakeAction(doer Doer) Action

func (Action) Do added in v0.4.0

func (a Action) Do()

func (Action) Enabled added in v0.5.0

func (a Action) Enabled() bool

type Alert added in v0.4.0

type Alert struct {
	Name      string
	Priority  AlertPriority
	Message   string
	Duration  time.Duration
	FadeLevel float64
}

type AlertPriority added in v0.4.0

type AlertPriority int
const (
	None AlertPriority = iota
	Info
	Warning
	Error
)

type Alerts added in v0.4.0

type Alerts Model

func (*Alerts) Add added in v0.4.0

func (m *Alerts) Add(message string, priority AlertPriority)

Add a new alert with the given message and priority.

func (*Alerts) AddAlert added in v0.4.0

func (m *Alerts) AddAlert(a Alert)

AddAlert adds or updates an alert.

func (*Alerts) AddNamed added in v0.4.0

func (m *Alerts) AddNamed(name, message string, priority AlertPriority)

AddNamed adds a new alert with the given name, message, and priority.

func (*Alerts) ClearNamed added in v0.6.0

func (m *Alerts) ClearNamed(name string)

ClearNamed clears the alert with the given name.

func (*Alerts) Iterate added in v0.4.0

func (m *Alerts) Iterate(yield func(index int, alert Alert) bool)

Iterate through the alerts.

func (Alerts) Len added in v0.4.0

func (m Alerts) Len() int

func (Alerts) Less added in v0.4.0

func (m Alerts) Less(i, j int) bool

func (*Alerts) Pop added in v0.4.0

func (m *Alerts) Pop() any

func (*Alerts) Push added in v0.4.0

func (m *Alerts) Push(x any)

func (Alerts) Swap added in v0.4.0

func (m Alerts) Swap(i, j int)

func (*Alerts) Update added in v0.4.0

func (m *Alerts) Update(d time.Duration) (animating bool)

Update the alerts, reducing their duration and updating their fade levels, given the elapsed time d.

type BPMMsg added in v0.4.0

type BPMMsg struct {
	// contains filtered or unexported fields
}

Model implements the mutable state for the tracker program GUI.

Go does not have immutable slices, so there's no efficient way to guarantee accidental mutations in the song. But at least the value members are protected. It is owned by the GUI thread (goroutine), while the player is owned by by the audioprocessing thread. They communicate using the two channels

type BiquadCoeffs added in v0.6.0

type BiquadCoeffs struct {
	// contains filtered or unexported fields
}

func (*BiquadCoeffs) Gain added in v0.6.0

func (c *BiquadCoeffs) Gain(omega float32) float32

type Bool added in v0.4.0

type Bool struct {
	// contains filtered or unexported fields
}

func MakeBool added in v0.5.0

func MakeBool(value BoolValue) Bool

func MakeBoolFromPtr added in v0.6.0

func MakeBoolFromPtr(value *bool) Bool

func (Bool) Enabled added in v0.5.0

func (v Bool) Enabled() bool

func (Bool) SetValue added in v0.5.0

func (v Bool) SetValue(value bool) (changed bool)

func (Bool) Toggle added in v0.4.0

func (v Bool) Toggle()

func (Bool) Value added in v0.5.0

func (v Bool) Value() bool

type BoolValue added in v0.5.0

type BoolValue interface {
	Value() bool
	SetValue(bool)
}

type Broker added in v0.5.0

type 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
	ToMIDIHandler chan any

	CloseDetector    chan struct{}
	CloseGUI         chan struct{}
	CloseSpecAn      chan struct{}
	CloseMIDIHandler chan struct{}

	FinishedGUI         chan struct{}
	FinishedDetector    chan struct{}
	FinishedSpecAn      chan struct{}
	FinishedMIDIHandler chan struct{}
	// contains filtered or unexported fields
}

Broker is the centralized message broker for the tracker. It is used to communicate between the player, the model, and the loudness detector. At the moment, the broker is just many-to-one communication, implemented with one channel for each recipient. Additionally, the broker has a sync.pool for *sointu.AudioBuffers, from which the player can get and return buffers to pass buffers around without allocating new memory every time. We can later consider making many-to-many types of communication and more complex routing logic to the Broker if needed.

For closing goroutines, the broker has two channels for each goroutine: CloseXXX and FinishedXXX. The CloseXXX channel has a capacity of 1, so you can always send a empty message (struct{}{}) to it without blocking. If the channel is already full, that means someone else has already requested its closure and the goroutine is already closing, so dropping the message is fine. Then, FinishedXXX is used to signal that a goroutine has succesfully closed and cleaned up. Nothing is ever sent to the channel, it is only closed. You can wait until the goroutines is done closing with "<- FinishedXXX", which for avoiding deadlocks can be combined with a timeout:

select {
  case <-FinishedXXX:
  case <-time.After(3 * time.Second):
}

func NewBroker added in v0.5.0

func NewBroker() *Broker

func (*Broker) GetAudioBuffer added in v0.5.0

func (b *Broker) GetAudioBuffer() *sointu.AudioBuffer

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.

func (*Broker) GetSpectrum added in v0.6.0

func (b *Broker) GetSpectrum() *Spectrum

func (*Broker) PutAudioBuffer added in v0.5.0

func (b *Broker) PutAudioBuffer(buf *sointu.AudioBuffer)

PutAudioBuffer returns an audio buffer to the buffer pool. If the buffer is not empty, its length is resetted (but capacity kept) before returning it to the pool.

func (*Broker) PutSpectrum added in v0.6.0

func (b *Broker) PutSpectrum(s *Spectrum)

type ChangeSeverity added in v0.4.0

type ChangeSeverity int

Model implements the mutable state for the tracker program GUI.

Go does not have immutable slices, so there's no efficient way to guarantee accidental mutations in the song. But at least the value members are protected. It is owned by the GUI thread (goroutine), while the player is owned by by the audioprocessing thread. They communicate using the two channels

const (
	MajorChange ChangeSeverity = iota
	MinorChange
)

type ChangeType added in v0.4.0

type ChangeType int

Model implements the mutable state for the tracker program GUI.

Go does not have immutable slices, so there's no efficient way to guarantee accidental mutations in the song. But at least the value members are protected. It is owned by the GUI thread (goroutine), while the player is owned by by the audioprocessing thread. They communicate using the two channels

const (
	NoChange    ChangeType = 0
	PatchChange ChangeType = 1 << iota
	ScoreChange
	BPMChange
	RowsPerBeatChange
	SongChange ChangeType = PatchChange | ScoreChange | BPMChange | RowsPerBeatChange
)

type Cursor added in v0.4.0

type Cursor struct {
	Track int
	sointu.SongPos
}

Cursor identifies a row and a track in a song score.

type Decibel added in v0.5.0

type Decibel float32

type DetectorModel added in v0.6.0

type DetectorModel Model

func (*DetectorModel) Oversampling added in v0.6.0

func (m *DetectorModel) Oversampling() Bool

Oversampling returns a Bool property for setting whether the peak detector uses oversampling to calculate true peaks, or just sample peaks if not.

func (*DetectorModel) Result added in v0.6.0

func (m *DetectorModel) Result() DetectorResult

Result returns the latest DetectorResult from the detector.

func (*DetectorModel) Weighting added in v0.6.0

func (m *DetectorModel) Weighting() Int

Weighting returns an Int property for setting the detector weighting type.

type DetectorResult added in v0.5.0

type DetectorResult struct {
	Loudness LoudnessResult
	Peaks    PeakResult
}

type Dialog added in v0.4.0

type Dialog int

Model implements the mutable state for the tracker program GUI.

Go does not have immutable slices, so there's no efficient way to guarantee accidental mutations in the song. But at least the value members are protected. It is owned by the GUI thread (goroutine), while the player is owned by by the audioprocessing thread. They communicate using the two channels

type Doer added in v0.5.0

type Doer interface {
	Do()
}

Doer is an interface that defines a single Do() method, which is called when an action is performed.

type Enabler added in v0.5.0

type Enabler interface {
	Enabled() bool
}

Enabler is an interface that defines a single Enabled() method, which is used by the UI to check if UI Action/Bool/Int etc. is enabled or not.

type Envelope added in v0.6.0

type Envelope [5]EnvelopePoint

func (*Envelope) Value added in v0.6.0

func (e *Envelope) Value(position int) float32

type EnvelopePoint added in v0.6.0

type EnvelopePoint struct {
	Position     int
	Level, Slope float32
}

func (*EnvelopePoint) Value added in v0.6.0

func (e *EnvelopePoint) Value(position int) float32

type Explore added in v0.4.0

type Explore struct {
	IsSave       bool         // true if this is a save operation, false if open operation
	IsSong       bool         // true if this is a song, false if instrument
	Continuation func(string) // function to call with the selected file path
}

Model implements the mutable state for the tracker program GUI.

Go does not have immutable slices, so there's no efficient way to guarantee accidental mutations in the song. But at least the value members are protected. It is owned by the GUI thread (goroutine), while the player is owned by by the audioprocessing thread. They communicate using the two channels

type GUIMessageKind added in v0.5.0

type GUIMessageKind int
const (
	GUIMessageKindNone GUIMessageKind = iota
	GUIMessageCenterOnRow
	GUIMessageEnsureCursorVisible
)

type GmDlsEntry

type GmDlsEntry struct {
	Start              int    // sample start offset in words
	LoopStart          int    // loop start offset in words
	LoopLength         int    // loop length in words
	SuggestedTranspose int    // suggested transpose in semitones, so that all samples play at same pitch
	Name               string // sample Name
}

GmDlsEntry is a single sample entry from the gm.dls file

type HistoryModel added in v0.6.0

type HistoryModel Model

func (*HistoryModel) MarshalRecovery added in v0.6.0

func (m *HistoryModel) MarshalRecovery() []byte

MarshalRecovery marshals the current model data to a byte slice for recovery saving.

func (*HistoryModel) Redo added in v0.6.0

func (m *HistoryModel) Redo() Action

Redo returns an Action to redo the last undone change.

func (*HistoryModel) SaveRecovery added in v0.6.0

func (m *HistoryModel) SaveRecovery() error

SaveRecovery saves the current model data to the recovery file on disk if there are unsaved changes.

func (*HistoryModel) Undo added in v0.6.0

func (m *HistoryModel) Undo() Action

Undo returns an Action to undo the last change.

func (*HistoryModel) UnmarshalRecovery added in v0.6.0

func (m *HistoryModel) UnmarshalRecovery(bytes []byte)

UnmarshalRecovery unmarshals the model data from a byte slice, then checking if a recovery file exists on disk and loading it instead.

type InstrModel added in v0.6.0

type InstrModel Model

func (*InstrModel) Add added in v0.6.0

func (m *InstrModel) Add() Action

Add returns an Action to add a new instrument.

func (*InstrModel) Comment added in v0.6.0

func (m *InstrModel) Comment() String

Comment returns a String representing the comment of the currently selected instrument.

func (*InstrModel) Delete added in v0.6.0

func (m *InstrModel) Delete() Action

Delete returns an Action to delete the currently selected instrument(s).

func (*InstrModel) Item added in v0.6.0

func (v *InstrModel) Item(i int) (name, title string, maxLevel float32, mute bool, ok bool)

Item returns information about the instrument at a given index.

func (*InstrModel) List added in v0.6.0

func (m *InstrModel) List() List

List returns a List of all the instruments in the patch, implementing ListData and MutableListData interfaces.

func (*InstrModel) Mute added in v0.6.0

func (m *InstrModel) Mute() Bool

Mute returns a Bool for muting/unmuting the currently selected instrument(s).

func (*InstrModel) Name added in v0.6.0

func (m *InstrModel) Name() String

Name returns a String representing the name of the currently selected instrument.

func (*InstrModel) Read added in v0.6.0

func (m *InstrModel) Read(r io.ReadCloser) bool

Read reads an instrument from the given io.ReadCloser and sets it as the currently selected instrument. The format is determined by trying JSON first, then YAML, then 4klang Patch, then 4klang Instrument.

func (*InstrModel) Solo added in v0.6.0

func (m *InstrModel) Solo() Bool

Solo returns a Bool for soloing/unsoloing the currently selected instrument(s).

func (*InstrModel) Split added in v0.6.0

func (m *InstrModel) Split() Action

Split returns an Action to split the currently selected instrument, dividing the voices as evenly as possible.

func (*InstrModel) Tab added in v0.6.0

func (m *InstrModel) Tab() Int

Tab returns an Int representing the currently selected instrument tab.

func (*InstrModel) Thread1 added in v0.6.0

func (m *InstrModel) Thread1() Bool

func (*InstrModel) Thread2 added in v0.6.0

func (m *InstrModel) Thread2() Bool

func (*InstrModel) Thread3 added in v0.6.0

func (m *InstrModel) Thread3() Bool

func (*InstrModel) Thread4 added in v0.6.0

func (m *InstrModel) Thread4() Bool

func (*InstrModel) Voices added in v0.6.0

func (m *InstrModel) Voices() Int

Voices returns an Int representing the number of voices for the currently selected instrument.

func (*InstrModel) Write added in v0.6.0

func (m *InstrModel) Write(w io.WriteCloser) bool

Write writes the currently selected instrument to the given io.WriteCloser. If the WriteCloser is a file, the file extension is used to determine the format (.json for JSON, anything else for YAML).

type InstrumentTab added in v0.6.0

type InstrumentTab int

Model implements the mutable state for the tracker program GUI.

Go does not have immutable slices, so there's no efficient way to guarantee accidental mutations in the song. But at least the value members are protected. It is owned by the GUI thread (goroutine), while the player is owned by by the audioprocessing thread. They communicate using the two channels

const (
	InstrumentEditorTab InstrumentTab = iota
	InstrumentPresetsTab
	InstrumentCommentTab
	NumInstrumentTabs
)

type Int added in v0.4.0

type Int struct {
	// contains filtered or unexported fields
}

Int represents an integer value in the tracker model e.g. BPM, song length, etc. It is a wrapper around an IntValue interface that provides methods to manipulate the value, but Int guard that all changes are within the range of the underlying IntValue implementation and that SetValue is not called when the value is unchanged. The IntValue can optionally implement the StringOfer interface to provide custom string representations of the integer values.

func MakeInt added in v0.5.0

func MakeInt(value IntValue) Int

func (Int) Add added in v0.4.0

func (v Int) Add(delta int) (changed bool)

func (Int) Range added in v0.5.0

func (v Int) Range() RangeInclusive

func (Int) SetValue added in v0.5.0

func (v Int) SetValue(value int) (changed bool)

func (Int) String added in v0.6.0

func (v Int) String() string

func (*Int) StringOf added in v0.6.0

func (v *Int) StringOf(value int) string

func (Int) Value added in v0.5.0

func (v Int) Value() int

func (Int) Values added in v0.6.0

func (v Int) Values(yield func(int, string) bool)

type IntValue added in v0.5.0

type IntValue interface {
	Value() int
	SetValue(int) (changed bool)
	Range() RangeInclusive
}

type IsPlayingMsg added in v0.4.0

type IsPlayingMsg struct {
	// contains filtered or unexported fields
}

Model implements the mutable state for the tracker program GUI.

Go does not have immutable slices, so there's no efficient way to guarantee accidental mutations in the song. But at least the value members are protected. It is owned by the GUI thread (goroutine), while the player is owned by by the audioprocessing thread. They communicate using the two channels

type List added in v0.4.0

type List struct {
	// contains filtered or unexported fields
}

func MakeList added in v0.6.0

func MakeList(data ListData) List

func (List) CopyElements added in v0.4.0

func (v List) CopyElements() ([]byte, bool)

CopyElements copies the selected elements in a list. The list must implement the MutableListData interface. Returns the copied data, marshaled into byte slice, and true if successful.

func (List) Count added in v0.6.0

func (l List) Count() int

func (List) DeleteElements added in v0.4.0

func (v List) DeleteElements(backwards bool) bool

DeleteElements deletes the selected elements in a list. The list must implement the MutableListData interface.

func (List) MoveElements added in v0.4.0

func (v List) MoveElements(delta int) bool

MoveElements moves the selected elements in a list by delta. The list must implement the MutableListData interface.

func (List) Mutable added in v0.6.0

func (v List) Mutable() bool

func (List) PasteElements added in v0.4.0

func (v List) PasteElements(data []byte) (ok bool)

PasteElements pastes the data into the list. The data is unmarshaled from the byte slice. The list must implement the MutableListData interface. Returns true if successful.

func (List) Selected added in v0.6.0

func (l List) Selected() int

func (List) Selected2 added in v0.6.0

func (l List) Selected2() int

func (List) SetSelected added in v0.6.0

func (l List) SetSelected(value int)

func (List) SetSelected2 added in v0.6.0

func (l List) SetSelected2(value int)

type ListData added in v0.4.0

type ListData interface {
	Selected() int
	Selected2() int
	SetSelected(int)
	SetSelected2(int)
	Count() int
}

type Loop added in v0.4.0

type Loop struct {
	Start, Length int
}

Loop identifier the order rows, which are the loop positions Length = 0 means no loop is chosen, regardless of start

type LoudnessResult added in v0.5.0

type LoudnessResult [NumLoudnessTypes]Decibel

type LoudnessType added in v0.5.0

type LoudnessType int
const (
	LoudnessMomentary LoudnessType = iota
	LoudnessShortTerm
	LoudnessMaxMomentary
	LoudnessMaxShortTerm
	LoudnessIntegrated
	NumLoudnessTypes
)

type MIDIBindings added in v0.6.0

type MIDIBindings struct {
	ControlBindings map[MIDIControl]MIDIParam
	ParamBindings   map[MIDIParam]MIDIControl
}

Two-way map between MIDI controls and parameters that makes sure only one control channel is linked to only one parameter and vice versa.

func (*MIDIBindings) Copy added in v0.6.0

func (t *MIDIBindings) Copy() MIDIBindings

func (*MIDIBindings) GetControl added in v0.6.0

func (t *MIDIBindings) GetControl(p MIDIParam) (MIDIControl, bool)

func (*MIDIBindings) GetParam added in v0.6.0

func (t *MIDIBindings) GetParam(m MIDIControl) (MIDIParam, bool)
func (t *MIDIBindings) Link(m MIDIControl, p MIDIParam)

func (MIDIBindings) MarshalJSON added in v0.6.0

func (t MIDIBindings) MarshalJSON() ([]byte, error)

func (*MIDIBindings) UnlinkParam added in v0.6.0

func (t *MIDIBindings) UnlinkParam(p MIDIParam)

func (*MIDIBindings) UnmarshalJSON added in v0.6.0

func (t *MIDIBindings) UnmarshalJSON(data []byte) error

marshal as slice of bindings cause json doesn't support marshaling maps with struct keys

type MIDIContext added in v0.5.0

type MIDIContext interface {
	Inputs(yield func(input MIDIInputDevice) bool)
	Close()
	Support() MIDISupport
}

type MIDIControl added in v0.6.0

type MIDIControl struct{ Channel, Control int }

type MIDIInputDevice added in v0.6.0

type MIDIInputDevice interface {
	Open(func(msg *MIDIMessage)) error
	Close() error
	IsOpen() bool
	String() string
}

type MIDIMessage added in v0.6.0

type MIDIMessage struct {
	Timestamp int64 // in samples (at 44100 Hz)
	Data      [3]byte
	Source    any // tag to identify the source of the message; any unique pointer will do
}

MIDIMessage represents a MIDI message received from a MIDI input port or VST host.

type MIDIModel added in v0.6.0

type MIDIModel Model

func (*MIDIModel) Binding added in v0.6.0

func (m *MIDIModel) Binding() Bool

Binding returns a Bool controlling whether the next received MIDI controller event is used to bind a parameter.

func (*MIDIModel) Change added in v0.6.0

func (m *MIDIModel) Change() Bool

Change returns a Bool controlling whether only the change in note or velocity value is used

func (*MIDIModel) Channel added in v0.6.0

func (m *MIDIModel) Channel() Int

Channel returns an Int controlling the MIDI channel of the currently selected instrument. 0 = automatically selected, 1-16 fixed to specific MIDI channel

func (*MIDIModel) IgnoreNoteOff added in v0.6.0

func (m *MIDIModel) IgnoreNoteOff() Bool

IgnoreNoteOff returns a Bool controlling whether note off events are ignored

func (*MIDIModel) Input added in v0.6.0

func (m *MIDIModel) Input() Int

InputDevices can be iterated to get string names of all the MIDI input devices.

func (*MIDIModel) InputtingNotes added in v0.6.0

func (m *MIDIModel) InputtingNotes() Bool

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 (*MIDIModel) NoteEnd added in v0.6.0

func (m *MIDIModel) NoteEnd() Int

NoteEnd returns an Int controlling the MIDI note end value of the currently selected instrument.

func (*MIDIModel) NoteStart added in v0.6.0

func (m *MIDIModel) NoteStart() Int

NoteStart returns an Int controlling the MIDI note start value of the currently selected instrument.

func (*MIDIModel) Refresh added in v0.6.0

func (m *MIDIModel) Refresh() Action

Refresh

func (*MIDIModel) Transpose added in v0.6.0

func (m *MIDIModel) Transpose() Int

Transpose returns an Int controlling the MIDI transpose value of the currently selected instrument.

func (*MIDIModel) Unbind added in v0.6.0

func (m *MIDIModel) Unbind() Action

Unbind removes the MIDI binding for the currently selected parameter.

func (*MIDIModel) UnbindAll added in v0.6.0

func (m *MIDIModel) UnbindAll() Action

UnbindAll removes all MIDI bindings.

func (*MIDIModel) Velocity added in v0.6.0

func (m *MIDIModel) Velocity() Bool

Velocity returns a Bool controlling whether the velocity value from MIDI event is used instead of the normal note value

type MIDIParam added in v0.6.0

type MIDIParam struct {
	Id       int
	Param    string
	Min, Max int
}

type MIDISupport added in v0.6.0

type MIDISupport int
const (
	MIDISupportNotCompiled MIDISupport = iota
	MIDISupportNoDriver
	MIDISupported
)

type Model

type Model struct {
	// contains filtered or unexported fields
}

Model implements the mutable state for the tracker program GUI.

Go does not have immutable slices, so there's no efficient way to guarantee accidental mutations in the song. But at least the value members are protected. It is owned by the GUI thread (goroutine), while the player is owned by by the audioprocessing thread. They communicate using the two channels

func NewModel

func NewModel(broker *Broker, synthers []sointu.Synther, midiContext MIDIContext, recoveryFilePath string) *Model

NewModelPlayer creates a new model and a player that communicates with it

func (*Model) Alerts added in v0.4.0

func (m *Model) Alerts() *Alerts

Alerts returns the Alerts model from the main Model, used to manage alerts.

func (*Model) Broker added in v0.5.0

func (m *Model) Broker() *Broker

func (*Model) CancelDialog added in v0.6.0

func (m *Model) CancelDialog() Action

CancelDialog returns an Action to cancel the current dialog.

func (*Model) Close added in v0.6.0

func (m *Model) Close()

func (*Model) Detector added in v0.6.0

func (m *Model) Detector() *DetectorModel

Detector returns a DetectorModel which provides access to the detector settings and results.

func (*Model) Dialog added in v0.4.0

func (m *Model) Dialog() Dialog

func (*Model) ForceQuit added in v0.4.0

func (m *Model) ForceQuit() Action

ForceQuit returns an Action to force the tracker to quit immediately, without saving any changes.

func (*Model) History added in v0.6.0

func (m *Model) History() *HistoryModel

History returns the History view of the model, containing methods to manipulate the undo/redo history and saving recovery files.

func (*Model) Instrument

func (m *Model) Instrument() *InstrModel

Instrument returns the Instrument view of the model, containing methods to manipulate the instruments.

func (*Model) MIDI added in v0.5.0

func (m *Model) MIDI() *MIDIModel

func (*Model) Note

func (m *Model) Note() *NoteModel

Note returns the Note view of the model, containing methods to manipulate the note data.

func (*Model) Order added in v0.4.0

func (m *Model) Order() *OrderModel

Order returns the Order view of the model, containing methods to manipulate the pattern order list.

func (*Model) Params added in v0.4.0

func (m *Model) Params() *ParamModel

Params returns the Param view of the Model, containing methods to manipulate the parameters.

func (*Model) Play added in v0.6.0

func (m *Model) Play() *Play

func (*Model) Preset added in v0.6.0

func (m *Model) Preset() *PresetModel

Preset returns a PresetModel, a view of the model used to manipulate instrument presets.

func (*Model) ProcessMsg added in v0.5.0

func (m *Model) ProcessMsg(msg MsgToModel)

func (*Model) Quitted added in v0.4.0

func (m *Model) Quitted() bool

func (*Model) RequestQuit added in v0.5.0

func (m *Model) RequestQuit() Action

RequestQuit asks the tracker to quit, showing a dialog if there are unsaved changes.

func (*Model) Scope added in v0.6.0

func (m *Model) Scope() *ScopeModel

Scope returns the ScopeModel view of the Model, used for oscilloscope control.

func (*Model) ShowLicense added in v0.5.0

func (m *Model) ShowLicense() Action

ShowLicense returns an Action to show the software license dialog.

func (*Model) Song

func (m *Model) Song() *SongModel

Song returns the Song view of the model, containing methods to manipulate the song.

func (*Model) Spectrum added in v0.6.0

func (m *Model) Spectrum() *SpectrumModel

Spectrum returns a SpectrumModel to access spectrum analyzer data and settings.

func (*Model) Track

func (m *Model) Track() *TrackModel

Track returns the Track view of the model, containing methods to manipulate the tracks.

func (*Model) Unit

func (m *Model) Unit() *UnitModel

Unit returns the Unit view of the model, containing methods to manipulate the units.

type MsgToDetector added in v0.5.0

type MsgToDetector struct {
	Reset bool
	Data  any // TODO: consider using a sum type here, for a bit more type safety. See: https://www.jerf.org/iri/post/2917/

	WeightingType    WeightingType
	HasWeightingType bool
	Oversampling     bool
	HasOversampling  bool
}

MsgToDetector is a message sent to the detector. It contains a reset flag and a data field. The data field can contain many different messages, including *sointu.AudioBuffer for the detector to analyze and func() which gets executed in the detector goroutine.

type MsgToGUI added in v0.5.0

type MsgToGUI struct {
	Kind  GUIMessageKind
	Param int
}

MsgToGUI is a message sent to the GUI, as GUI stores part of the state. In particular, GUI knows about where lists / tables are centered, so the kind of messages we send to the GUI are about centering the view on a specific row, or ensuring that the cursor is visible.

type MsgToModel added in v0.5.0

type MsgToModel struct {
	HasPanicPlayerStatus bool
	Panic                bool
	PlayerStatus         PlayerStatus

	HasDetectorResult bool
	DetectorResult    DetectorResult

	TriggerChannel int  // note: 0 = no trigger, 1 = first channel, etc.
	Reset          bool // true: playing started, so should reset the detector and the scope cursor

	Data any // TODO: consider using a sum type here, for a bit more type safety. See: https://www.jerf.org/iri/post/2917/
}

MsgToModel is a message sent to the model. The most often sent data (Panic, SongPosition, VoiceLevels and DetectorResult) are not boxed to avoid allocations. All the infrequently passed messages can be boxed & cast to any; casting pointer types to any is cheap (does not allocate).

type MsgToSpecAn added in v0.6.0

type MsgToSpecAn struct {
	SpecSettings specAnSettings
	HasSettings  bool
	Data         any
}

type MutableListData added in v0.4.0

type MutableListData interface {
	Change(kind string, severity ChangeSeverity) func()
	Cancel()
	Move(r Range, delta int) (ok bool)
	Delete(r Range) (ok bool)
	Marshal(r Range) ([]byte, error)
	Unmarshal([]byte) (r Range, err error)
}

type NoteEvent added in v0.5.0

type NoteEvent struct {
	Timestamp int64 // in frames, relative to whatever clock the source is using
	On        bool
	Channel   int // which track or instrument is triggered, depending on IsTrack
	Note      byte
	IsTrack   bool // true if "Channel" means track number, false if it means instrument number
	Source    any
	// contains filtered or unexported fields
}

NoteEvent describes triggering or releasing of a note. The timestamps are in frames, and relative to the clock of the event source. Different sources can use different clocks. Player tries to adjust the timestamps so that each note events would fall inside the current processing block, by maintaining an estimate of the delta from the source clock to the player clock.

type NoteEventList added in v0.5.0

type NoteEventList []NoteEvent

type NoteModel added in v0.6.0

type NoteModel Model

func (*NoteModel) AddOctave added in v0.6.0

func (m *NoteModel) AddOctave() Action

AddOctave returns an Action for adding an octave to the selected notes.

func (*NoteModel) AddSemitone added in v0.6.0

func (m *NoteModel) AddSemitone() Action

AddSemiTone returns an Action for adding a semitone to the selected notes.

func (*NoteModel) At added in v0.6.0

func (m *NoteModel) At(p Point) byte

At returns the note value at the given point.

func (*NoteModel) Cursor added in v0.6.0

func (m *NoteModel) Cursor() Point

func (*NoteModel) Cursor2 added in v0.6.0

func (m *NoteModel) Cursor2() Point

func (*NoteModel) Height added in v0.6.0

func (v *NoteModel) Height() int

func (*NoteModel) Input added in v0.6.0

func (v *NoteModel) Input(note byte) NoteEvent

Input fills the current selection of the note table with a given note value, returning a NoteEvent telling which note should be played.

func (*NoteModel) InputNibble added in v0.6.0

func (v *NoteModel) InputNibble(nibble byte) NoteEvent

InputNibble fills the nibbles of current selection of the note table with a given nibble value. LowNibble tells whether the user is currently editing the low or high nibbles. It returns a NoteEvent telling which note should be played.

func (*NoteModel) LowNibble added in v0.6.0

func (m *NoteModel) LowNibble() bool

LowNibble returns whether the user is currently editing the low nibble of the note value when editing an effect track.

func (*NoteModel) MoveCursor added in v0.6.0

func (v *NoteModel) MoveCursor(dx, dy int) (ok bool)

func (*NoteModel) NoteOff added in v0.6.0

func (m *NoteModel) NoteOff() Action

NoteOff returns an Action to set the selected notes to Note Off (0).

func (*NoteModel) Octave added in v0.6.0

func (m *NoteModel) Octave() Int

Octave returns an Int controlling the current octave for note input.

func (*NoteModel) RowList added in v0.6.0

func (m *NoteModel) RowList() List

RowList is a list of all the note rows, implementing ListData & MutableListData interfaces

func (*NoteModel) SetCursor added in v0.6.0

func (v *NoteModel) SetCursor(p Point)

func (*NoteModel) SetCursor2 added in v0.6.0

func (v *NoteModel) SetCursor2(p Point)

func (*NoteModel) SetCursorFloat added in v0.6.0

func (m *NoteModel) SetCursorFloat(x, y float32)

func (*NoteModel) SetValue added in v0.6.0

func (m *NoteModel) SetValue(p Point, val byte)

SetValue sets the note value at the given point.

func (*NoteModel) Step added in v0.6.0

func (m *NoteModel) Step() Int

Step returns an Int controlling how many note rows the cursor advances every time the user inputs a note.

func (*NoteModel) SubtractOctave added in v0.6.0

func (m *NoteModel) SubtractOctave() Action

SubtractOctave returns an Action for subtracting an octave from the selected notes.

func (*NoteModel) SubtractSemitone added in v0.6.0

func (m *NoteModel) SubtractSemitone() Action

SubtractSemitone returns an Action for subtracting a semitone from the selected notes.

func (*NoteModel) Table added in v0.6.0

func (v *NoteModel) Table() Table

Table returns a Table of all the note data.

func (*NoteModel) UniquePatterns added in v0.6.0

func (m *NoteModel) UniquePatterns() Bool

UniquePatterns returns a Bool controlling whether patterns are made unique when editing notes.

func (*NoteModel) Width added in v0.6.0

func (v *NoteModel) Width() int

type NullMIDIContext added in v0.5.0

type NullMIDIContext struct{}

NullMIDIContext is a mockup MIDIContext if you don't want to create a real one.

func (NullMIDIContext) Close added in v0.5.0

func (m NullMIDIContext) Close()

func (NullMIDIContext) Inputs added in v0.6.0

func (m NullMIDIContext) Inputs(yield func(input MIDIInputDevice) bool)

func (NullMIDIContext) Support added in v0.6.0

func (m NullMIDIContext) Support() MIDISupport

type NullPlayerProcessContext added in v0.5.0

type NullPlayerProcessContext struct{}

func (NullPlayerProcessContext) BPM added in v0.5.0

func (p NullPlayerProcessContext) BPM() (bpm float64, ok bool)

type OrderModel added in v0.6.0

type OrderModel Model

func (*OrderModel) AddRow added in v0.6.0

func (m *OrderModel) AddRow(before bool) Action

AddRow returns an Action that adds an order row before or after the current cursor row.

func (*OrderModel) Cursor added in v0.6.0

func (m *OrderModel) Cursor() Point

func (*OrderModel) Cursor2 added in v0.6.0

func (m *OrderModel) Cursor2() Point

func (*OrderModel) DeleteRow added in v0.6.0

func (m *OrderModel) DeleteRow(backwards bool) Action

DeleteRow returns an Action to delete the current row of in the pattern order list.

func (*OrderModel) Height added in v0.6.0

func (v *OrderModel) Height() int

func (*OrderModel) MoveCursor added in v0.6.0

func (v *OrderModel) MoveCursor(dx, dy int) (ok bool)

func (*OrderModel) PatternUnique added in v0.6.0

func (m *OrderModel) PatternUnique(track, pat int) bool

PatternUnique returns true if the given pattern in the given track is used only once in the pattern order list.

func (*OrderModel) RemoveUnusedPatterns added in v0.6.0

func (m *OrderModel) RemoveUnusedPatterns() Action

RemoveUnused returns an Action that removes all unused patterns from all tracks in the song, and updates the pattern orders accordingly.

func (*OrderModel) RowList added in v0.6.0

func (m *OrderModel) RowList() List

RowList returns a List of all the rows of the pattern order table.

func (*OrderModel) SetCursor added in v0.6.0

func (m *OrderModel) SetCursor(p Point)

func (*OrderModel) SetCursor2 added in v0.6.0

func (m *OrderModel) SetCursor2(p Point)

func (*OrderModel) SetValue added in v0.6.0

func (m *OrderModel) SetValue(p Point, val int)

func (*OrderModel) Table added in v0.6.0

func (v *OrderModel) Table() Table

Table returns a Table of all the pattern order data.

func (*OrderModel) Value added in v0.6.0

func (m *OrderModel) Value(p Point) int

func (*OrderModel) Width added in v0.6.0

func (v *OrderModel) Width() int

type PanicMsg added in v0.4.0

type PanicMsg struct {
	// contains filtered or unexported fields
}

Model implements the mutable state for the tracker program GUI.

Go does not have immutable slices, so there's no efficient way to guarantee accidental mutations in the song. But at least the value members are protected. It is owned by the GUI thread (goroutine), while the player is owned by by the audioprocessing thread. They communicate using the two channels

type ParamModel added in v0.6.0

type ParamModel Model

func (*ParamModel) ChooseSendSource added in v0.6.0

func (m *ParamModel) ChooseSendSource(id int) Action

func (*ParamModel) ChooseSendTarget added in v0.6.0

func (m *ParamModel) ChooseSendTarget(id int, port int) Action

func (*ParamModel) Columns added in v0.6.0

func (m *ParamModel) Columns() List

func (*ParamModel) Cursor added in v0.6.0

func (pt *ParamModel) Cursor() Point

func (*ParamModel) Cursor2 added in v0.6.0

func (pt *ParamModel) Cursor2() Point

func (*ParamModel) Height added in v0.6.0

func (pt *ParamModel) Height() int

func (*ParamModel) IsChoosingSendTarget added in v0.6.0

func (m *ParamModel) IsChoosingSendTarget() bool

func (*ParamModel) Item added in v0.6.0

func (pt *ParamModel) Item(p Point) Parameter

func (*ParamModel) MoveCursor added in v0.6.0

func (pt *ParamModel) MoveCursor(dx, dy int) (ok bool)

func (*ParamModel) RowWidth added in v0.6.0

func (pt *ParamModel) RowWidth(y int) int

func (*ParamModel) SetCursor added in v0.6.0

func (pt *ParamModel) SetCursor(p Point)

func (*ParamModel) SetCursor2 added in v0.6.0

func (pt *ParamModel) SetCursor2(p Point)

func (*ParamModel) Table added in v0.6.0

func (pt *ParamModel) Table() Table

func (*ParamModel) Width added in v0.6.0

func (pt *ParamModel) Width() int

func (*ParamModel) Wires added in v0.6.0

func (m *ParamModel) Wires(yield func(wire Wire) bool)

Wires returns the wires of the current instrument, telling which parameters are connected to which.

type ParamYieldFunc added in v0.4.0

type ParamYieldFunc func(param Parameter) bool

type Parameter

type Parameter struct {
	// contains filtered or unexported fields
}

Parameter represents a parameter of a unit. To support polymorphism without causing allocations, it has a vtable that defines the methods for the specific parameter type, to which all the method calls are delegated.

func (*Parameter) Add added in v0.5.0

func (p *Parameter) Add(delta int, snapToGrid bool) bool

func (*Parameter) Hint

func (p *Parameter) Hint() ParameterHint

func (*Parameter) Name

func (p *Parameter) Name() string

func (*Parameter) Neutral added in v0.5.0

func (p *Parameter) Neutral() int

func (*Parameter) Port added in v0.5.0

func (p *Parameter) Port() (int, bool)

func (*Parameter) Range added in v0.5.0

func (p *Parameter) Range() RangeInclusive

func (*Parameter) Reset added in v0.4.0

func (p *Parameter) Reset()

func (*Parameter) SetValue added in v0.5.0

func (p *Parameter) SetValue(value int) bool

func (*Parameter) Type

func (p *Parameter) Type() ParameterType

func (*Parameter) UnitID added in v0.5.0

func (p *Parameter) UnitID() int

func (*Parameter) Value

func (p *Parameter) Value() int

type ParameterHint added in v0.5.0

type ParameterHint struct {
	Label string
	Valid bool
}

type ParameterType

type ParameterType int
const (
	NoParameter ParameterType = iota
	IntegerParameter
	BoolParameter
	IDParameter
)

type PeakResult added in v0.5.0

type PeakResult [NumPeakTypes][2]Decibel

type PeakType added in v0.5.0

type PeakType int
const (
	PeakMomentary PeakType = iota
	PeakShortTerm
	PeakIntegrated
	NumPeakTypes
)

type Play added in v0.6.0

type Play Model

func (*Play) CPULoad added in v0.6.0

func (m *Play) CPULoad(buf []sointu.CPULoad) int

CPULoad fills the given buffer with CPU load information and returns the number of threads filled.

func (*Play) FromBeginning added in v0.6.0

func (m *Play) FromBeginning() Action

FromBeginning returns an Action to start playing the song from the beginning.

func (*Play) FromCurrentPos added in v0.6.0

func (m *Play) FromCurrentPos() Action

FromCurrentPos returns an Action to start playing the song from the current cursor position

func (*Play) FromLoopBeginning added in v0.6.0

func (m *Play) FromLoopBeginning() Action

FromLoopBeginning returns an Action to start playing from the beginning of the

func (*Play) FromSelected added in v0.6.0

func (m *Play) FromSelected() Action

FromSelected returns an Action to start playing and looping the currently selected patterns.

func (*Play) IsFollowing added in v0.6.0

func (m *Play) IsFollowing() Bool

IsFollowing returns a Bool to toggle whether user cursors follows the playback cursor.

func (*Play) IsLooping added in v0.6.0

func (m *Play) IsLooping() Bool

IsLooping returns a Bool to toggle whether looping is on or off.

func (*Play) IsRecording added in v0.6.0

func (m *Play) IsRecording() Bool

IsRecording returns a Bool to toggle whether recording is on or off.

func (*Play) Loop added in v0.6.0

func (m *Play) Loop() Loop

Loop returns the current Loop telling which part of the song is looped.

func (*Play) Multithreading added in v0.6.0

func (m *Play) Multithreading() Bool

func (*Play) Panicked added in v0.6.0

func (m *Play) Panicked() Bool

Panicked returns a Bool to toggle whether the synth is in panic mode or not.

func (*Play) Position added in v0.6.0

func (m *Play) Position() sointu.SongPos

Position returns the current play position as sointu.SongPos.

func (*Play) SongRow added in v0.6.0

func (m *Play) SongRow() int

SongRow returns the current order row being played.

func (*Play) Started added in v0.6.0

func (m *Play) Started() Bool

Started returns a Bool to toggle whether playback has started or not.

func (*Play) Stop added in v0.6.0

func (m *Play) Stop() Action

Stop returns an Action to stop playing the song.

func (*Play) SyntherIndex added in v0.6.0

func (m *Play) SyntherIndex() Int

SyntherIndex returns an Int representing the index of the currently selected synther.

func (*Play) TrackerHidden added in v0.6.0

func (m *Play) TrackerHidden() Bool

TrackerHidden returns a Bool controlling whether the tracker UI is hidden during playback (for example when recording).

type Player

type Player struct {
	// contains filtered or unexported fields
}

Player is the audio player for the tracker, run in a separate thread. It is controlled by messages from the model and MIDI messages via the context, typically from the VSTI host. The player sendTargets messages to the model via the playerMessages channel. The model sendTargets messages to the player via the modelMessages channel.

func NewPlayer

func NewPlayer(broker *Broker, synther sointu.Synther) *Player

func (*Player) EmitMIDIMsg added in v0.6.0

func (p *Player) EmitMIDIMsg(msg *MIDIMessage) bool

func (*Player) Process added in v0.2.0

func (p *Player) Process(buffer sointu.AudioBuffer, context PlayerProcessContext)

Process renders audio to the given buffer, trying to fill it completely. If the buffer is not filled, the synth is destroyed and an error is sent to the model. context tells the player which MIDI events happen during the current buffer. It is used to trigger and release notes during processing. The context is also used to get the current BPM from the host.

func (*Player) SendAlert added in v0.5.0

func (p *Player) SendAlert(name, message string, priority AlertPriority)

type PlayerProcessContext added in v0.2.0

type PlayerProcessContext interface {
	BPM() (bpm float64, ok bool)
}

PlayerProcessContext is the context given to the player when processing audio. Currently it is only used to get BPM from the VSTI host.

type PlayerStatus added in v0.5.0

type PlayerStatus struct {
	SongPos     sointu.SongPos         // the current position in the score
	VoiceLevels [vm.MAX_VOICES]float32 // a level that can be used to visualize the volume of each voice
	NumThreads  int
	CPULoad     [vm.MAX_THREADS]sointu.CPULoad // current CPU load of the player, used to adjust the render rate
}

PlayerStatus is the part of the player state that is communicated to the model, for different visualizations of what is happening in the player.

type Point added in v0.4.0

type Point struct {
	X, Y int
}

type PresetModel added in v0.6.0

type PresetModel Model

func (*PresetModel) BuiltinFilter added in v0.6.0

func (m *PresetModel) BuiltinFilter() Bool

BuiltinFilter return a Bool toggling whether to show the built-in presets in the preset search results.

func (*PresetModel) ClearSearch added in v0.6.0

func (m *PresetModel) ClearSearch() Action

ClearSearch returns an Action to clear the current preset search term(s).

func (*PresetModel) ConfirmDelete added in v0.6.0

func (m *PresetModel) ConfirmDelete() Action

DeleteUserPreset returns an Action to confirm the deletion of an user preset.

func (*PresetModel) Delete added in v0.6.0

func (m *PresetModel) Delete() Action

TryDeleteUserPreset returns an Action to display a dialog to confirm deletion of an user preset.

func (*PresetModel) Dir added in v0.6.0

func (m *PresetModel) Dir(i int) string

Dir returns the name of the directory at the given index in the preset directory list.

func (*PresetModel) DirList added in v0.6.0

func (m *PresetModel) DirList() List

PresetDirList return a List of all the different preset directories.

func (*PresetModel) NoGmDls added in v0.6.0

func (m *PresetModel) NoGmDls() Bool

NoGmDls returns a Bool toggling whether to show presets relying on gm.dls samples.

func (*PresetModel) Overwrite added in v0.6.0

func (m *PresetModel) Overwrite() Action

OverwriteUserPreset returns an Action to overwrite the current instrument as a user-defined preset.

func (*PresetModel) Save added in v0.6.0

func (m *PresetModel) Save() Action

Save returns an Action to save the current instrument as a user-defined preset. It will not overwrite existing presets, but rather show a dialog to confirm the overwrite.

func (*PresetModel) SearchResult added in v0.6.0

func (m *PresetModel) SearchResult(i int) (name string, dir string, user bool)

SearchResult returns the search result at the given index in the search result list.

func (*PresetModel) SearchResultList added in v0.6.0

func (m *PresetModel) SearchResultList() List

SearchResultList returns a List of the current preset search results.

func (*PresetModel) SearchTerm added in v0.6.0

func (m *PresetModel) SearchTerm() String

SearchTerm returns a String containing the search terms for finding the presets.

func (*PresetModel) UserFilter added in v0.6.0

func (m *PresetModel) UserFilter() Bool

UserPresetsFilter returns a Bool toggling whether to show the user defined presets.

type Rail added in v0.5.0

type Rail struct {
	PassThrough int
	Send        bool
	StackUse    sointu.StackUse
}

func (*Rail) StackAfter added in v0.5.0

func (s *Rail) StackAfter() int

type RailError added in v0.5.0

type RailError struct {
	InstrIndex, UnitIndex int
	Err                   error
}

func (*RailError) Error added in v0.5.0

func (e *RailError) Error() string

type Range added in v0.5.0

type Range struct{ Start, End int }

Range is used to represent a range [Start,End) of integers, excluding End

func Complement added in v0.5.0

func Complement(a Range) [2]Range

func MakeMoveRanges added in v0.5.0

func MakeMoveRanges(a Range, delta int) [4]Range

func MakeSetLength added in v0.5.0

func MakeSetLength(a Range, length int) []Range

MakeSetLength takes a range and a length, and returns a slice of ranges that can be used with VoiceSlice to expand or shrink the range to the given length, by either duplicating or removing elements. The function tries to duplicate elements so all elements are equally spaced, and tries to remove elements from the middle of the range.

func VoiceInsert added in v0.5.0

func VoiceInsert[T any, S ~[]T, P sointu.NumVoicerPointer[T]](orig S, index, length int, added ...T) (ret S, retRange Range, ok bool)

VoiceInsert tries adding the elements "added" to the slice "orig" at the voice index "index". Notice that index is the index into a virtual slice where each element is repeated by the number of voices it has. If the index is between elements, the new elements are added in between the old elements. If the addition would cause splitting of an element, we rather increase the number of voices the element has, but do not split it.

func VoiceRange added in v0.5.0

func VoiceRange[T any, S ~[]T, P sointu.NumVoicerPointer[T]](slice S, indexRange Range) (voiceRange Range)

func (Range) Intersect added in v0.5.0

func (r Range) Intersect(s Range) (ret Range)

func (Range) Len added in v0.5.0

func (r Range) Len() int

func (Range) Swaps added in v0.5.0

func (r Range) Swaps(delta int) iter.Seq2[int, int]

type RangeInclusive added in v0.6.0

type RangeInclusive struct{ Min, Max int }

RangeInclusive represents a range of integers [Min, Max], inclusive.

func (RangeInclusive) Clamp added in v0.6.0

func (r RangeInclusive) Clamp(value int) int

type Recording added in v0.3.0

type Recording struct {
	BPM                  float64 // vsts allow bpms as floats so for accurate reconstruction, keep it as float for recording
	Events               NoteEventList
	StartFrame, EndFrame int64
	State                RecordingState
}

func (*Recording) Finish added in v0.5.0

func (r *Recording) Finish(frame int64, frameDeltas map[any]int64)

func (*Recording) Record added in v0.5.0

func (r *Recording) Record(ev NoteEvent, frame int64)

func (*Recording) Score added in v0.4.0

func (recording *Recording) Score(patch sointu.Patch, rowsPerBeat, rowsPerPattern int) (sointu.Score, error)

type RecordingMsg added in v0.4.0

type RecordingMsg struct {
	// contains filtered or unexported fields
}

Model implements the mutable state for the tracker program GUI.

Go does not have immutable slices, so there's no efficient way to guarantee accidental mutations in the song. But at least the value members are protected. It is owned by the GUI thread (goroutine), while the player is owned by by the audioprocessing thread. They communicate using the two channels

type RecordingState added in v0.5.0

type RecordingState int
const (
	RecordingNone RecordingState = iota
	RecordingWaitingForNote
	RecordingStarted  // StartFrame is set, but EndFrame is not
	RecordingFinished // StartFrame and EndFrame are both set, recording is finished
)

type Rect added in v0.4.0

type Rect struct {
	TopLeft, BottomRight Point
}

func (*Rect) Contains added in v0.4.0

func (r *Rect) Contains(p Point) bool

func (*Rect) Height added in v0.4.0

func (r *Rect) Height() int

func (*Rect) Limit added in v0.4.0

func (r *Rect) Limit(width, height int)

func (*Rect) Width added in v0.4.0

func (r *Rect) Width() int

type RingBuffer added in v0.5.0

type RingBuffer[T any] struct {
	Buffer []T
	Cursor int
}

RingBuffer is a generic ring buffer with buffer and a cursor. It is used by the oscilloscope.

func (*RingBuffer[T]) WriteOnce added in v0.5.0

func (r *RingBuffer[T]) WriteOnce(values []T)

func (*RingBuffer[T]) WriteOnceSingle added in v0.5.0

func (r *RingBuffer[T]) WriteOnceSingle(value T)

func (*RingBuffer[T]) WriteWrap added in v0.5.0

func (r *RingBuffer[T]) WriteWrap(values []T)

func (*RingBuffer[T]) WriteWrapSingle added in v0.5.0

func (r *RingBuffer[T]) WriteWrapSingle(value T)

type RowsPerBeatMsg added in v0.4.0

type RowsPerBeatMsg struct {
	// contains filtered or unexported fields
}

Model implements the mutable state for the tracker program GUI.

Go does not have immutable slices, so there's no efficient way to guarantee accidental mutations in the song. But at least the value members are protected. It is owned by the GUI thread (goroutine), while the player is owned by by the audioprocessing thread. They communicate using the two channels

type ScopeModel added in v0.5.0

type ScopeModel Model

func (*ScopeModel) Envelope added in v0.6.0

func (s *ScopeModel) Envelope() (Envelope, bool)

func (*ScopeModel) LengthInBeats added in v0.5.0

func (m *ScopeModel) LengthInBeats() Int

LengthInBeats returns an Int for controlling the length of the oscilloscope buffer in beats.

func (*ScopeModel) Once added in v0.5.0

func (m *ScopeModel) Once() Bool

Once returns a Bool for controlling whether the oscilloscope should only trigger once.

func (*ScopeModel) TriggerChannel added in v0.5.0

func (m *ScopeModel) TriggerChannel() Int

TriggerChannel returns an Int for controlling the trigger channel of the oscilloscope. 0 = no trigger, 1 is the first channel etc.

func (*ScopeModel) Waveform added in v0.5.0

func (s *ScopeModel) Waveform() RingBuffer[[2]float32]

Waveform returns the oscilloscope waveform buffer.

func (*ScopeModel) Wrap added in v0.5.0

func (m *ScopeModel) Wrap() Bool

Wrap returns a Bool for controlling whether the oscilloscope should wrap the buffer when full.

type SongModel added in v0.6.0

type SongModel Model

func (*SongModel) BPM added in v0.6.0

func (m *SongModel) BPM() Int

BPM returns an Int representing the BPM of the current song.

func (*SongModel) ChangedSinceSave added in v0.6.0

func (m *SongModel) ChangedSinceSave() bool

ChangesSinceSave returns a Bool representing whether the current song has unsaved

func (*SongModel) Discard added in v0.6.0

func (m *SongModel) Discard() Action

Discard returns an Action to discard the current changes to the song when opening a song from disk or creating a new one.

func (*SongModel) Export added in v0.6.0

func (m *SongModel) Export() Action

Export returns an Action to show the wav export dialog.

func (*SongModel) ExportFloat added in v0.6.0

func (m *SongModel) ExportFloat() Action

ExportFloat returns an Action to start exporting the song as a wav file with 32-bit float samples.

func (*SongModel) ExportInt16 added in v0.6.0

func (m *SongModel) ExportInt16() Action

ExportInt16 returns an Action to start exporting the song as a wav file with 16-bit integer samples.

func (*SongModel) FilePath added in v0.6.0

func (m *SongModel) FilePath() String

FilePath returns a String representing the file path of the current song.

func (*SongModel) Length added in v0.6.0

func (m *SongModel) Length() Int

Length returns an Int representing the length of the current song, in number of order rows.

func (*SongModel) New added in v0.6.0

func (m *SongModel) New() Action

New returns an Action to create a new song.

func (*SongModel) Open added in v0.6.0

func (m *SongModel) Open() Action

Open returns an Action to open a song from the disk.

func (*SongModel) Read added in v0.6.0

func (m *SongModel) Read(r io.ReadCloser)

Read the song from a given io.ReadCloser, trying parsing it both as json and yaml.

func (*SongModel) RowsPerBeat added in v0.6.0

func (m *SongModel) RowsPerBeat() Int

RowsPerBeat returns an Int representing the number of rows per beat of the current song.

func (*SongModel) RowsPerPattern added in v0.6.0

func (m *SongModel) RowsPerPattern() Int

RowsPerPattern returns an Int representing the number of rows per pattern of the current song.

func (*SongModel) Save added in v0.6.0

func (m *SongModel) Save() Action

Save returns an Action to initiate saving the current song to disk.

func (*SongModel) SaveAs added in v0.6.0

func (m *SongModel) SaveAs() Action

SaveAs returns an Action to save the song to the disk with a new filename.

func (*SongModel) Write added in v0.6.0

func (m *SongModel) Write(w io.WriteCloser)

Save the song to a given io.ReadCloser. If the given argument is an os.File and has the file extension ".json", the song is marshaled as json; otherwise, it's marshaled as yaml.

func (*SongModel) WriteWav added in v0.6.0

func (m *SongModel) WriteWav(w io.WriteCloser, pcm16 bool)

WriteWav renders the song as a wav file and outputs it to the given io.WriteCloser. If the pcm16 is true, the sample format is 16-bit unsigned shorts, otherwise it's 32-bit floats.

type SpecChnMode added in v0.6.0

type SpecChnMode int
const (
	SpecChnModeSum      SpecChnMode = iota // calculate a single combined spectrum for both channels
	SpecChnModeSeparate                    // calculate separate spectrums for left and right channels
	NumSpecChnModes
)

type Spectrum added in v0.6.0

type Spectrum [2][]float32

type SpectrumModel added in v0.6.0

type SpectrumModel Model

func (*SpectrumModel) BiquadCoeffs added in v0.6.0

func (m *SpectrumModel) BiquadCoeffs() (coeffs BiquadCoeffs, ok bool)

BiquadCoeffs returns the biquad filter coefficients of the currently selected filter or belleq, to plot its frequency response on top of the spectrum.

func (*SpectrumModel) Channels added in v0.6.0

func (m *SpectrumModel) Channels() Int

Channels returns an Int to adjust the channel mode of the spectrum analyzer.

func (*SpectrumModel) Enabled added in v0.6.0

func (m *SpectrumModel) Enabled() Bool

Enabled returns a Bool to toggle whether the spectrum analyzer is enabled or not. If it is disabled, it will not process any audio data, saving CPU resources.

func (*SpectrumModel) Resolution added in v0.6.0

func (m *SpectrumModel) Resolution() Int

Resolution returns an Int to adjust the resolution of the spectrum analyzer.

func (*SpectrumModel) Result added in v0.6.0

func (m *SpectrumModel) Result() Spectrum

Result returns the latest spectrum analyzer result.

func (*SpectrumModel) Speed added in v0.6.0

func (m *SpectrumModel) Speed() Int

Speed returns an Int to adjust the smoothing speed of the spectrum analyzer.

type StartPlayMsg added in v0.4.0

type StartPlayMsg struct{ sointu.SongPos }

Model implements the mutable state for the tracker program GUI.

Go does not have immutable slices, so there's no efficient way to guarantee accidental mutations in the song. But at least the value members are protected. It is owned by the GUI thread (goroutine), while the player is owned by by the audioprocessing thread. They communicate using the two channels

type String added in v0.4.0

type String struct {
	// contains filtered or unexported fields
}

func MakeString added in v0.5.0

func MakeString(value StringValue) String

func (String) SetValue added in v0.5.0

func (v String) SetValue(value string) (changed bool)

func (String) Value added in v0.5.0

func (v String) Value() string

type StringOfer added in v0.6.0

type StringOfer interface {
	StringOf(value int) string
}

type StringValue added in v0.5.0

type StringValue interface {
	Value() string
	SetValue(string) (changed bool)
}

type Table added in v0.4.0

type Table struct {
	TableData
}

func (Table) Add added in v0.4.0

func (v Table) Add(delta int, largeStep bool)

func (Table) Clear added in v0.4.0

func (v Table) Clear()

func (Table) Copy added in v0.4.0

func (v Table) Copy() ([]byte, bool)

func (Table) Fill added in v0.4.0

func (v Table) Fill(value int)

func (Table) Paste added in v0.4.0

func (v Table) Paste(data []byte) bool

func (Table) Range added in v0.4.0

func (v Table) Range() (rect Rect)

func (Table) Set added in v0.5.0

func (v Table) Set(value byte)

func (Table) SetCursorX added in v0.4.0

func (v Table) SetCursorX(x int)

func (Table) SetCursorY added in v0.4.0

func (v Table) SetCursorY(y int)

type TableData added in v0.4.0

type TableData interface {
	Cursor() Point
	Cursor2() Point
	SetCursor(Point)
	SetCursor2(Point)
	Width() int
	Height() int
	MoveCursor(dx, dy int) (ok bool)
	// contains filtered or unexported methods
}

type TrackListItem added in v0.6.0

type TrackListItem struct {
	Title  string
	Effect bool
}

type TrackModel added in v0.6.0

type TrackModel Model

func (*TrackModel) Add added in v0.6.0

func (m *TrackModel) Add() Action

Add returns an Action to add a new track.

func (*TrackModel) Delete added in v0.6.0

func (m *TrackModel) Delete() Action

Delete returns an Action to delete the selected track(s).

func (*TrackModel) Effect added in v0.6.0

func (m *TrackModel) Effect() Bool

Effect returns a Bool to toggle whether the currently selected track is an effect track and should be displayed as hexadecimals or not.

func (*TrackModel) Item added in v0.6.0

func (m *TrackModel) Item(index int) TrackListItem

Title returns the title of the track for a given index.

func (*TrackModel) LinkInstrument added in v0.6.0

func (m *TrackModel) LinkInstrument() Bool

LinkInstrument returns a Bool controlling whether instruments and tracks are linked.

func (*TrackModel) List added in v0.6.0

func (m *TrackModel) List() List

List returns a List of all the tracks, implementing MutableListData

func (*TrackModel) Split added in v0.6.0

func (m *TrackModel) Split() Action

Split returns an Action to split the selected track into two tracks, distributing the voices as evenly as possible.

func (*TrackModel) Voices added in v0.6.0

func (m *TrackModel) Voices() Int

Voices returns an Int to adjust the number of voices for the currently selected track.

type UnitListItem added in v0.4.0

type UnitListItem struct {
	Type, Comment string
	Disabled      bool
	Signals       Rail
}

type UnitModel added in v0.6.0

type UnitModel Model

func (*UnitModel) Add added in v0.6.0

func (m *UnitModel) Add(before bool) Action

Add returns an Action to add a new unit. If the before parameter is true, then the new unit is added before the currently selected unit; otherwise, after.

func (*UnitModel) Clear added in v0.6.0

func (m *UnitModel) Clear() Action

Clear returns an Action to clear the currently selected unit(s) i.e. they are set as empty units, but are kept in the unit list.

func (*UnitModel) Comment added in v0.6.0

func (m *UnitModel) Comment() String

Comment returns a String representing the comment string of the current unit.

func (*UnitModel) Delete added in v0.6.0

func (m *UnitModel) Delete() Action

Delete returns an Action to delete the currently selected unit(s).

func (*UnitModel) Disabled added in v0.6.0

func (m *UnitModel) Disabled() Bool

Disabled returns a Bool controlling whether the currently selected unit(s) are disabled.

func (*UnitModel) Item added in v0.6.0

func (v *UnitModel) Item(index int) UnitListItem

Item returns information about the unit at the given index.

func (*UnitModel) List added in v0.6.0

func (m *UnitModel) List() List

List returns a List of all the units of the selected instrument, implementing ListData & MutableListData interfaces

func (*UnitModel) RailError added in v0.6.0

func (s *UnitModel) RailError() RailError

func (*UnitModel) RailWidth added in v0.6.0

func (s *UnitModel) RailWidth() int

func (*UnitModel) SearchResult added in v0.6.0

func (l *UnitModel) SearchResult(index int) (name string, ok bool)

SearchResult returns the unit search result at a given index.

func (*UnitModel) SearchResults added in v0.6.0

func (m *UnitModel) SearchResults() List

SearchResults returns a List of all the unit names matching the given search term.

func (*UnitModel) SearchTerm added in v0.6.0

func (m *UnitModel) SearchTerm() String

SearchTerm returns a String which is the search term user has typed when searching for units.

func (*UnitModel) Searching added in v0.6.0

func (m *UnitModel) Searching() Bool

Searching returns a Bool telling whether the user is currently searching for a unit (should the search resultsbe displayed).

func (*UnitModel) SetType added in v0.6.0

func (m *UnitModel) SetType(t string)

SetType sets the type of the currently selected unit.

func (*UnitModel) Type added in v0.6.0

func (m *UnitModel) Type() string

Type returns the type of the currently selected unit.

type WeightingType added in v0.5.0

type WeightingType int
const (
	KWeighting WeightingType = iota
	AWeighting
	CWeighting
	NoWeighting
	NumWeightingTypes
)

type Wire added in v0.5.0

type Wire struct {
	From      int
	FromSet   bool
	To        Point
	ToSet     bool
	Hint      string
	Highlight bool
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL