Skip to content

Commit

Permalink
Refactor UI (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
iljarotar authored Aug 14, 2024
1 parent 57981b9 commit ff11f53
Show file tree
Hide file tree
Showing 17 changed files with 327 additions and 230 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ on:
branches: [ "main" ]

jobs:

build:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: install portaudio
run: sudo apt update && sudo apt -y install portaudio19-dev

- name: Set up Go
uses: actions/setup-go@v4
with:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
bin
examples/test.yaml
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ VERSION := $(shell git describe --tags --exact-match 2> /dev/null || git symboli
PHONY: build
build:
go build -o bin/synth -ldflags="-X github.com/iljarotar/synth/cmd.version=$(VERSION)"

PHONY: test
test:
go test ./...
12 changes: 7 additions & 5 deletions audio/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import (
"github.com/gordonklaus/portaudio"
)

type ProcessCallback func([]float32)
type AudioOutput struct {
Left, Right float64
}

type Context struct {
*portaudio.Stream
Input chan struct{ Left, Right float32 }
Input chan AudioOutput
}

func NewContext(input chan struct{ Left, Right float32 }, sampleRate float64) (*Context, error) {
func NewContext(input chan AudioOutput, sampleRate float64) (*Context, error) {
ctx := &Context{Input: input}

var err error
Expand All @@ -26,8 +28,8 @@ func NewContext(input chan struct{ Left, Right float32 }, sampleRate float64) (*
func (c *Context) Process(out [][]float32) {
for i := range out[0] {
y := <-c.Input
out[0][i] = y.Left
out[1][i] = y.Right
out[0][i] = float32(y.Left)
out[1][i] = float32(y.Right)
}
}

Expand Down
60 changes: 35 additions & 25 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"time"

"github.com/iljarotar/synth/audio"
"github.com/iljarotar/synth/config"

c "github.com/iljarotar/synth/config"
"github.com/iljarotar/synth/control"
f "github.com/iljarotar/synth/file"
Expand Down Expand Up @@ -53,19 +53,19 @@ documentation and usage: https://github.com/iljarotar/synth`,
if cfg == "" {
cfg = defaultConfigPath
}
err = c.LoadConfig(cfg)
config, err := c.LoadConfig(cfg)
if err != nil {
fmt.Printf("could not load config file: %v\n", err)
return
}

err = parseFlags(cmd)
err = parseFlags(cmd, config)
if err != nil {
fmt.Println(err)
return
}

err = start(file)
err = start(file, config)
if err != nil {
fmt.Println(err)
}
Expand All @@ -80,45 +80,55 @@ func Execute() {
}

func init() {
defaultConfigPath, err := config.GetDefaultConfigPath()
defaultConfigPath, err := c.GetDefaultConfigPath()
if err != nil {
os.Exit(1)
}
rootCmd.Flags().Float64P("sample-rate", "s", config.Default.SampleRate, "sample rate")
rootCmd.Flags().Float64("fade-in", config.Default.FadeIn, "fade-in in seconds")
rootCmd.Flags().Float64("fade-out", config.Default.FadeOut, "fade-out in seconds")
rootCmd.Flags().Float64P("sample-rate", "s", c.DefaultSampleRate, "sample rate")
rootCmd.Flags().Float64("fade-in", c.DefaultFadeIn, "fade-in in seconds")
rootCmd.Flags().Float64("fade-out", c.DefaultFadeOut, "fade-out in seconds")
rootCmd.Flags().StringP("config", "c", defaultConfigPath, "path to your config file")
rootCmd.Flags().Float64P("duration", "d", config.Default.Duration, "duration in seconds; if positive duration is specified, synth will stop playing after the defined time")
rootCmd.Flags().Float64P("duration", "d", c.DefaultDuration, "duration in seconds; if positive duration is specified, synth will stop playing after the defined time")
}

func parseFlags(cmd *cobra.Command) error {
func parseFlags(cmd *cobra.Command, config *c.Config) error {
s, _ := cmd.Flags().GetFloat64("sample-rate")
in, _ := cmd.Flags().GetFloat64("fade-in")
out, _ := cmd.Flags().GetFloat64("fade-out")
duration, _ := cmd.Flags().GetFloat64("duration")

c.Config.SampleRate = s
c.Config.FadeIn = in
c.Config.FadeOut = out
c.Config.Duration = duration
if cmd.Flag("sample-rate").Changed {
config.SampleRate = s
}
if cmd.Flag("fade-in").Changed {
config.FadeIn = in
}
if cmd.Flag("fade-out").Changed {
config.FadeOut = out
}
if cmd.Flag("duration").Changed {
config.Duration = duration
}

return c.Config.Validate()
return config.Validate()
}

func start(file string) error {
func start(file string, config *c.Config) error {
err := audio.Init()
if err != nil {
return err
}
defer audio.Terminate()

logger := ui.NewLogger(10)
quit := make(chan bool)
autoStop := make(chan bool)
u := ui.NewUI(file, quit, autoStop)
var closing bool
u := ui.NewUI(logger, file, quit, autoStop, config.Duration, &closing)
go u.Enter()

output := make(chan struct{ Left, Right float32 })
ctx, err := audio.NewContext(output, c.Config.SampleRate)
output := make(chan audio.AudioOutput)
ctx, err := audio.NewContext(output, config.SampleRate)
if err != nil {
return err
}
Expand All @@ -129,11 +139,11 @@ func start(file string) error {
return err
}

ctl := control.NewControl(output, autoStop)
ctl := control.NewControl(logger, *config, output, autoStop, &closing)
ctl.Start()
defer ctl.StopSynth()

loader, err := f.NewLoader(ctl, file)
loader, err := f.NewLoader(logger, ctl, file, &closing)
if err != nil {
return err
}
Expand All @@ -150,20 +160,20 @@ func start(file string) error {
interrupt := make(chan bool)
go catchInterrupt(interrupt, sig)

ctl.FadeIn(c.Config.FadeIn)
ctl.FadeIn(config.FadeIn)
var fadingOut bool

Loop:
for {
select {
case <-quit:
if fadingOut {
ui.Logger.Info("already received quit signal")
logger.Info("already received quit signal")
continue
}
fadingOut = true
ui.Logger.Info(fmt.Sprintf("fading out in %fs", c.Config.FadeOut))
ctl.Stop(c.Config.FadeOut)
logger.Info(fmt.Sprintf("fading out in %fs", config.FadeOut))
ctl.Stop(config.FadeOut)
case <-interrupt:
ctl.Stop(0.05)
case <-ctl.SynthDone:
Expand Down
54 changes: 32 additions & 22 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,26 @@ import (
)

const (
minSampleRate = 8000
maxSampleRate = 48000
maxFadeDuration = 3600
maxDuration = 7200
minSampleRate = 8000
maxSampleRate = 48000
maxFadeDuration = 3600
maxDuration = 7200

defaultConfigFile = "config.yaml"
defaultConfigDir = "synth"
DefaultSampleRate = 44100
DefaultFadeIn = 1
DefaultFadeOut = 1
DefaultDuration = -1
)

type config struct {
type Config struct {
SampleRate float64 `yaml:"sample-rate"`
FadeIn float64 `yaml:"fade-in"`
FadeOut float64 `yaml:"fade-out"`
Duration float64 `yaml:"duration"`
}

var Default = config{
SampleRate: 44100,
FadeIn: 1,
FadeOut: 1,
Duration: -1,
}

var Config = config{}

func GetDefaultConfigPath() (string, error) {
userConfigDir, err := os.UserConfigDir()
if err != nil {
Expand All @@ -55,7 +51,14 @@ func EnsureDefaultConfig() error {
return fmt.Errorf("unable to open config file: %w", err)
}

defaultConfig, err := yaml.Marshal(Default)
defaultConfig := Config{
SampleRate: DefaultSampleRate,
FadeIn: DefaultFadeIn,
FadeOut: DefaultFadeOut,
Duration: DefaultDuration,
}

defaultConfigBytes, err := yaml.Marshal(defaultConfig)
if err != nil {
return fmt.Errorf("unable to marshal default config: %w", err)
}
Expand All @@ -65,24 +68,31 @@ func EnsureDefaultConfig() error {
return fmt.Errorf("unable to create config directory: %w", err)
}

return os.WriteFile(configPath, defaultConfig, 0600)
return os.WriteFile(configPath, defaultConfigBytes, 0600)
}

func LoadConfig(path string) error {
func LoadConfig(path string) (*Config, error) {
raw, err := os.ReadFile(path)
if err != nil {
return err
return nil, err
}

err = yaml.Unmarshal(raw, &Config)
config := &Config{}

err = yaml.Unmarshal(raw, &config)
if err != nil {
return err
return nil, err
}

err = config.Validate()
if err != nil {
return nil, err
}

return Config.Validate()
return config, nil
}

func (c *config) Validate() error {
func (c *Config) Validate() error {
if c.SampleRate < minSampleRate {
return fmt.Errorf("sample rate must be greater than or equal to %d", minSampleRate)
}
Expand Down
Loading

0 comments on commit ff11f53

Please sign in to comment.