mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-18 13:04:25 -04:00
style: group types into fewer, logical files
This commit is contained in:
parent
0187cc66ec
commit
e4a2ed9f32
248
patch.go
248
patch.go
@ -6,8 +6,252 @@ import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// Patch is simply a list of instruments used in a song
|
||||
type Patch []Instrument
|
||||
type (
|
||||
// Patch is simply a list of instruments used in a song
|
||||
Patch []Instrument
|
||||
|
||||
// Instrument includes a list of units consisting of the instrument, and the number of polyphonic voices for this instrument
|
||||
Instrument struct {
|
||||
Name string `yaml:",omitempty"`
|
||||
Comment string `yaml:",omitempty"`
|
||||
NumVoices int
|
||||
Units []Unit
|
||||
}
|
||||
|
||||
// Unit is e.g. a filter, oscillator, envelope and its parameters
|
||||
Unit struct {
|
||||
// Type is the type of the unit, e.g. "add","oscillator" or "envelope".
|
||||
// Always in lowercase. "" type should be ignored, no invalid types should
|
||||
// be used.
|
||||
Type string `yaml:",omitempty"`
|
||||
|
||||
// ID should be a unique ID for this unit, used by SEND units to target
|
||||
// specific units. ID = 0 means that no ID has been given to a unit and thus
|
||||
// cannot be targeted by SENDs. When possible, units that are not targeted
|
||||
// by any SENDs should be cleaned from having IDs, e.g. to keep the exported
|
||||
// data clean.
|
||||
ID int `yaml:",omitempty"`
|
||||
|
||||
// Parameters is a map[string]int of parameters of a unit. For example, for
|
||||
// an oscillator, unit.Type == "oscillator" and unit.Parameters["attack"]
|
||||
// could be 64. Most parameters are either limites to 0 and 1 (e.g. stereo
|
||||
// parameters) or between 0 and 128, inclusive.
|
||||
Parameters map[string]int `yaml:",flow"`
|
||||
|
||||
// VarArgs is a list containing the variable number arguments that some
|
||||
// units require, most notably the DELAY units. For example, for a DELAY
|
||||
// unit, VarArgs is the delaytimes, in samples, of the different delaylines
|
||||
// in the unit.
|
||||
VarArgs []int `yaml:",flow,omitempty"`
|
||||
}
|
||||
|
||||
// UnitParameter documents one parameter that an unit takes
|
||||
UnitParameter struct {
|
||||
Name string // thould be found with this name in the Unit.Parameters map
|
||||
MinValue int // minimum value of the parameter, inclusive
|
||||
MaxValue int // maximum value of the parameter, inclusive
|
||||
CanSet bool // if this parameter can be set before hand i.e. through the gui
|
||||
CanModulate bool // if this parameter can be modulated i.e. has a port number in "send" unit
|
||||
}
|
||||
)
|
||||
|
||||
// UnitTypes documents all the available unit types and if they support stereo variant
|
||||
// and what parameters they take.
|
||||
var UnitTypes = map[string]([]UnitParameter){
|
||||
"add": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
|
||||
"addp": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
|
||||
"pop": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
|
||||
"loadnote": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
|
||||
"mul": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
|
||||
"mulp": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
|
||||
"push": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
|
||||
"xch": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
|
||||
"distort": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "drive", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}},
|
||||
"hold": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "holdfreq", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}},
|
||||
"crush": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "resolution", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}},
|
||||
"gain": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "gain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}},
|
||||
"invgain": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "invgain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}},
|
||||
"filter": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "frequency", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "resonance", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "lowpass", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "bandpass", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "highpass", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "negbandpass", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "neghighpass", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
|
||||
"clip": []UnitParameter{{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
|
||||
"pan": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "panning", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}},
|
||||
"delay": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "pregain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "dry", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "feedback", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "damp", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "notetracking", MinValue: 0, MaxValue: 2, CanSet: true, CanModulate: false},
|
||||
{Name: "delaytime", MinValue: 0, MaxValue: -1, CanSet: false, CanModulate: true}},
|
||||
"compressor": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "attack", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "release", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "invgain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "threshold", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "ratio", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}},
|
||||
"speed": []UnitParameter{},
|
||||
"out": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "gain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}},
|
||||
"outaux": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "outgain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "auxgain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}},
|
||||
"aux": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "gain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "channel", MinValue: 0, MaxValue: 6, CanSet: true, CanModulate: false}},
|
||||
"send": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "amount", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "voice", MinValue: 0, MaxValue: 32, CanSet: true, CanModulate: false},
|
||||
{Name: "target", MinValue: 0, MaxValue: math.MaxInt32, CanSet: true, CanModulate: false},
|
||||
{Name: "port", MinValue: 0, MaxValue: 7, CanSet: true, CanModulate: false},
|
||||
{Name: "sendpop", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false}},
|
||||
"envelope": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "attack", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "decay", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "sustain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "release", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "gain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}},
|
||||
"noise": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "shape", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "gain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}},
|
||||
"oscillator": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "transpose", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "detune", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "phase", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "color", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "shape", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "gain", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true},
|
||||
{Name: "frequency", MinValue: 0, MaxValue: -1, CanSet: false, CanModulate: true},
|
||||
{Name: "type", MinValue: int(Sine), MaxValue: int(Sample), CanSet: true, CanModulate: false},
|
||||
{Name: "lfo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "unison", MinValue: 0, MaxValue: 3, CanSet: true, CanModulate: false},
|
||||
{Name: "samplestart", MinValue: 0, MaxValue: 1720329, CanSet: true, CanModulate: false},
|
||||
{Name: "loopstart", MinValue: 0, MaxValue: 65535, CanSet: true, CanModulate: false},
|
||||
{Name: "looplength", MinValue: 0, MaxValue: 65535, CanSet: true, CanModulate: false}},
|
||||
"loadval": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "value", MinValue: 0, MaxValue: 128, CanSet: true, CanModulate: true}},
|
||||
"receive": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "left", MinValue: 0, MaxValue: -1, CanSet: false, CanModulate: true},
|
||||
{Name: "right", MinValue: 0, MaxValue: -1, CanSet: false, CanModulate: true}},
|
||||
"in": []UnitParameter{
|
||||
{Name: "stereo", MinValue: 0, MaxValue: 1, CanSet: true, CanModulate: false},
|
||||
{Name: "channel", MinValue: 0, MaxValue: 6, CanSet: true, CanModulate: false}},
|
||||
"sync": []UnitParameter{},
|
||||
}
|
||||
|
||||
// When unit.Type = "oscillator", its unit.Parameter["Type"] tells the type of
|
||||
// the oscillator. There is five different oscillator types, so these consts
|
||||
// just enumerate them.
|
||||
const (
|
||||
Sine = iota
|
||||
Trisaw = iota
|
||||
Pulse = iota
|
||||
Gate = iota
|
||||
Sample = iota
|
||||
)
|
||||
|
||||
// Ports is static map allowing quickly finding the parameters of a unit that
|
||||
// can be modulated. This is populated based on the UnitTypes list during
|
||||
// init(). Thus, should be immutable, but Go not supporting that, then this will
|
||||
// have to suffice: DO NOT EVER CHANGE THIS MAP.
|
||||
var Ports = make(map[string]([]string))
|
||||
|
||||
func init() {
|
||||
for name, unitType := range UnitTypes {
|
||||
unitPorts := make([]string, 0)
|
||||
for _, param := range unitType {
|
||||
if param.CanModulate {
|
||||
unitPorts = append(unitPorts, param.Name)
|
||||
}
|
||||
}
|
||||
Ports[name] = unitPorts
|
||||
}
|
||||
}
|
||||
|
||||
// Copy makes a deep copy of a unit.
|
||||
func (u *Unit) Copy() Unit {
|
||||
parameters := make(map[string]int)
|
||||
for k, v := range u.Parameters {
|
||||
parameters[k] = v
|
||||
}
|
||||
varArgs := make([]int, len(u.VarArgs))
|
||||
copy(varArgs, u.VarArgs)
|
||||
return Unit{Type: u.Type, Parameters: parameters, VarArgs: varArgs, ID: u.ID}
|
||||
}
|
||||
|
||||
// StackChange returns how this unit will affect the signal stack. "pop" and
|
||||
// "addp" and such will consume the topmost signal, and thus return -1 (or -2,
|
||||
// if the unit is a stereo unit). On the other hand, "oscillator" and "envelope"
|
||||
// will produce a signal, and thus return 1 (or 2, if the unit is a stereo
|
||||
// unit). Effects that just change the topmost signal and will not change the
|
||||
// number of signals on the stack and thus return 0.
|
||||
func (u *Unit) StackChange() int {
|
||||
switch u.Type {
|
||||
case "addp", "mulp", "pop", "out", "outaux", "aux":
|
||||
return -1 - u.Parameters["stereo"]
|
||||
case "envelope", "oscillator", "push", "noise", "receive", "loadnote", "loadval", "in", "compressor":
|
||||
return 1 + u.Parameters["stereo"]
|
||||
case "pan":
|
||||
return 1 - u.Parameters["stereo"]
|
||||
case "speed":
|
||||
return -1
|
||||
case "send":
|
||||
return (-1 - u.Parameters["stereo"]) * u.Parameters["sendpop"]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// StackNeed returns the number of signals that should be on the stack before
|
||||
// this unit is executed. Used to prevent stack underflow. Units producing
|
||||
// signals do not care what is on the stack before and will return 0.
|
||||
func (u *Unit) StackNeed() int {
|
||||
switch u.Type {
|
||||
case "", "envelope", "oscillator", "noise", "receive", "loadnote", "loadval", "in":
|
||||
return 0
|
||||
case "mulp", "mul", "add", "addp", "xch":
|
||||
return 2 * (1 + u.Parameters["stereo"])
|
||||
case "speed":
|
||||
return 1
|
||||
}
|
||||
return 1 + u.Parameters["stereo"]
|
||||
}
|
||||
|
||||
// Copy makes a deep copy of an Instrument
|
||||
func (instr *Instrument) Copy() Instrument {
|
||||
units := make([]Unit, len(instr.Units))
|
||||
for i, u := range instr.Units {
|
||||
units[i] = u.Copy()
|
||||
}
|
||||
return Instrument{Name: instr.Name, Comment: instr.Comment, NumVoices: instr.NumVoices, Units: units}
|
||||
}
|
||||
|
||||
// Copy makes a deep copy of a Patch.
|
||||
func (p Patch) Copy() Patch {
|
||||
|
Reference in New Issue
Block a user