-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathpcm_buffer.go
349 lines (327 loc) · 8.92 KB
/
pcm_buffer.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
package audio
import (
"bytes"
"encoding/binary"
"errors"
)
var (
ErrInvalidBuffer = errors.New("invalid buffer")
)
// DataFormat is an enum type to indicate the underlying data format used.
type DataFormat int
const (
// Unknown refers to an unknown format
Unknown DataFormat = iota
// Integer represents the int type.
// it represents the native int format used in audio buffers.
Integer
// Float represents the float64 type.
// It represents the native float format used in audio buffers.
Float
// Byte represents the byte type.
Byte
)
// Format is a high level representation of the underlying data.
type Format struct {
// NumChannels is the number of channels contained in the data
NumChannels int
// SampleRate is the sampling rate in Hz
SampleRate int
// BitDepth is the number of bits of data for each sample
BitDepth int
// Endianess indicate how the byte order of underlying bytes
Endianness binary.ByteOrder
}
// PCMBuffer encapsulates uncompressed audio data
// and provides useful methods to read/manipulate this PCM data.
type PCMBuffer struct {
// Format describes the format of the buffer data.
Format *Format
// Ints is a store for audio sample data as integers.
Ints []int
// Floats is a store for audio samples data as float64.
Floats []float64
// Bytes is a store for audio samples data as raw bytes.
Bytes []byte
// DataType indicates the primary format used for the underlying data.
// The consumer of the buffer might want to look at this value to know what store
// to use to optimaly retrieve data.
DataType DataFormat
// framePos is the position of the last frame we read
framePos int64
}
// NewPCMIntBuffer returns a new PCM buffer backed by the passed integer samples
func NewPCMIntBuffer(data []int, format *Format) *PCMBuffer {
return &PCMBuffer{
Format: format,
DataType: Integer,
Ints: data,
}
}
// NewPCMFloatBuffer returns a new PCM buffer backed by the passed float samples
func NewPCMFloatBuffer(data []float64, format *Format) *PCMBuffer {
return &PCMBuffer{
Format: format,
DataType: Float,
Floats: data,
}
}
// NewPCMByteBuffer returns a new PCM buffer backed by the passed float samples
func NewPCMByteBuffer(data []byte, format *Format) *PCMBuffer {
return &PCMBuffer{
Format: format,
DataType: Byte,
Bytes: data,
}
}
// Len returns the length of the underlying data.
func (b *PCMBuffer) Len() int {
if b == nil {
return 0
}
switch b.DataType {
case Integer:
return len(b.Ints)
case Float:
return len(b.Floats)
case Byte:
return len(b.Bytes)
default:
return 0
}
}
// Size returns the number of frames contained in the buffer.
func (b *PCMBuffer) Size() (numFrames int) {
if b == nil || b.Format == nil {
return 0
}
numChannels := b.Format.NumChannels
if numChannels == 0 {
numChannels = 1
}
switch b.DataType {
case Integer:
numFrames = len(b.Ints) / numChannels
case Float:
numFrames = len(b.Floats) / numChannels
case Byte:
sampleSize := int((b.Format.BitDepth-1)/8 + 1)
numFrames = (len(b.Bytes) / sampleSize) / numChannels
}
return numFrames
}
// Clone creates a clean clone that can be modified without
// changing the source buffer.
func (b *PCMBuffer) Clone() *PCMBuffer {
if b == nil {
return nil
}
newB := &PCMBuffer{DataType: b.DataType}
switch b.DataType {
case Integer:
newB.Ints = make([]int, len(b.Ints))
copy(newB.Ints, b.Ints)
case Float:
newB.Floats = make([]float64, len(b.Floats))
copy(newB.Floats, b.Floats)
case Byte:
newB.Bytes = make([]byte, len(b.Bytes))
copy(newB.Bytes, b.Bytes)
}
newB.Format = &Format{
NumChannels: b.Format.NumChannels,
SampleRate: b.Format.SampleRate,
BitDepth: b.Format.BitDepth,
Endianness: b.Format.Endianness,
}
return newB
}
// AsInt16s returns the buffer samples as int16 sample values.
func (b *PCMBuffer) AsInt16s() (out []int16) {
if b == nil {
return nil
}
switch b.DataType {
case Integer, Float:
out = make([]int16, len(b.Ints))
for i := 0; i < len(b.Ints); i++ {
out[i] = int16(b.Ints[i])
}
case Byte:
// if the format isn't defined, we can't read the byte data
if b.Format == nil || b.Format.Endianness == nil || b.Format.BitDepth == 0 {
return out
}
bytesPerSample := int((b.Format.BitDepth-1)/8 + 1)
buf := bytes.NewBuffer(b.Bytes)
out := make([]int16, len(b.Bytes)/bytesPerSample)
binary.Read(buf, b.Format.Endianness, &out)
}
return out
}
// AsInt32s returns the buffer samples as int32 sample values.
func (b *PCMBuffer) AsInt32s() (out []int32) {
if b == nil {
return nil
}
switch b.DataType {
case Integer, Float:
out = make([]int32, len(b.Ints))
for i := 0; i < len(b.Ints); i++ {
out[i] = int32(b.Ints[i])
}
case Byte:
// if the format isn't defined, we can't read the byte data
if b.Format == nil || b.Format.Endianness == nil || b.Format.BitDepth == 0 {
return out
}
bytesPerSample := int((b.Format.BitDepth-1)/8 + 1)
buf := bytes.NewBuffer(b.Bytes)
out := make([]int32, len(b.Bytes)/bytesPerSample)
binary.Read(buf, b.Format.Endianness, &out)
}
return out
}
// AsInt64s returns the buffer samples as int64 sample values.
func (b *PCMBuffer) AsInt64s() (out []int64) {
if b == nil {
return nil
}
switch b.DataType {
case Integer, Float:
out = make([]int64, len(b.Ints))
for i := 0; i < len(b.Ints); i++ {
out[i] = int64(b.Ints[i])
}
case Byte:
// if the format isn't defined, we can't read the byte data
if b.Format == nil || b.Format.Endianness == nil || b.Format.BitDepth == 0 {
return out
}
bytesPerSample := int((b.Format.BitDepth-1)/8 + 1)
buf := bytes.NewBuffer(b.Bytes)
out := make([]int64, len(b.Bytes)/bytesPerSample)
binary.Read(buf, b.Format.Endianness, &out)
}
return out
}
// AsInts returns the content of the buffer values as ints.
func (b *PCMBuffer) AsInts() (out []int) {
if b == nil {
return nil
}
switch b.DataType {
case Integer:
return b.Ints
case Float:
out = make([]int, len(b.Floats))
for i := 0; i < len(b.Floats); i++ {
out[i] = int(b.Floats[i])
}
case Byte:
// if the format isn't defined, we can't read the byte data
if b.Format == nil || b.Format.Endianness == nil || b.Format.BitDepth == 0 {
return out
}
bytesPerSample := int((b.Format.BitDepth-1)/8 + 1)
buf := bytes.NewBuffer(b.Bytes)
out := make([]int, len(b.Bytes)/bytesPerSample)
binary.Read(buf, b.Format.Endianness, &out)
}
return out
}
// AsFloat32s returns the buffer samples as float32 sample values.
func (b *PCMBuffer) AsFloat32s() (out []float32) {
if b == nil {
return nil
}
switch b.DataType {
case Integer:
out = make([]float32, len(b.Ints))
for i := 0; i < len(b.Ints); i++ {
out[i] = float32(b.Ints[i])
}
case Float:
out = make([]float32, len(b.Floats))
for i := 0; i < len(b.Floats); i++ {
out[i] = float32(b.Floats[i])
}
case Byte:
// if the format isn't defined, we can't read the byte data
if b.Format == nil || b.Format.Endianness == nil || b.Format.BitDepth == 0 {
return out
}
bytesPerSample := int((b.Format.BitDepth-1)/8 + 1)
buf := bytes.NewBuffer(b.Bytes)
out := make([]int, len(b.Bytes)/bytesPerSample)
binary.Read(buf, b.Format.Endianness, &out)
}
return out
}
// AsFloat64s returns the buffer samples as float64 sample values.
func (b *PCMBuffer) AsFloat64s() (out []float64) {
if b == nil {
return nil
}
switch b.DataType {
case Integer:
out = make([]float64, len(b.Ints))
for i := 0; i < len(b.Ints); i++ {
out[i] = float64(b.Ints[i])
}
case Float:
return b.Floats
case Byte:
// if the format isn't defined, we can't read the byte data
if b.Format == nil || b.Format.Endianness == nil || b.Format.BitDepth == 0 {
return out
}
bytesPerSample := int((b.Format.BitDepth-1)/8 + 1)
buf := bytes.NewBuffer(b.Bytes)
out := make([]int, len(b.Bytes)/bytesPerSample)
binary.Read(buf, b.Format.Endianness, &out)
}
return out
}
// CacheInts ensures that the underlying int store is filled up
// so Ints() can be called knowing that the data is available.
// Note that if the underlying data is changed, it is the caller responsibility
// to refresh the cache.
func (b *PCMBuffer) CacheInts() {
if b == nil || b.DataType == Integer {
return
}
b.Ints = b.AsInts()
}
// CacheFloat64s ensures that the underlying int store is filled up
// so Floats() can be called knowing that the data is available.
// Note that if the underlying data is changed, it is the caller responsibility
// to refresh the cache.
func (b *PCMBuffer) CacheFloat64s() {
if b == nil || b.DataType == Float {
return
}
b.Ints = b.AsInts()
}
// SwitchPrimaryType is a convenience method to switch the primary data type.
// Use this if you process/swap a different type than the original type.
func (b *PCMBuffer) SwitchPrimaryType(t DataFormat) {
if b == nil || t == b.DataType {
return
}
switch t {
case Integer:
b.Ints = b.AsInts()
b.Floats = nil
b.Bytes = nil
case Float:
b.Floats = b.AsFloat64s()
b.Ints = nil
b.Bytes = nil
case Byte:
// TODO: get as bytes
b.Floats = nil
b.Ints = nil
}
b.DataType = t
}