forked from xlab/portmidi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaudio.go
More file actions
93 lines (81 loc) · 2.04 KB
/
audio.go
File metadata and controls
93 lines (81 loc) · 2.04 KB
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
package main
import (
"errors"
"unsafe"
"github.com/xlab/portaudio-go/portaudio"
)
type IOControl struct {
stream *portaudio.Stream
inCh int
outCh int
in chan<- []float32
out <-chan []float32
}
const (
paFormat = portaudio.PaFloat32
paSampleRate = 44100
)
func NewIOControl(inCh, outCh int, samplesPerCh int,
in chan<- []float32, out <-chan []float32) (*IOControl, error) {
if err := portaudio.Initialize(); paError(err) {
return nil, errors.New(paErrorText(err))
}
if in == nil {
inCh = 0
}
if out == nil {
outCh = 0
}
var stream *portaudio.Stream
ctl := &IOControl{
inCh: inCh,
outCh: outCh,
in: in,
out: out,
}
if err := portaudio.OpenDefaultStream(&stream, int32(inCh), int32(outCh), paFormat, paSampleRate,
uint(samplesPerCh), ctl.audioCallback, nil); paError(err) {
return nil, errors.New(paErrorText(err))
}
ctl.stream = stream
return ctl, nil
}
func (i *IOControl) StartStream() error {
err := portaudio.StartStream(i.stream)
if paError(err) {
return errors.New(paErrorText(err))
}
return nil
}
func (i *IOControl) audioCallback(input unsafe.Pointer, output unsafe.Pointer, sampleCount uint,
_ *portaudio.StreamCallbackTimeInfo, _ portaudio.StreamCallbackFlags, _ unsafe.Pointer) int32 {
const statusContinue = int32(portaudio.PaContinue)
samples := int(sampleCount)
if input != nil && i.in != nil {
inFrame := (*(*[1 << 32]float32)(input))[:samples*i.inCh]
i.in <- inFrame[:samples*i.inCh] // TODO(xlab): consider copying
}
if output != nil && i.out != nil {
outFrame := (*(*[1 << 32]float32)(output))[:samples*i.outCh]
select {
case frame := <-i.out:
copy(outFrame, frame[:samples*i.outCh])
default:
return statusContinue
}
}
return statusContinue
}
func (i *IOControl) Destroy() {
if i.stream != nil {
portaudio.StopStream(i.stream)
portaudio.Terminate()
i.stream = nil
}
}
func paError(err portaudio.Error) bool {
return portaudio.ErrorCode(err) != portaudio.PaNoError
}
func paErrorText(err portaudio.Error) string {
return portaudio.GetErrorText(err)
}