//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 }