-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathprocessor.go
137 lines (126 loc) · 3.67 KB
/
processor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// +build !plugin
package vst2
import (
"context"
"pipelined.dev/pipe"
"pipelined.dev/pipe/mutable"
"pipelined.dev/signal"
)
type (
// Processor is pipe component that wraps.
Processor struct {
bufferSize int
channels int
sampleRate signal.Frequency
plugin *Plugin
progressFn ProgressProcessedFunc
}
// ProcessorInitFunc applies configuration on plugin before starting it
// in the processor routine.
ProcessorInitFunc func(*Plugin)
// HostProgressProcessed is executed by processor after every process
// call.
ProgressProcessedFunc func(int)
)
// Processor represents vst2 sound processor. Processor always overrides
// GetBufferSize and GetSampleRate callbacks, because this vaules are
// injected when processor is allocated by pipe.
func (v *VST) Processor(h Host, progressFn ProgressProcessedFunc) *Processor {
processor := Processor{}
h.GetBufferSize = func() int {
return processor.bufferSize
}
h.GetSampleRate = func() signal.Frequency {
return processor.sampleRate
}
plugin := v.Plugin(h.Callback())
return &Processor{
plugin: plugin,
progressFn: progressFn,
}
}
// Allocator returns pipe processor allocator that can be plugged into line.
func (p *Processor) Allocator(init ProcessorInitFunc) pipe.ProcessorAllocatorFunc {
return func(mctx mutable.Context, bufferSize int, props pipe.SignalProperties) (pipe.Processor, error) {
p.bufferSize = bufferSize
p.channels = props.Channels
p.sampleRate = props.SampleRate
p.plugin.Start()
p.plugin.SetSampleRate(props.SampleRate)
p.plugin.SetBufferSize(bufferSize)
if init != nil {
init(p.plugin)
}
processFn, flushFn := processorFns(p.plugin, p.channels, p.bufferSize, p.progressFn)
return pipe.Processor{
SignalProperties: pipe.SignalProperties{
Channels: p.channels,
SampleRate: p.sampleRate,
},
StartFunc: func(context.Context) error {
p.plugin.Resume()
return nil
},
ProcessFunc: processFn,
FlushFunc: flushFn,
}, nil
}
}
func processorFns(p *Plugin, channels, bufferSize int, progressFn ProgressProcessedFunc) (pipe.ProcessFunc, pipe.FlushFunc) {
if p.CanProcessFloat64() {
return doubleFns(p, channels, bufferSize, progressFn)
}
return floatFns(p, channels, bufferSize, progressFn)
}
func doubleFns(p *Plugin, channels, bufferSize int, progressFn ProgressProcessedFunc) (pipe.ProcessFunc, pipe.FlushFunc) {
doubleIn := NewDoubleBuffer(channels, bufferSize)
doubleOut := NewDoubleBuffer(channels, bufferSize)
processFn := func(in, out signal.Floating) (int, error) {
doubleIn.Write(in)
p.ProcessDouble(doubleIn, doubleOut)
doubleOut.Read(out)
return in.Length(), nil
}
if progressFn != nil {
processFn = func(in, out signal.Floating) (int, error) {
doubleIn.Write(in)
p.ProcessDouble(doubleIn, doubleOut)
doubleOut.Read(out)
progressFn(in.Length())
return in.Length(), nil
}
}
return processFn,
func(context.Context) error {
doubleIn.Free()
doubleOut.Free()
p.Suspend()
return nil
}
}
func floatFns(p *Plugin, channels, bufferSize int, progressFn ProgressProcessedFunc) (pipe.ProcessFunc, pipe.FlushFunc) {
floatIn := NewFloatBuffer(channels, bufferSize)
floatOut := NewFloatBuffer(channels, bufferSize)
processFn := func(in, out signal.Floating) (int, error) {
floatIn.Write(in)
p.ProcessFloat(floatIn, floatOut)
floatOut.Read(out)
return in.Length(), nil
}
if progressFn != nil {
processFn = func(in, out signal.Floating) (int, error) {
floatIn.Write(in)
p.ProcessFloat(floatIn, floatOut)
floatOut.Read(out)
progressFn(in.Length())
return in.Length(), nil
}
}
return processFn,
func(context.Context) error {
floatIn.Free()
floatOut.Free()
p.Suspend()
return nil
}
}