diff --git a/audio.go b/audio.go index 531fc89..bdadbf7 100644 --- a/audio.go +++ b/audio.go @@ -2,6 +2,7 @@ package audio import ( "errors" + "reflect" ) var ( @@ -32,4 +33,7 @@ type Buffer interface { // Clone creates a clean clone that can be modified without // changing the source buffer. Clone() Buffer + // Type returns a reflect value for determining the type + // for on the fly conversions + Type() reflect.Kind } diff --git a/float_buffer.go b/float_buffer.go index 8698810..6949876 100644 --- a/float_buffer.go +++ b/float_buffer.go @@ -1,5 +1,7 @@ package audio +import "reflect" + var _ Buffer = (*FloatBuffer)(nil) var _ Buffer = (*Float32Buffer)(nil) @@ -74,6 +76,11 @@ func (buf *FloatBuffer) NumFrames() int { return len(buf.Data) / numChannels } +// Type returns the type of this buffer +func (buf *FloatBuffer) Type() reflect.Kind { + return reflect.Float64 +} + // Float32Buffer is an audio buffer with its PCM data formatted as float32. type Float32Buffer struct { // Format is the representation of the underlying data format @@ -154,3 +161,8 @@ func (buf *Float32Buffer) NumFrames() int { return len(buf.Data) / numChannels } + +// Type returns the type of this buffer +func (buf *Float32Buffer) Type() reflect.Kind { + return reflect.Float32 +} diff --git a/float_buffer_test.go b/float_buffer_test.go index 3b999c6..95b4a74 100644 --- a/float_buffer_test.go +++ b/float_buffer_test.go @@ -97,10 +97,16 @@ func TestFloat32Buffer(t *testing.T) { if !reflect.DeepEqual(fb64.Data, tt.f64) { t.Errorf("Expected %+v got %+v", tt.f64, fb64.Data) } + if fb64.Type() != reflect.Float64 { + t.Errorf("buffer was improperly typed: %v", fb64.Type()) + } integer := fb.AsIntBuffer() if !reflect.DeepEqual(integer.Data, tt.integer) { t.Errorf("Expected %+v got %+v", tt.integer, integer.Data) } + if integer.Type() != reflect.Int { + t.Errorf("buffer was improperly typed: %v", integer.Type()) + } }) } } diff --git a/int_buffer.go b/int_buffer.go index fccd1de..2d065f6 100644 --- a/int_buffer.go +++ b/int_buffer.go @@ -1,6 +1,9 @@ package audio -import "math" +import ( + "math" + "reflect" +) var _ Buffer = (*IntBuffer)(nil) @@ -104,3 +107,8 @@ func (buf *IntBuffer) Clone() Buffer { } return newB } + +// Type returns the type of this buffer +func (buf *IntBuffer) Type() reflect.Kind { + return reflect.Int +} diff --git a/int_buffer_test.go b/int_buffer_test.go index 2133858..04c840c 100644 --- a/int_buffer_test.go +++ b/int_buffer_test.go @@ -1,6 +1,7 @@ package audio import ( + "reflect" "testing" ) @@ -36,6 +37,20 @@ func TestIntBuffer_AsFloat32Buffer(t *testing.T) { t.Errorf("%d was converted out of range to %f", intData[i], f) } } + if got.Type() != reflect.Float32 { + t.Errorf("buffer was improperly typed: %v", got.Type()) + } + + gotb := got.Clone() + got64 := gotb.AsFloatBuffer() + for i, f := range got64.Data { + if f < -1.0 || f > 1.0 { + t.Errorf("%d was converted out of range to %f", intData[i], f) + } + } + if got64.Type() != reflect.Float64 { + t.Errorf("buffer was improperly typed: %v", got64.Type()) + } }) } } diff --git a/pcm_buffer.go b/pcm_buffer.go index dae22ef..2cc84bc 100644 --- a/pcm_buffer.go +++ b/pcm_buffer.go @@ -1,6 +1,9 @@ package audio -import "math" +import ( + "math" + "reflect" +) // PCMDataFormat is an enum type to indicate the underlying data format used. type PCMDataFormat uint8 @@ -459,3 +462,26 @@ func (b *PCMBuffer) calculateIntBitDepth() uint8 { return bitDepth } + +// Type returns the type of this buffer +func (b *PCMBuffer) Type() reflect.Kind { + if b == nil { + return reflect.Invalid + } + + switch b.DataType { + case DataTypeI8: + return reflect.Int8 + case DataTypeI16: + return reflect.Int16 + case DataTypeI32: + return reflect.Int32 + case DataTypeF32: + return reflect.Float32 + case DataTypeF64: + return reflect.Float64 + default: + return reflect.Invalid + } + +} diff --git a/pcm_buffer_test.go b/pcm_buffer_test.go new file mode 100644 index 0000000..2e402dc --- /dev/null +++ b/pcm_buffer_test.go @@ -0,0 +1,60 @@ +package audio + +import ( + "reflect" + "testing" +) + +func TestPCMBuffer_AsFloatBuffer(t *testing.T) { + tests := []struct { + name string + datatype PCMDataFormat + bd uint8 + i8 []int8 + i16 []int16 + i32 []int32 + f32 []float32 + f64 []float64 + }{ + {"int8 conversion", DataTypeI8, 1, []int8{1, 2, 3}, []int16{1, 2, 3}, []int32{1, 2, 3}, []float32{2, 4, 6}, []float64{2, 4, 6}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pcmb := PCMBuffer{ + Format: FormatMono22500, + I8: tt.i8, + SourceBitDepth: tt.bd, + DataType: tt.datatype, + } + + // I'm unsure if the actual behavior is for int8 individual + // data to double the way it did + // 1,2,3 => 2,4,6 + pcmb32 := pcmb.AsFloat32Buffer() + if !reflect.DeepEqual(pcmb32.Data, tt.f32) { + t.Errorf("Expected %+v got %+v", tt.f32, pcmb32.Data) + } + pcmb64 := pcmb.AsFloatBuffer() + if !reflect.DeepEqual(pcmb64.Data, tt.f64) { + t.Errorf("Expected %+v got %+v", tt.f64, pcmb64.Data) + } + + if !reflect.DeepEqual(pcmb.AsI16(), tt.i16) { + t.Errorf("Expected %+v got %+v", tt.i8, pcmb.AsI16()) + } + if !reflect.DeepEqual(pcmb.AsI32(), tt.i32) { + t.Errorf("Expected %+v got %+v", tt.i32, pcmb.AsI32()) + } + if pcmb.Type() != reflect.Int8 { + t.Errorf("buffer was improperly typed: %v", pcmb.Type()) + } + if pcmb32.Type() != reflect.Float32 { + t.Errorf("buffer was improperly typed: %v", pcmb32.Type()) + } + if pcmb64.Type() != reflect.Float64 { + t.Errorf("buffer was improperly typed: %v", pcmb64.Type()) + } + }) + } + +}