Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
369 changes: 216 additions & 153 deletions README.md

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions calc/calc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package calc

import "math"

type Range struct {
Min, Max float64
}

// Percentage returns x's position within Range in percent
func Percentage(x float64, r Range) float64 {
return (x - r.Min) / (r.Max - r.Min)
}

// Limit limits x to fix into Range
func Limit(x float64, r Range) float64 {
return math.Max(r.Min, math.Min(r.Max, x))
}

// Transppose projects x from one range to another maintaining equal proportions
func Transpose(x float64, from, to Range) float64 {
p := Percentage(x, from)
return p*(to.Max-to.Min) + to.Min
}
199 changes: 199 additions & 0 deletions calc/calc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package calc

import (
"testing"
)

func TestPercentage(t *testing.T) {
tests := []struct {
name string
x float64
r Range
want float64
}{
{
name: "minimum is 0",
x: 100,
r: Range{
Min: 100,
Max: 200,
},
want: 0,
},
{
name: "middle is 0.5",
x: 150,
r: Range{
Min: 100,
Max: 200,
},
want: 0.5,
},
{
name: "maximum is 1",
x: 200,
r: Range{
Min: 100,
Max: 200,
},
want: 1,
},
{
name: "higher than max",
x: 300,
r: Range{
Min: 100,
Max: 200,
},
want: 2,
},
{
name: "lower than min",
x: -100,
r: Range{
Min: 100,
Max: 200,
},
want: -2,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Percentage(tt.x, tt.r); got != tt.want {
t.Errorf("Percentage() = %v, want %v", got, tt.want)
}
})
}
}

func TestLimit(t *testing.T) {
tests := []struct {
name string
x float64
r Range
want float64
}{
{
name: "idempotent on the lower end",
x: 100,
r: Range{
Min: 100,
Max: 200,
},
want: 100,
},
{
name: "idempotent on the upper end",
x: 200,
r: Range{
Min: 100,
Max: 200,
},
want: 200,
},
{
name: "upper limit",
x: 300,
r: Range{
Min: 100,
Max: 200,
},
want: 200,
},
{
name: "lower limit",
x: 0,
r: Range{
Min: 100,
Max: 200,
},
want: 100,
},
{
name: "don't limit",
x: 0.1,
r: Range{
Min: 0,
Max: 1,
},
want: 0.1,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Limit(tt.x, tt.r); got != tt.want {
t.Errorf("Limit() = %v, want %v", got, tt.want)
}
})
}
}

func TestTranspose(t *testing.T) {
tests := []struct {
name string
x float64
from Range
to Range
want float64
}{
{
name: "equal ranges",
x: 6,
from: Range{
Min: 1,
Max: 11,
},
to: Range{
Min: 1,
Max: 11,
},
want: 6,
},
{
name: "different ranges",
x: 0.5,
from: Range{
Min: 0,
Max: 1,
},
to: Range{
Min: -1,
Max: 1,
},
want: 0,
},
{
name: "negative limits work",
x: 2,
from: Range{
Min: 0,
Max: 10,
},
to: Range{
Min: -2,
Max: 18,
},
want: 2,
},
{
name: "negative ranges work",
x: 5,
from: Range{
Min: 0,
Max: 10,
},
to: Range{
Min: -20,
Max: 0,
},
want: -10,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Transpose(tt.x, tt.from, tt.to); got != tt.want {
t.Errorf("Transpose() = %v, want %v", got, tt.want)
}
})
}
}
16 changes: 8 additions & 8 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,18 @@ var version = "unknown"
var rootCmd = &cobra.Command{
Use: "synth",
Version: version,
Short: "command line synthesizer",
Long: `command line synthesizer
Short: "A modular synthesizer for the command line",
Long: `A modular synthesizer for the command line.

documentation and usage: https://github.com/iljarotar/synth`,
Documentation and usage: https://github.com/iljarotar/synth`,
RunE: func(cmd *cobra.Command, args []string) error {
cfg, _ := cmd.Flags().GetString("config")

err := config.EnsureDefaultConfig()
if err != nil {
return err
}

if len(args) == 0 {
cmd.Help()
return nil
Expand All @@ -37,11 +42,6 @@ documentation and usage: https://github.com/iljarotar/synth`,
}
filename := args[0]

err := config.EnsureDefaultConfig()
if err != nil {
return err
}

defaultConfigPath, err := config.GetDefaultConfigPath()
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion control/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func NewControl(logger *log.Logger, c *config.Config) (*control, error) {
func (c *control) ReadSample() [2]float64 {
sample := [2]float64{}

o := c.synth.Next()
o := c.synth.GetOutput()
sample[0] = o.Left
sample[1] = o.Right

Expand Down
60 changes: 0 additions & 60 deletions examples/a-major.yaml

This file was deleted.

47 changes: 47 additions & 0 deletions examples/envelope.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
vol: 1
out: main

envelopes:
env:
attack: 0.01
decay: 0.01
release: 0.2
peak: 0.5
level: 0.2
gate: gate

gates:
gate:
bpm: 520
signal: [1, 0, 0, 0]

mixers:
main:
cv: env
in:
sine_mix: 1

sine_mix:
gain: 0.5
mod: tremolo_mix
in:
sine: 1

tremolo_mix:
gain: 0.2
in:
tremolo: 1

oscillators:
sine:
type: Sawtooth
freq: 80

lfo:
type: Sine
freq: 0.1
phase: -0.25

tremolo:
type: Sine
freq: 5
Loading