Skip to content

Commit 1ba7db1

Browse files
committed
Move large chunk of catnip setup to separate package.
make it possible to use the general setup for more generic uses
1 parent c8673eb commit 1ba7db1

File tree

7 files changed

+242
-115
lines changed

7 files changed

+242
-115
lines changed

catnip.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package catnip
2+
3+
import (
4+
"context"
5+
"sync"
6+
7+
"github.com/noriah/catnip/input"
8+
"github.com/noriah/catnip/processor"
9+
10+
"github.com/pkg/errors"
11+
)
12+
13+
type SetupFunc func() error
14+
type StartFunc func(ctx context.Context) (context.Context, error)
15+
type CleanupFunc func() error
16+
17+
func Catnip(cfg *Config) error {
18+
if err := cfg.Validate(); err != nil {
19+
return err
20+
}
21+
22+
inputBuffers := input.MakeBuffers(cfg.ChannelCount, cfg.SampleSize)
23+
24+
procConfig := processor.Config{
25+
SampleRate: cfg.SampleRate,
26+
SampleSize: cfg.SampleSize,
27+
ChannelCount: cfg.ChannelCount,
28+
ProcessRate: cfg.ProcessRate,
29+
Buffers: inputBuffers,
30+
Analyzer: cfg.Analyzer,
31+
Output: cfg.Output,
32+
Smoother: cfg.Smoother,
33+
Windower: cfg.Windower,
34+
}
35+
36+
var vis processor.Processor
37+
38+
if cfg.UseThreaded {
39+
vis = processor.NewThreaded(procConfig)
40+
} else {
41+
vis = processor.New(procConfig)
42+
}
43+
44+
// INPUT SETUP
45+
46+
backend, err := input.InitBackend(cfg.Backend)
47+
if err != nil {
48+
return err
49+
}
50+
51+
sessConfig := input.SessionConfig{
52+
FrameSize: cfg.ChannelCount,
53+
SampleSize: cfg.SampleSize,
54+
SampleRate: cfg.SampleRate,
55+
}
56+
57+
if sessConfig.Device, err = input.GetDevice(backend, cfg.Device); err != nil {
58+
return err
59+
}
60+
61+
audio, err := backend.Start(sessConfig)
62+
defer backend.Close()
63+
64+
if err != nil {
65+
return errors.Wrap(err, "failed to start the input backend")
66+
}
67+
68+
// DISPLAY SETUP
69+
70+
if cfg.SetupFunc != nil {
71+
if err := cfg.SetupFunc(); err != nil {
72+
return err
73+
}
74+
}
75+
76+
if cfg.CleanupFunc != nil {
77+
defer cfg.CleanupFunc()
78+
}
79+
80+
// Root Context
81+
ctx, cancel := context.WithCancel(context.Background())
82+
defer cancel()
83+
84+
if cfg.StartFunc != nil {
85+
if ctx, err = cfg.StartFunc(ctx); err != nil {
86+
return err
87+
}
88+
}
89+
90+
ctx = vis.Start(ctx)
91+
defer vis.Stop()
92+
93+
kickChan := make(chan bool, 1)
94+
95+
mu := &sync.Mutex{}
96+
97+
// Start the processor
98+
go vis.Process(ctx, kickChan, mu)
99+
100+
if err := audio.Start(ctx, inputBuffers, kickChan, mu); err != nil {
101+
if !errors.Is(ctx.Err(), context.Canceled) {
102+
return errors.Wrap(err, "failed to start input session")
103+
}
104+
}
105+
106+
return nil
107+
}

cmd/catnip/config.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ type config struct {
3535
spaceSize int
3636
// ChannelCount is the number of channels we want to look at. DO NOT TOUCH
3737
channelCount int
38-
// Combine determines if we merge streams (stereo -> mono)
38+
// DrawType is the draw type
3939
drawType int
40-
// Styles is the configuration for bar color styles
40+
// Combine determines if we merge streams (stereo -> mono)
4141
combine bool
4242
// Use threaded processor
4343
useThreaded bool
4444
// Invert the order of bin drawing
4545
invertDraw bool
46-
// DrawType is the draw type
46+
// Styles is the configuration for bar color styles
4747
styles graphic.Styles
4848
}
4949

@@ -72,7 +72,7 @@ func newZeroConfig() config {
7272
}
7373

