369 lines
8.1 KiB
Go
369 lines
8.1 KiB
Go
//go:build !cgo
|
|
|
|
package vector
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"golang.org/x/exp/slices"
|
|
"math"
|
|
"runtime"
|
|
"unsafe"
|
|
)
|
|
|
|
func bitsToDiv(b int) float32 {
|
|
return float32((int(1) << (b - 1)) - 1)
|
|
}
|
|
|
|
// MultipleChannelsToMonoFloat32 bring any number of channels to mono, equally weighted
|
|
func MultipleChannelsToMonoFloat32(buffer []float32, channels int) (buf []float32) {
|
|
buf = make([]float32, len(buffer)/channels)
|
|
for i := 0; i < len(buffer); i += channels {
|
|
f := buffer[i]
|
|
for j := 1; j < channels; j++ {
|
|
f += buffer[i+j]
|
|
}
|
|
buf[i/channels] = f / float32(channels)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// MultipleChannelsToStereoFloat32 bring any number of channels to stereo, using downmix formulas when necessary
|
|
func MultipleChannelsToStereoFloat32(buffer []float32, channels int) (buf []float32) {
|
|
if channels != 2 {
|
|
buf = make([]float32, (len(buffer)/channels)*2)
|
|
}
|
|
|
|
var samples int
|
|
surroundMix := 1 / float32(math.Sqrt(2))
|
|
|
|
switch channels {
|
|
case 1: //mono, duplicate channels
|
|
for i := 0; i < len(buffer); i++ {
|
|
buf[i*2] = buffer[i]
|
|
buf[i*2+1] = buffer[i]
|
|
}
|
|
break
|
|
case 2: //copy
|
|
buf = slices.Clone(buffer)
|
|
break
|
|
case 3: //2.1, FL, FR, LFE
|
|
for i := 0; i < len(buffer); i += 3 {
|
|
FL := i
|
|
FR := i + 1
|
|
//LFE := i + 2
|
|
buf[samples*2] = buffer[FL]
|
|
buf[samples*2+1] = buffer[FR]
|
|
samples++
|
|
}
|
|
case 5: //5.0, FL, FR, FC, RL, RR
|
|
for i := 0; i < len(buffer); i += 5 {
|
|
FL := i
|
|
FR := i + 1
|
|
C := i + 2
|
|
RL := i + 3
|
|
RR := i + 4
|
|
//TODO: this is wrong
|
|
buf[samples*2] = buffer[FL] + surroundMix*buffer[C] + surroundMix*buffer[RL]
|
|
buf[samples*2+1] = buffer[FR] + surroundMix*buffer[C] + surroundMix*buffer[RR]
|
|
samples++
|
|
}
|
|
case 6: //5.1, FL, FR, FC, LFE, RL, RR
|
|
for i := 0; i < len(buffer); i += 6 {
|
|
FL := i
|
|
FR := i + 1
|
|
C := i + 2
|
|
//LFE := i + 3
|
|
RL := i + 4
|
|
RR := i + 5
|
|
//TODO: this is wrong
|
|
buf[samples*2] = buffer[FL] + surroundMix*buffer[C] + surroundMix*buffer[RL]
|
|
buf[samples*2+1] = buffer[FR] + surroundMix*buffer[C] + surroundMix*buffer[RR]
|
|
samples++
|
|
}
|
|
break
|
|
default: //no known formula, just take stereo out of it
|
|
for i := 0; i < len(buffer); i += channels {
|
|
buf[samples*2] = buffer[i]
|
|
buf[samples*2+1] = buffer[i+1]
|
|
samples++
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// MultipleChannelsToMonoInt32 bring any number of channels to mono, equally weighted
|
|
func MultipleChannelsToMonoInt32(buffer []int32, channels int) (buf []int32) {
|
|
buf = make([]int32, len(buffer)/channels)
|
|
for i := 0; i < len(buffer); i += channels {
|
|
f := int64(buffer[i])
|
|
for j := 1; j < channels; j++ {
|
|
f += int64(buffer[i+j])
|
|
}
|
|
buf[i/channels] = int32(f / int64(channels))
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// MultipleChannelsToStereoInt32 bring any number of channels to stereo, using downmix formulas when necessary
|
|
func MultipleChannelsToStereoInt32(buffer []int32, channels int) (buf []int32) {
|
|
if channels != 2 {
|
|
buf = make([]int32, (len(buffer)/channels)*2)
|
|
}
|
|
|
|
var samples int
|
|
surroundMix := 1 / float32(math.Sqrt(2))
|
|
|
|
switch channels {
|
|
case 1: //mono, duplicate channels
|
|
for i := 0; i < len(buffer); i++ {
|
|
buf[i*2] = buffer[i]
|
|
buf[i*2+1] = buffer[i]
|
|
}
|
|
break
|
|
case 2: //copy
|
|
buf = slices.Clone(buffer)
|
|
break
|
|
case 3: //2.1, FL, FR, LFE
|
|
for i := 0; i < len(buffer); i += 3 {
|
|
FL := i
|
|
FR := i + 1
|
|
//LFE := i + 2
|
|
buf[samples*2] = buffer[FL]
|
|
buf[samples*2+1] = buffer[FR]
|
|
samples++
|
|
}
|
|
case 5: //5.0, FL, FR, FC, RL, RR
|
|
for i := 0; i < len(buffer); i += 5 {
|
|
FL := i
|
|
FR := i + 1
|
|
C := i + 2
|
|
RL := i + 3
|
|
RR := i + 4
|
|
//TODO: this is wrong
|
|
buf[samples*2] = int32(int64(buffer[FL]) + int64(surroundMix*float32(buffer[C])+surroundMix*float32(buffer[RL])))
|
|
buf[samples*2+1] = int32(int64(buffer[FR]) + int64(surroundMix*float32(buffer[C])+surroundMix*float32(buffer[RR])))
|
|
samples++
|
|
}
|
|
case 6: //5.1, FL, FR, FC, LFE, RL, RR
|
|
for i := 0; i < len(buffer); i += 6 {
|
|
FL := i
|
|
FR := i + 1
|
|
C := i + 2
|
|
//LFE := i + 3
|
|
RL := i + 4
|
|
RR := i + 5
|
|
//TODO: this is wrong
|
|
buf[samples*2] = int32(int64(buffer[FL]) + int64(surroundMix*float32(buffer[C])+surroundMix*float32(buffer[RL])))
|
|
buf[samples*2+1] = int32(int64(buffer[FR]) + int64(surroundMix*float32(buffer[C])+surroundMix*float32(buffer[RR])))
|
|
samples++
|
|
}
|
|
break
|
|
default: //no known formula, just take stereo out of it
|
|
for i := 0; i < len(buffer); i += channels {
|
|
buf[samples*2] = buffer[i]
|
|
buf[samples*2+1] = buffer[i+1]
|
|
samples++
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func Int32ToInt16(data []int32, bitDepth int) (buf []int16) {
|
|
buf = make([]int16, len(data))
|
|
diff := bitDepth - 16
|
|
|
|
if diff >= 0 {
|
|
for i := range data {
|
|
buf[i] = int16(data[i] >> diff)
|
|
}
|
|
} else {
|
|
diff = -diff
|
|
for i := range data {
|
|
buf[i] = int16(data[i] << diff)
|
|
}
|
|
}
|
|
return buf
|
|
}
|
|
|
|
func Int32ToBytes(data []int32, bitDepth int) (buf []byte) {
|
|
buf = make([]byte, len(data)*(bitDepth/8))
|
|
|
|
//element size in bytes, rounded up
|
|
switch bitDepth {
|
|
case 8:
|
|
for i := range data {
|
|
buf[i] = byte(data[i])
|
|
}
|
|
break
|
|
case 16:
|
|
for i := range data {
|
|
binary.LittleEndian.PutUint16(buf[i*2:], uint16(int16(data[i])))
|
|
}
|
|
break
|
|
case 24:
|
|
var tmp [4]byte
|
|
for i := range data {
|
|
binary.LittleEndian.PutUint32(tmp[:], uint32(data[i]))
|
|
copy(buf[i*3:], tmp[:3])
|
|
}
|
|
break
|
|
case 32:
|
|
buf = slices.Clone(unsafe.Slice((*byte)(unsafe.Pointer(unsafe.SliceData(data))), len(data)*4))
|
|
runtime.KeepAlive(data)
|
|
break
|
|
}
|
|
|
|
return buf
|
|
}
|
|
|
|
func BytesToInt32(data []byte, bitDepth int) (buf []int32) {
|
|
buf = make([]int32, len(data)/(bitDepth/8))
|
|
|
|
switch bitDepth {
|
|
case 8:
|
|
for i := 0; i < len(data); i++ {
|
|
buf[i] = int32(data[i])
|
|
}
|
|
break
|
|
case 16:
|
|
for i := 0; i < len(data); i += 2 {
|
|
buf[i/2] = int32(int16(binary.LittleEndian.Uint16(data[i : i+2])))
|
|
}
|
|
break
|
|
case 24:
|
|
{
|
|
var sample uint32
|
|
|
|
for i := 0; i < len(data); i += 3 {
|
|
sample = uint32(data[i])
|
|
sample += uint32(data[i+1]) << 8
|
|
sample += uint32(data[i+2]) << 16
|
|
|
|
/*if sample > (1 << 23) {
|
|
sample = -((1 << 24) - sample)
|
|
}*/
|
|
//sign extend
|
|
buf[i/3] = int32(sample<<8) >> 8
|
|
}
|
|
}
|
|
break
|
|
case 32:
|
|
buf = slices.Clone(unsafe.Slice((*int32)(unsafe.Pointer(unsafe.SliceData(data))), len(data)/4))
|
|
runtime.KeepAlive(data)
|
|
break
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func Int32ToFloat32(data []int32, bitDepth int) (buf []float32) {
|
|
buf = make([]float32, len(data))
|
|
for i := 0; i < len(data); i++ {
|
|
buf[i] = float32(data[i]) / bitsToDiv(bitDepth)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Int24ToFloat32 special case
|
|
func Int24ToFloat32(data []byte, bitDepth int) (buf []float32) {
|
|
buf = make([]float32, len(data)/3)
|
|
var sample uint32
|
|
|
|
for i := 0; i < len(data); i += 3 {
|
|
sample = uint32(data[i])
|
|
sample += uint32(data[i+1]) << 8
|
|
sample += uint32(data[i+2]) << 16
|
|
|
|
//sign extend
|
|
buf[i/3] = (float32(int32(sample<<8) >> 8)) / bitsToDiv(bitDepth)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Int16ToFloat32(data []int16, bitDepth int) (buf []float32) {
|
|
buf = make([]float32, len(data))
|
|
for i := 0; i < len(data); i++ {
|
|
buf[i] = float32(data[i]) / bitsToDiv(bitDepth)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Int8ToFloat32(data []int8, bitDepth int) (buf []float32) {
|
|
buf = make([]float32, len(data))
|
|
|
|
for i := 0; i < len(data); i++ {
|
|
buf[i] = float32(data[i]) / bitsToDiv(bitDepth)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func Float32ToInt32(data []float32, bitDepth int) (buf []int32) {
|
|
buf = make([]int32, len(data))
|
|
for i := 0; i < len(data); i++ {
|
|
f := data[i]
|
|
if f < -1.0 {
|
|
f = -1.0
|
|
}
|
|
if f > 1.0 {
|
|
f = 1.0
|
|
}
|
|
buf[i] = int32(f * bitsToDiv(bitDepth))
|
|
}
|
|
return
|
|
}
|
|
|
|
func Float32ToInt24(data []float32) (buf []byte) {
|
|
buf = make([]byte, len(data)*3)
|
|
|
|
for i := 0; i < len(data); i++ {
|
|
f := data[i]
|
|
if f < -1.0 {
|
|
f = -1.0
|
|
}
|
|
if f > 1.0 {
|
|
f = 1.0
|
|
}
|
|
|
|
value := int32(f * bitsToDiv(24))
|
|
buf[i*3] = byte(value & 0xFF)
|
|
buf[i*3+1] = byte((value >> 8) & 0xFF)
|
|
buf[i*3+2] = byte((value >> 16) & 0xFF)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Float32ToInt16(data []float32) (buf []int16) {
|
|
buf = make([]int16, len(data))
|
|
for i := 0; i < len(data); i++ {
|
|
f := data[i]
|
|
if f < -1.0 {
|
|
f = -1.0
|
|
}
|
|
if f > 1.0 {
|
|
f = 1.0
|
|
}
|
|
buf[i] = int16(f * bitsToDiv(16))
|
|
}
|
|
return
|
|
}
|
|
|
|
func Float32ToInt8(data []float32) (buf []int8) {
|
|
buf = make([]int8, len(data))
|
|
for i := 0; i < len(data); i++ {
|
|
f := data[i]
|
|
if f < -1.0 {
|
|
f = -1.0
|
|
}
|
|
if f > 1.0 {
|
|
f = 1.0
|
|
}
|
|
buf[i] = int8(f * bitsToDiv(8))
|
|
}
|
|
return
|
|
}
|