mirror of
https://github.com/vsariola/sointu.git
synced 2025-11-13 13:22:51 -05:00
drafting
This commit is contained in:
parent
bdd729efc1
commit
f80e71d2ec
@ -34,7 +34,7 @@ func NewInstrumentPresets(m *tracker.Model) *InstrumentPresets {
|
|||||||
builtinPresetsBtn: new(Clickable),
|
builtinPresetsBtn: new(Clickable),
|
||||||
dirBtn: new(Clickable),
|
dirBtn: new(Clickable),
|
||||||
dirList: NewDragList(m.PresetDirList().List(), layout.Vertical),
|
dirList: NewDragList(m.PresetDirList().List(), layout.Vertical),
|
||||||
resultList: NewDragList(m.PresetDirList().List(), layout.Vertical),
|
resultList: NewDragList(m.PresetResultList().List(), layout.Vertical),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,12 +48,25 @@ func (ip *InstrumentPresets) layout(gtx C) D {
|
|||||||
return Label(tr.Theme, &tr.Theme.Dialog.Text, tr.Model.PresetDirList().Value(i)).Layout(gtx)
|
return Label(tr.Theme, &tr.Theme.Dialog.Text, tr.Model.PresetDirList().Value(i)).Layout(gtx)
|
||||||
}
|
}
|
||||||
dirs := func(gtx C) D {
|
dirs := func(gtx C) D {
|
||||||
return FilledDragList(tr.Theme, ip.dirList).Layout(gtx, dirElem, nil)
|
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(140), gtx.Constraints.Max.Y))
|
||||||
|
style := FilledDragList(tr.Theme, ip.dirList)
|
||||||
|
dims := style.Layout(gtx, dirElem, nil)
|
||||||
|
style.LayoutScrollBar(gtx)
|
||||||
|
return dims
|
||||||
|
}
|
||||||
|
dirSurface := func(gtx C) D {
|
||||||
|
return Surface{Gray: 30, Focus: tr.PatchPanel.TreeFocused(gtx)}.Layout(gtx, dirs)
|
||||||
|
}
|
||||||
|
resultElem := func(gtx C, i int) D {
|
||||||
|
return Label(tr.Theme, &tr.Theme.Dialog.Text, tr.Model.PresetResultList().Value(i)).Layout(gtx)
|
||||||
|
}
|
||||||
|
results := func(gtx C) D {
|
||||||
|
return FilledDragList(tr.Theme, ip.resultList).Layout(gtx, resultElem, nil)
|
||||||
}
|
}
|
||||||
bottom := func(gtx C) D {
|
bottom := func(gtx C) D {
|
||||||
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||||
layout.Rigid(dirs),
|
layout.Rigid(dirSurface),
|
||||||
layout.Rigid(dirs),
|
layout.Flexed(1, results),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// layout
|
// layout
|
||||||
|
|||||||
@ -138,9 +138,6 @@ func MakeInstrumentTools(m *tracker.Model) InstrumentTools {
|
|||||||
shrinkHint: makeHint("Shrink", " (%s)", "InstrEnlargedToggle"),
|
shrinkHint: makeHint("Shrink", " (%s)", "InstrEnlargedToggle"),
|
||||||
addInstrumentHint: makeHint("Add\ninstrument", "\n(%s)", "AddInstrument"),
|
addInstrumentHint: makeHint("Add\ninstrument", "\n(%s)", "AddInstrument"),
|
||||||
}
|
}
|
||||||
for index, name := range m.IterateInstrumentPresets {
|
|
||||||
ret.presetMenuItems = append(ret.presetMenuItems, MenuItem(m.LoadPreset(index), name, "", icons.ImageAudiotrack))
|
|
||||||
}
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -85,6 +85,9 @@ type (
|
|||||||
broker *Broker
|
broker *Broker
|
||||||
|
|
||||||
MIDI MIDIContext
|
MIDI MIDIContext
|
||||||
|
|
||||||
|
presets PresetSlice
|
||||||
|
presetIndex int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cursor identifies a row and a track in a song score.
|
// Cursor identifies a row and a track in a song score.
|
||||||
@ -202,6 +205,8 @@ func NewModel(broker *Broker, synthers []sointu.Synther, midiContext MIDIContext
|
|||||||
TrySend(broker.ToPlayer, any(m.d.Song.Copy())) // we should be non-blocking in the constructor
|
TrySend(broker.ToPlayer, any(m.d.Song.Copy())) // we should be non-blocking in the constructor
|
||||||
m.signalAnalyzer = NewScopeModel(broker, m.d.Song.BPM)
|
m.signalAnalyzer = NewScopeModel(broker, m.d.Song.BPM)
|
||||||
m.updateDeriveData(SongChange)
|
m.updateDeriveData(SongChange)
|
||||||
|
m.updateDerivedPresetSearch()
|
||||||
|
m.loadPresets()
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -50,6 +50,9 @@ func (s *modelFuzzState) Iterate(yield func(string, func(p string, t *testing.T)
|
|||||||
s.IterateList("OrderRows", s.model.OrderRows().List(), yield, seed)
|
s.IterateList("OrderRows", s.model.OrderRows().List(), yield, seed)
|
||||||
s.IterateList("NoteRows", s.model.NoteRows().List(), yield, seed)
|
s.IterateList("NoteRows", s.model.NoteRows().List(), yield, seed)
|
||||||
s.IterateList("UnitSearchResults", s.model.SearchResults().List(), yield, seed)
|
s.IterateList("UnitSearchResults", s.model.SearchResults().List(), yield, seed)
|
||||||
|
s.IterateList("PresetDirs", s.model.PresetDirList().List(), yield, seed)
|
||||||
|
s.IterateList("PresetResults", s.model.PresetResultList().List(), yield, seed)
|
||||||
|
// Bools
|
||||||
s.IterateBool("Panic", s.model.Panic(), yield, seed)
|
s.IterateBool("Panic", s.model.Panic(), yield, seed)
|
||||||
s.IterateBool("Recording", s.model.IsRecording(), yield, seed)
|
s.IterateBool("Recording", s.model.IsRecording(), yield, seed)
|
||||||
s.IterateBool("Playing", s.model.Playing(), yield, seed)
|
s.IterateBool("Playing", s.model.Playing(), yield, seed)
|
||||||
@ -87,8 +90,6 @@ func (s *modelFuzzState) Iterate(yield func(string, func(p string, t *testing.T)
|
|||||||
s.IterateAction("DeleteOrderRowBackward", s.model.DeleteOrderRow(true), yield, seed)
|
s.IterateAction("DeleteOrderRowBackward", s.model.DeleteOrderRow(true), yield, seed)
|
||||||
s.IterateAction("SplitInstrument", s.model.SplitInstrument(), yield, seed)
|
s.IterateAction("SplitInstrument", s.model.SplitInstrument(), yield, seed)
|
||||||
s.IterateAction("SplitTrack", s.model.SplitTrack(), yield, seed)
|
s.IterateAction("SplitTrack", s.model.SplitTrack(), yield, seed)
|
||||||
// just test loading one of the presets
|
|
||||||
s.IterateAction("LoadPreset", s.model.LoadPreset(seed%tracker.NumPresets()), yield, seed)
|
|
||||||
// Tables
|
// Tables
|
||||||
s.IterateTable("Order", s.model.Order().Table(), yield, seed)
|
s.IterateTable("Order", s.model.Order().Table(), yield, seed)
|
||||||
s.IterateTable("Notes", s.model.Notes().Table(), yield, seed)
|
s.IterateTable("Notes", s.model.Notes().Table(), yield, seed)
|
||||||
|
|||||||
@ -17,6 +17,9 @@ import (
|
|||||||
//go:generate go run generate/gmdls_entries.go
|
//go:generate go run generate/gmdls_entries.go
|
||||||
//go:generate go run generate/clean_presets.go
|
//go:generate go run generate/clean_presets.go
|
||||||
|
|
||||||
|
//go:embed presets/*
|
||||||
|
var instrumentPresetFS embed.FS
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// GmDlsEntry is a single sample entry from the gm.dls file
|
// GmDlsEntry is a single sample entry from the gm.dls file
|
||||||
GmDlsEntry struct {
|
GmDlsEntry struct {
|
||||||
@ -27,6 +30,15 @@ type (
|
|||||||
Name string // sample Name
|
Name string // sample Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Preset struct {
|
||||||
|
Directory string
|
||||||
|
User bool
|
||||||
|
NeedsGmDls bool
|
||||||
|
Instr sointu.Instrument
|
||||||
|
}
|
||||||
|
|
||||||
|
PresetSlice []Preset
|
||||||
|
|
||||||
InstrumentPresetYieldFunc func(index int, item string) (ok bool)
|
InstrumentPresetYieldFunc func(index int, item string) (ok bool)
|
||||||
LoadPreset struct {
|
LoadPreset struct {
|
||||||
Index int
|
Index int
|
||||||
@ -41,13 +53,15 @@ type (
|
|||||||
PresetKind Model
|
PresetKind Model
|
||||||
ClearPresetSearch Model
|
ClearPresetSearch Model
|
||||||
PresetDirList Model
|
PresetDirList Model
|
||||||
|
PresetResultList Model
|
||||||
|
|
||||||
derivedPresetSearch struct {
|
derivedPresetSearch struct {
|
||||||
dirIndex int
|
dirIndex int
|
||||||
noGmDls bool
|
noGmDls bool
|
||||||
kind PresetKindEnum
|
kind PresetKindEnum
|
||||||
|
searchStrings []string
|
||||||
dirs []string
|
dirs []string
|
||||||
results []int
|
results []Preset
|
||||||
}
|
}
|
||||||
|
|
||||||
PresetKindEnum int
|
PresetKindEnum int
|
||||||
@ -62,15 +76,15 @@ const (
|
|||||||
func (m *Model) updateDerivedPresetSearch() {
|
func (m *Model) updateDerivedPresetSearch() {
|
||||||
// parse filters from the search string. in: dir, gmdls: yes/no, kind: builtin/user/all
|
// parse filters from the search string. in: dir, gmdls: yes/no, kind: builtin/user/all
|
||||||
search := strings.TrimSpace(m.d.PresetSearchString)
|
search := strings.TrimSpace(m.d.PresetSearchString)
|
||||||
lower := strings.ToLower(search)
|
parts := strings.Fields(search)
|
||||||
parts := strings.Fields(lower)
|
|
||||||
// parse parts to see if they contain :
|
// parse parts to see if they contain :
|
||||||
m.derived.presetSearch.dirs = []string{"All"}
|
m.derived.presetSearch.dirIndex = 0
|
||||||
m.derived.presetSearch.noGmDls = false
|
m.derived.presetSearch.noGmDls = false
|
||||||
m.derived.presetSearch.kind = AllPresets
|
m.derived.presetSearch.kind = AllPresets
|
||||||
|
m.derived.presetSearch.searchStrings = m.derived.presetSearch.searchStrings[:0]
|
||||||
for _, part := range parts {
|
for _, part := range parts {
|
||||||
if strings.HasPrefix(part, "d:") && len(part) > 3 {
|
if strings.HasPrefix(part, "d:") && len(part) > 2 {
|
||||||
dir := strings.TrimSpace(part[3:])
|
dir := strings.TrimSpace(part[2:])
|
||||||
ind := slices.IndexFunc(m.derived.presetSearch.dirs, func(c string) bool { return c == dir })
|
ind := slices.IndexFunc(m.derived.presetSearch.dirs, func(c string) bool { return c == dir })
|
||||||
m.derived.presetSearch.dirIndex = max(ind, 0)
|
m.derived.presetSearch.dirIndex = max(ind, 0)
|
||||||
} else if strings.HasPrefix(part, "g:n") {
|
} else if strings.HasPrefix(part, "g:n") {
|
||||||
@ -83,8 +97,100 @@ func (m *Model) updateDerivedPresetSearch() {
|
|||||||
case "u":
|
case "u":
|
||||||
m.derived.presetSearch.kind = UserPresets
|
m.derived.presetSearch.kind = UserPresets
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
m.derived.presetSearch.searchStrings = append(m.derived.presetSearch.searchStrings, strings.ToLower(part))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// update results
|
||||||
|
m.derived.presetSearch.results = m.derived.presetSearch.results[:0]
|
||||||
|
for _, p := range m.presets {
|
||||||
|
if m.derived.presetSearch.kind == BuiltinPresets && p.User {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if m.derived.presetSearch.kind == UserPresets && !p.User {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if m.derived.presetSearch.dirIndex > 0 && m.derived.presetSearch.dirIndex < len(m.derived.presetSearch.dirs) && p.Directory != m.derived.presetSearch.dirs[m.derived.presetSearch.dirIndex] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if m.derived.presetSearch.noGmDls && p.NeedsGmDls {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(m.derived.presetSearch.searchStrings) == 0 {
|
||||||
|
goto found
|
||||||
|
}
|
||||||
|
for _, s := range m.derived.presetSearch.searchStrings {
|
||||||
|
if strings.Contains(strings.ToLower(p.Instr.Name), s) {
|
||||||
|
goto found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
found:
|
||||||
|
m.derived.presetSearch.results = append(m.derived.presetSearch.results, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Model) loadPresets() {
|
||||||
|
m.presets = nil
|
||||||
|
m.loadPresetsFromFs(instrumentPresetFS, false)
|
||||||
|
if configDir, err := os.UserConfigDir(); err == nil {
|
||||||
|
userPresets := filepath.Join(configDir, "sointu", "presets")
|
||||||
|
m.loadPresetsFromFs(os.DirFS(userPresets), true)
|
||||||
|
}
|
||||||
|
sort.Sort(m.presets)
|
||||||
|
seenDir := make(map[string]bool)
|
||||||
|
for _, p := range m.presets {
|
||||||
|
seenDir[p.Directory] = true
|
||||||
|
}
|
||||||
|
dirs := make([]string, 0, len(seenDir))
|
||||||
|
for k := range seenDir {
|
||||||
|
dirs = append(dirs, k)
|
||||||
|
}
|
||||||
|
sort.Strings(dirs)
|
||||||
|
m.derived.presetSearch.dirs = make([]string, 0, len(dirs)+1)
|
||||||
|
m.derived.presetSearch.dirs = append(m.derived.presetSearch.dirs, "---")
|
||||||
|
m.derived.presetSearch.dirs = append(m.derived.presetSearch.dirs, dirs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Model) loadPresetsFromFs(fsys fs.FS, userDefined bool) {
|
||||||
|
fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if d.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
data, err := fs.ReadFile(instrumentPresetFS, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var instr sointu.Instrument
|
||||||
|
if yaml.UnmarshalStrict(data, &instr) == nil {
|
||||||
|
noExt := path[:len(path)-len(filepath.Ext(path))]
|
||||||
|
splitted := splitPath(noExt)
|
||||||
|
splitted = splitted[1:] // remove "presets" from the path
|
||||||
|
instr.Name = splitted[len(splitted)-1]
|
||||||
|
preset := Preset{
|
||||||
|
Directory: strings.Join(splitted[:len(splitted)-1], "/"),
|
||||||
|
User: userDefined,
|
||||||
|
Instr: instr,
|
||||||
|
NeedsGmDls: checkNeedsGmDls(instr),
|
||||||
|
}
|
||||||
|
m.presets = append(m.presets, preset)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkNeedsGmDls(instr sointu.Instrument) bool {
|
||||||
|
for _, u := range instr.Units {
|
||||||
|
if u.Type == "oscillator" {
|
||||||
|
if u.Parameters["type"] == sointu.Sample {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) PresetSearchString() String { return MakeString((*PresetSearchString)(m)) }
|
func (m *Model) PresetSearchString() String { return MakeString((*PresetSearchString)(m)) }
|
||||||
@ -185,11 +291,45 @@ func (m *PresetDirList) SetSelected(i int) {
|
|||||||
}
|
}
|
||||||
m.d.PresetSearchString = removeFilters(m.d.PresetSearchString, "d:")
|
m.d.PresetSearchString = removeFilters(m.d.PresetSearchString, "d:")
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
m.d.PresetSearchString = "d: " + m.derived.presetSearch.dirs[i] + " " + m.d.PresetSearchString
|
m.d.PresetSearchString = "d:" + m.derived.presetSearch.dirs[i] + " " + m.d.PresetSearchString
|
||||||
}
|
}
|
||||||
(*Model)(m).updateDerivedPresetSearch()
|
(*Model)(m).updateDerivedPresetSearch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Model) PresetResultList() *PresetResultList { return (*PresetResultList)(m) }
|
||||||
|
func (v *PresetResultList) List() List { return List{v} }
|
||||||
|
func (m *PresetResultList) Count() int { return len(m.derived.presetSearch.results) }
|
||||||
|
func (m *PresetResultList) Selected() int {
|
||||||
|
return min(max(m.presetIndex, 0), len(m.derived.presetSearch.results)-1)
|
||||||
|
}
|
||||||
|
func (m *PresetResultList) Selected2() int { return m.Selected() }
|
||||||
|
func (m *PresetResultList) SetSelected2(i int) {}
|
||||||
|
func (m *PresetResultList) Value(i int) string {
|
||||||
|
if i < 0 || i >= len(m.derived.presetSearch.results) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return m.derived.presetSearch.results[i].Instr.Name
|
||||||
|
}
|
||||||
|
func (m *PresetResultList) SetSelected(i int) {
|
||||||
|
i = min(max(i, 0), len(m.derived.presetSearch.results)-1)
|
||||||
|
if i < 0 || i >= len(m.derived.presetSearch.results) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.presetIndex = i
|
||||||
|
defer (*Model)(m).change("LoadPreset", PatchChange, MinorChange)()
|
||||||
|
if m.d.InstrIndex < 0 {
|
||||||
|
m.d.InstrIndex = 0
|
||||||
|
}
|
||||||
|
m.d.InstrIndex2 = m.d.InstrIndex
|
||||||
|
for m.d.InstrIndex >= len(m.d.Song.Patch) {
|
||||||
|
m.d.Song.Patch = append(m.d.Song.Patch, defaultInstrument.Copy())
|
||||||
|
}
|
||||||
|
newInstr := m.derived.presetSearch.results[i].Instr.Copy()
|
||||||
|
newInstr.NumVoices = clamp(m.d.Song.Patch[m.d.InstrIndex].NumVoices, 1, vm.MAX_VOICES)
|
||||||
|
(*Model)(m).assignUnitIDs(newInstr.Units)
|
||||||
|
m.d.Song.Patch[m.d.InstrIndex] = newInstr
|
||||||
|
}
|
||||||
|
|
||||||
func removeFilters(str string, prefix string) string {
|
func removeFilters(str string, prefix string) string {
|
||||||
parts := strings.Fields(str)
|
parts := strings.Fields(str)
|
||||||
newParts := make([]string, 0, len(parts))
|
newParts := make([]string, 0, len(parts))
|
||||||
@ -297,97 +437,6 @@ type delayPreset struct {
|
|||||||
varArgs []int
|
varArgs []int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) IterateInstrumentPresets(yield InstrumentPresetYieldFunc) {
|
|
||||||
for index, instr := range instrumentPresets {
|
|
||||||
if !yield(index, instr.Name) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NumPresets() int {
|
|
||||||
return len(instrumentPresets)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadPreset loads a preset from the list of instrument presets. The index
|
|
||||||
// should be within the range of 0 to NumPresets()-1.
|
|
||||||
|
|
||||||
func (m *Model) LoadPreset(index int) Action {
|
|
||||||
return MakeEnabledAction(LoadPreset{Index: index, Model: m})
|
|
||||||
}
|
|
||||||
func (m LoadPreset) Do() {
|
|
||||||
defer m.change("LoadPreset", PatchChange, MajorChange)()
|
|
||||||
if m.d.InstrIndex < 0 {
|
|
||||||
m.d.InstrIndex = 0
|
|
||||||
}
|
|
||||||
m.d.InstrIndex2 = m.d.InstrIndex
|
|
||||||
for m.d.InstrIndex >= len(m.d.Song.Patch) {
|
|
||||||
m.d.Song.Patch = append(m.d.Song.Patch, defaultInstrument.Copy())
|
|
||||||
}
|
|
||||||
newInstr := instrumentPresets[m.Index].Copy()
|
|
||||||
newInstr.NumVoices = clamp(m.d.Song.Patch[m.d.InstrIndex].NumVoices, 1, vm.MAX_VOICES)
|
|
||||||
m.Model.assignUnitIDs(newInstr.Units)
|
|
||||||
m.d.Song.Patch[m.d.InstrIndex] = newInstr
|
|
||||||
}
|
|
||||||
|
|
||||||
type instrumentPresetsSlice []sointu.Instrument
|
|
||||||
|
|
||||||
//go:embed presets/*
|
|
||||||
var instrumentPresetFS embed.FS
|
|
||||||
var instrumentPresets instrumentPresetsSlice
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
fs.WalkDir(instrumentPresetFS, ".", func(path string, d fs.DirEntry, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if d.IsDir() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
data, err := fs.ReadFile(instrumentPresetFS, path)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var instr sointu.Instrument
|
|
||||||
if yaml.UnmarshalStrict(data, &instr) == nil {
|
|
||||||
noExt := path[:len(path)-len(filepath.Ext(path))]
|
|
||||||
splitted := splitPath(noExt)
|
|
||||||
splitted = splitted[1:] // remove "presets" from the path
|
|
||||||
instr.Name = strings.Join(splitted, " ")
|
|
||||||
instrumentPresets = append(instrumentPresets, instr)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if configDir, err := os.UserConfigDir(); err == nil {
|
|
||||||
userPresets := filepath.Join(configDir, "sointu", "presets")
|
|
||||||
filepath.WalkDir(userPresets, func(path string, d fs.DirEntry, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if d.IsDir() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
data, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var instr sointu.Instrument
|
|
||||||
if yaml.Unmarshal(data, &instr) == nil {
|
|
||||||
if len(userPresets)+1 > len(path) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
subPath := path[len(userPresets)+1:]
|
|
||||||
noExt := subPath[:len(subPath)-len(filepath.Ext(subPath))]
|
|
||||||
splitted := splitPath(noExt)
|
|
||||||
instr.Name = strings.Join(splitted, " ")
|
|
||||||
instrumentPresets = append(instrumentPresets, instr)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
sort.Sort(instrumentPresets)
|
|
||||||
}
|
|
||||||
|
|
||||||
func splitPath(path string) []string {
|
func splitPath(path string) []string {
|
||||||
subPath := path
|
subPath := path
|
||||||
var result []string
|
var result []string
|
||||||
@ -413,6 +462,14 @@ func splitPath(path string) []string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p instrumentPresetsSlice) Len() int { return len(p) }
|
func (p PresetSlice) Len() int { return len(p) }
|
||||||
func (p instrumentPresetsSlice) Less(i, j int) bool { return p[i].Name < p[j].Name }
|
func (p PresetSlice) Less(i, j int) bool {
|
||||||
func (p instrumentPresetsSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
if p[i].Directory == p[j].Directory {
|
||||||
|
if p[i].Instr.Name == p[j].Instr.Name {
|
||||||
|
return p[i].User && !p[j].User
|
||||||
|
}
|
||||||
|
return p[i].Instr.Name < p[j].Instr.Name
|
||||||
|
}
|
||||||
|
return p[i].Directory < p[j].Directory
|
||||||
|
}
|
||||||
|
func (p PresetSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||||
|
|||||||
Reference in New Issue
Block a user