7474
// Sanitize cleans things up
75-
func (cfg *config) Sanitize() error {
75+
func (cfg *config) validate() error {
7676

7777
if cfg.sampleRate < float64(cfg.sampleSize) {
7878
return errors.New("sample rate lower than sample size")

cmd/catnip/main.go

Lines changed: 35 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,16 @@ import (
44
"context"
55
"fmt"
66
"log"
7-
"sync"
87

8+
"github.com/noriah/catnip"
99
"github.com/noriah/catnip/dsp"
1010
"github.com/noriah/catnip/dsp/window"
1111
"github.com/noriah/catnip/graphic"
1212
"github.com/noriah/catnip/input"
13-
"github.com/noriah/catnip/processor"
1413

1514
_ "github.com/noriah/catnip/input/all"
1615

1716
"github.com/integrii/flaggy"
18-
"github.com/pkg/errors"
1917
)
2018

2119
// AppName is the app name
@@ -38,110 +36,58 @@ func main() {
3836
return
3937
}
4038

41-
chk(cfg.Sanitize(), "invalid config")
39+
chk(cfg.validate(), "invalid config")
4240

43-
chk(catnip(&cfg), "failed to run catnip")
44-
}
45-
46-
// Catnip starts to draw the processor on the termbox screen.
47-
func catnip(cfg *config) error {
48-
49-
display := &graphic.Display{}
50-
51-
// PROCESSOR SETUP
52-
53-
inputBuffers := input.MakeBuffers(cfg.channelCount, cfg.sampleSize)
41+
display := graphic.NewDisplay()
5442

55-
procConfig := processor.Config{
43+
catnipCfg := catnip.Config{
44+
Backend: cfg.backend,
45+
Device: cfg.device,
5646
SampleRate: cfg.sampleRate,
5747
SampleSize: cfg.sampleSize,
5848
ChannelCount: cfg.channelCount,
59-
FrameRate: cfg.frameRate,
60-
Buffers: inputBuffers,
49+
ProcessRate: cfg.frameRate,
50+
Combine: cfg.combine,
51+
UseThreaded: cfg.useThreaded,
52+
SetupFunc: func() error {
53+
if err := display.Init(cfg.sampleRate, cfg.sampleSize); err != nil {
54+
return err
55+
}
56+
57+
display.SetSizes(cfg.barSize, cfg.spaceSize)
58+
display.SetBase(cfg.baseSize)
59+
display.SetDrawType(graphic.DrawType(cfg.drawType))
60+
display.SetStyles(cfg.styles)
61+
display.SetInvertDraw(cfg.invertDraw)
62+
63+
return nil
64+
},
65+
StartFunc: func(ctx context.Context) (context.Context, error) {
66+
ctx = display.Start(ctx)
67+
68+
return ctx, nil
69+
},
70+
CleanupFunc: func() error {
71+
display.Stop()
72+
display.Close()
73+
return nil
74+
},
75+
Output: display,
76+
Windower: window.Lanczos,
6177
Analyzer: dsp.NewAnalyzer(dsp.AnalyzerConfig{
6278
SampleRate: cfg.sampleRate,
6379
SampleSize: cfg.sampleSize,
6480
SquashLow: true,
6581
BinMethod: dsp.MaxSamples,
6682
}),
67-
Output: display,
6883
Smoother: dsp.NewSmoother(dsp.SmootherConfig{
6984
SampleSize: cfg.sampleSize,
7085
ChannelCount: cfg.channelCount,
7186
SmoothingFactor: cfg.smoothFactor,
7287
}),
73-
Windower: window.Lanczos,
74-
}
75-
76-
var vis processor.Processor
77-
78-
if cfg.useThreaded {
79-
vis = processor.NewThreaded(procConfig)
80-
} else {
81-
vis = processor.New(procConfig)
82-
}
83-
84-
// INPUT SETUP
85-
86-
backend, err := input.InitBackend(cfg.backend)
87-
if err != nil {
88-
return err
89-
}
90-
91-
sessConfig := input.SessionConfig{
92-
FrameSize: cfg.channelCount,
93-
SampleSize: cfg.sampleSize,
94-
SampleRate: cfg.sampleRate,
95-
}
96-
97-
if sessConfig.Device, err = input.GetDevice(backend, cfg.device); err != nil {
98-
return err
99-
}
100-
101-
audio, err := backend.Start(sessConfig)
102-
defer backend.Close()
103-
104-
if err != nil {
105-
return errors.Wrap(err, "failed to start the input backend")
106-
}
107-
108-
// DISPLAY SETUP
109-
110-
if err = display.Init(cfg.sampleRate, cfg.sampleSize); err != nil {
111-
return err
112-
}
113-
defer display.Close()
114-
115-
display.SetSizes(cfg.barSize, cfg.spaceSize)
116-
display.SetBase(cfg.baseSize)
117-
display.SetDrawType(graphic.DrawType(cfg.drawType))
118-
display.SetStyles(cfg.styles)
119-
display.SetInvertDraw(cfg.invertDraw)
120-
121-
// Root Context
122-
ctx, cancel := context.WithCancel(context.Background())
123-
defer cancel()
124-
125-
ctx = display.Start(ctx)
126-
defer display.Stop()
127-
128-
ctx = vis.Start(ctx)
129-
defer vis.Stop()
130-
131-
kickChan := make(chan bool, 1)
132-
133-
mu := &sync.Mutex{}
134-
135-
// Start the processor
136-
go vis.Process(ctx, kickChan, mu)
137-
138-
if err := audio.Start(ctx, inputBuffers, kickChan, mu); err != nil {
139-
if !errors.Is(ctx.Err(), context.Canceled) {
140-
return errors.Wrap(err, "failed to start input session")
141-
}
14288
}
14389

144-
return nil
90+
chk(catnip.Catnip(&catnipCfg), "failed to run catnip")
14591
}
14692

14793
func doFlags(cfg *config) bool {

config.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package catnip
2+
3+
import (
4+
"errors"
5+
6+
"github.com/noriah/catnip/dsp"
7+
"github.com/noriah/catnip/dsp/window"
8+
"github.com/noriah/catnip/processor"
9+
)
10+
11+
type Config struct {
12+
// The name of the backend from the input package
13+
Backend string
14+
// The name of the device to pull data from
15+
Device string
16+
// The rate that samples are read
17+
SampleRate float64
18+
// The number of samples per batch
19+
SampleSize int
20+
// The number of channels to read data from
21+
ChannelCount int
22+
// The number of times per second to process data
23+
ProcessRate int
24+
// Merge multiple channels into a single stream
25+
Combine bool
26+
27+
// testing. leave false
28+
// Use threaded processor
29+
UseThreaded bool
30+
31+
// Function to call when setting up the pipeline
32+
SetupFunc SetupFunc
33+
// Function to call when starting the pipeline
34+
StartFunc StartFunc
35+
// Function to call when cleaning up the pipeline
36+
CleanupFunc CleanupFunc
37+
// Where to send the data from the audio analysis
38+
Output processor.Output
39+
// Method to run on data before running fft
40+
Windower window.Function
41+
// Analyzer to run analysis on data
42+
Analyzer dsp.Analyzer
43+
// Smoother to run smoothing on output from Analyzer
44+
Smoother dsp.Smoother
45+
}
46+
47+
func NewZeroConfig() Config {
48+
return Config{
49+
SampleRate: 44100,
50+
SampleSize: 1024,
51+
ChannelCount: 1,
52+
ProcessRate: 0,
53+
Combine: false,
54+
UseThreaded: false,
55+
}
56+
}
57+
58+
func (cfg *Config) Validate() error {
59+
if cfg.SampleRate < float64(cfg.SampleSize) {
60+
return errors.New("sample rate lower than sample size")
61+
}
62+
63+
if cfg.SampleSize < 4 {
64+
return errors.New("sample size too small (4+ required)")
65+
}
66+
67+
switch {
68+
69+
case cfg.ChannelCount > 2:
70+
return errors.New("too many channels (2 max)")
71+
72+
case cfg.ChannelCount < 1:
73+
return errors.New("too few channels (1 min)")
74+
75+
}
76+
77+
return nil
78+
}

graphic/display.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ type Display struct {
109109
cancel context.CancelFunc
110110
}
111111

112+
func NewDisplay() *Display {
113+
return &Display{}
114+
}
115+
112116
// Init initializes the display.
113117
// Should be called before any other display method.
114118
func (d *Display) Init(sampleRate float64, sampleSize int) error {

0 commit comments

Comments
 (0)