diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d96c28..7cdcded 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -105,6 +105,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ([#156][i156]) ### Changed +- When saving instrument to a file, the instrument name is not saved to the name + field, as Sointu will anyway use the filename as the instrument's name when it + is loaded. - Native version of the tracker/VSTi was removed. Instead, you can change between the two versions of the synth on the fly, by clicking on the "Synth" option under the CPU group in the song panel ([#200][i200]) diff --git a/tracker/files.go b/tracker/files.go index 819053b..8eb6347 100644 --- a/tracker/files.go +++ b/tracker/files.go @@ -114,13 +114,17 @@ func (m *Model) SaveInstrument(w io.WriteCloser) bool { var extension = filepath.Ext(path) var contents []byte var err error + instr := m.d.Song.Patch[m.d.InstrIndex] + if _, ok := w.(*os.File); ok { + instr.Name = "" // don't save the instrument name to a file; we'll replace the instruments name with the filename when loading from a file + } if extension == ".json" { - contents, err = json.Marshal(m.d.Song.Patch[m.d.InstrIndex]) + contents, err = json.Marshal(instr) } else { - contents, err = yaml.Marshal(m.d.Song.Patch[m.d.InstrIndex]) + contents, err = yaml.Marshal(instr) } if err != nil { - m.Alerts().Add(fmt.Sprintf("Error marshaling a ínstrument file: %v", err), Error) + m.Alerts().Add(fmt.Sprintf("Error marshaling an instrument file: %v", err), Error) return false } w.Write(contents) @@ -163,7 +167,7 @@ func (m *Model) LoadInstrument(r io.ReadCloser) bool { success: if f, ok := r.(*os.File); ok { filename := f.Name() - // the 4klang instrument names are junk, replace them with the filename without extension + // the instrument names are generally junk, replace them with the filename without extension instrument.Name = filepath.Base(filename[:len(filename)-len(filepath.Ext(filename))]) } defer m.change("LoadInstrument", PatchChange, MajorChange)() diff --git a/tracker/generate/clean_presets.go b/tracker/generate/clean_presets.go new file mode 100644 index 0000000..2b46fcb --- /dev/null +++ b/tracker/generate/clean_presets.go @@ -0,0 +1,47 @@ +//go:build ignore +// +build ignore + +package main + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" + + "github.com/vsariola/sointu" + "github.com/vsariola/sointu/tracker" + "gopkg.in/yaml.v3" +) + +func main() { + filepath.WalkDir("presets", 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 { + fmt.Fprintf(os.Stderr, "could not unmarshal the preset file %v: %v\n", path, err) + return nil + } + tracker.RemoveUnusedUnitParameters(&instr) // remove invalid parameters + instr.Name = "" // we don't need the names in the preset files as they are derived from the file path + outData, err := yaml.Marshal(instr) + if err != nil { + fmt.Fprintf(os.Stderr, "could not marshal the preset file %v: %v\n", path, err) + return nil + } + if err := os.WriteFile(path, outData, 0644); err != nil { + fmt.Fprintf(os.Stderr, "could not write the preset file %v: %v\n", path, err) + return nil + } + return nil + }) +} diff --git a/tracker/generate/main.go b/tracker/generate/gmdls_entries.go similarity index 100% rename from tracker/generate/main.go rename to tracker/generate/gmdls_entries.go diff --git a/tracker/model.go b/tracker/model.go index 973fb47..92d5719 100644 --- a/tracker/model.go +++ b/tracker/model.go @@ -521,21 +521,29 @@ func (m *Model) fixUnitParams() { // loop over all instruments and units and check that unit parameter table // only has the parameters that are defined in the unit type fixed := false - for i, instr := range m.d.Song.Patch { - for j, unit := range instr.Units { - for paramName := range unit.Parameters { - if !validParameters[unit.Type][paramName] { - delete(m.d.Song.Patch[i].Units[j].Parameters, paramName) - fixed = true - } - } - } + for i := range m.d.Song.Patch { + fixed = RemoveUnusedUnitParameters(&m.d.Song.Patch[i]) || fixed } if fixed { m.Alerts().AddNamed("InvalidUnitParameters", "Some units had invalid parameters, they were removed", Error) } } +// RemoveUnusedUnitParameters removes any parameters from the instrument that are not valid for the unit type. +// It returns true if any parameters were removed. +func RemoveUnusedUnitParameters(instr *sointu.Instrument) bool { + fixed := false + for _, unit := range instr.Units { + for paramName := range unit.Parameters { + if !validParameters[unit.Type][paramName] { + delete(unit.Parameters, paramName) + fixed = true + } + } + } + return fixed +} + func clamp(a, min, max int) int { if a > max { return max diff --git a/tracker/presets.go b/tracker/presets.go index 94e0be6..3e71da2 100644 --- a/tracker/presets.go +++ b/tracker/presets.go @@ -14,7 +14,8 @@ import ( "gopkg.in/yaml.v2" ) -//go:generate go run generate/main.go +//go:generate go run generate/gmdls_entries.go +//go:generate go run generate/clean_presets.go type ( // GmDlsEntry is a single sample entry from the gm.dls file