Split CGO audio utilities to its own file
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
DataHoarder 2022-04-17 19:43:54 +02:00
parent 16ee9d3e77
commit 578b3f3770
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
9 changed files with 297 additions and 281 deletions

View file

@ -1,11 +1,7 @@
package audio
/*
#cgo CFLAGS: -I"${SRCDIR}/../cgo" -march=native -Ofast -std=c99
#include "audio.h"
*/
import "C"
import (
"git.gammaspectra.live/S.O.N.G/Kirika/cgo"
"github.com/dh1tw/gosamplerate"
"log"
"time"
@ -132,10 +128,7 @@ func (f StereoFilter) Process(source Source) Source {
go func() {
defer close(outBlocks)
for block := range source.Blocks {
//bring any number of channels to stereo, using downmix formulas when necessary
buf := make([]float32, (len(block)/source.Channels)*2)
C.audio_multiple_channels_to_stereo((*C.float)(&block[0]), C.size_t(len(block)), (*C.float)(&buf[0]), C.int(source.Channels))
outBlocks <- buf
outBlocks <- cgo.MultipleChannelsToStereo(block, source.Channels)
}
}()
@ -158,9 +151,7 @@ func (f MonoFilter) Process(source Source) Source {
go func() {
defer close(outBlocks)
for block := range source.Blocks {
//bring any number of channels to mono, equally weighted, reusing buffer backwards
C.audio_multiple_channels_to_mono((*C.float)(&block[0]), C.size_t(len(block)), C.int(source.Channels))
outBlocks <- block[0:(len(block) / source.Channels)]
outBlocks <- cgo.MultipleChannelsToMono(block, source.Channels)
}
}()

View file

@ -1,15 +1,11 @@
package aac
/*
#cgo CFLAGS: -I"${SRCDIR}/../../../cgo" -march=native -Ofast -std=c99
#include "audio.h"
*/
import "C"
import (
"errors"
"fmt"
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
"git.gammaspectra.live/S.O.N.G/Kirika/audio/packetizer"
"git.gammaspectra.live/S.O.N.G/Kirika/cgo"
"git.gammaspectra.live/S.O.N.G/go-fdkaac/fdkaac"
"io"
"unsafe"
@ -30,14 +26,7 @@ func decodeFrame(decoder *fdkaac.AacDecoder, p *packetizer.AdtsPacketizer) ([]fl
}
if pcm != nil {
n := len(pcm) / 2
buf := make([]float32, n)
intBuf := make([]int32, n)
C.audio_bytes_to_int32((*C.int8_t)(unsafe.Pointer(&pcm[0])), C.size_t(len(pcm)), (*C.int32_t)(&intBuf[0]), C.int(16))
C.audio_int32_to_float32((*C.int32_t)(&intBuf[0]), C.size_t(n), (*C.float)(&buf[0]), C.int(16))
return buf, nil
return cgo.Int32ToFloat32(cgo.BytesToInt32(pcm, 16), 16), nil
}
packet := p.GetPacket()
@ -162,10 +151,8 @@ func (f Format) Encode(source audio.Source, writer io.WriteCloser, options map[s
var buffer []int16
for block := range source.Blocks {
samples := make([]int16, len(block))
C.audio_float32_to_int16((*C.float)(&block[0]), C.size_t(len(block)), (*C.int16_t)(&samples[0]))
buffer = append(buffer, samples...)
buffer = append(buffer, cgo.Float32ToInt16(block)...)
for len(buffer) >= frameSize {
sl := buffer[:frameSize]

View file

@ -1,14 +1,10 @@
package flac
/*
#cgo CFLAGS: -I"${SRCDIR}/../../../cgo" -march=native -Ofast -std=c99
#include "audio.h"
*/
import "C"
import (
"bytes"
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
"git.gammaspectra.live/S.O.N.G/Kirika/audio/format"
"git.gammaspectra.live/S.O.N.G/Kirika/cgo"
libflac "git.gammaspectra.live/S.O.N.G/goflac"
"io"
)
@ -52,11 +48,7 @@ func (f Format) Open(r io.ReadSeekCloser) (audio.Source, error) {
bitDepth = currentFrame.Depth
}
buf := make([]float32, len(currentFrame.Buffer))
C.audio_int32_to_float32((*C.int32_t)(&currentFrame.Buffer[0]), C.size_t(len(currentFrame.Buffer)), (*C.float)(&buf[0]), C.int(bitDepth))
newChannel <- buf
newChannel <- cgo.Int32ToFloat32(currentFrame.Buffer, bitDepth)
frameNumber++
}
@ -107,11 +99,8 @@ func (f Format) OpenAnalyzer(r io.ReadSeekCloser) (audio.Source, format.Analyzer
channels = currentFrame.Channels
}
buf := make([]float32, len(currentFrame.Buffer))
newChannel <- cgo.Int32ToFloat32(currentFrame.Buffer, bitDepth)
C.audio_int32_to_float32((*C.int32_t)(&currentFrame.Buffer[0]), C.size_t(len(currentFrame.Buffer)), (*C.float)(&buf[0]), C.int(bitDepth))
newChannel <- buf
analyzerChannel <- &format.AnalyzerPacket{
Samples: currentFrame.Buffer,
Channels: channels,
@ -186,15 +175,12 @@ func (f Format) Encode(source audio.Source, writer io.WriteCloser, options map[s
defer encoder.Close()
for block := range source.Blocks {
samples := make([]int32, len(block))
C.audio_float32_to_int32((*C.float)(&block[0]), C.size_t(len(block)), (*C.int32_t)(&samples[0]), C.int(bitsPerSample))
err = encoder.WriteFrame(libflac.Frame{
Rate: source.SampleRate,
Channels: source.Channels,
Depth: bitsPerSample,
Buffer: samples,
Buffer: cgo.Float32ToInt32(block, bitsPerSample),
})
if err != nil {

View file

@ -1,15 +1,11 @@
package mp3
/*
#cgo CFLAGS: -I"${SRCDIR}/../../../cgo" -march=native -Ofast -std=c99
#include "audio.h"
*/
import "C"
import (
"bytes"
"errors"
"fmt"
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
"git.gammaspectra.live/S.O.N.G/Kirika/cgo"
mp3Lib "github.com/kvark128/minimp3"
"github.com/viert/go-lame"
"io"
@ -47,12 +43,8 @@ func (f Format) Open(r io.ReadSeekCloser) (audio.Source, error) {
}
n /= SizeofInt16
buf := make([]float32, n)
//convert 16-bit to f32 samples
C.audio_int16_to_float32((*C.int16_t)(&samples[0]), C.size_t(n), (*C.float)(&buf[0]), C.int(16))
newChannel <- buf
newChannel <- cgo.Int16ToFloat32(samples[:n], 16)
}
}()
@ -145,9 +137,7 @@ func (f Format) Encode(source audio.Source, writer io.WriteCloser, options map[s
}
for block := range source.Blocks {
samples := make([]int16, len(block))
C.audio_float32_to_int16((*C.float)(&block[0]), C.size_t(len(block)), (*C.int16_t)(&samples[0]))
samples := cgo.Float32ToInt16(block)
_, err := encoder.Write(unsafe.Slice((*byte)(unsafe.Pointer(&samples[0])), len(samples)*2))

View file

@ -1,14 +1,10 @@
package opus
/*
#cgo CFLAGS: -I"${SRCDIR}/../../../cgo" -march=native -Ofast -std=c99
#include "audio.h"
*/
import "C"
import (
"bytes"
"fmt"
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
"git.gammaspectra.live/S.O.N.G/Kirika/cgo"
libopus "git.gammaspectra.live/S.O.N.G/go-pus"
"io"
)
@ -43,11 +39,8 @@ func (f Format) Open(r io.ReadSeekCloser) (audio.Source, error) {
return
}
buffer := make([]float32, n*2)
C.audio_int16_to_float32((*C.int16_t)(&buf[0]), C.size_t(n*2), (*C.float)(&buffer[0]), C.int(16))
if n > 0 {
newChannel <- buffer
newChannel <- cgo.Int16ToFloat32(buf[:n*2], 16)
}
}
}()
@ -120,11 +113,7 @@ func (f Format) Encode(source audio.Source, writer io.WriteCloser, options map[s
}
for block := range source.Blocks {
samples := make([]int16, len(block))
C.audio_float32_to_int16((*C.float)(&block[0]), C.size_t(len(block)), (*C.int16_t)(&samples[0]))
err = encoder.Encode(samples)
err = encoder.Encode(cgo.Float32ToInt16(block))
if err != nil {
return err
}

View file

@ -1,15 +1,11 @@
package tta
/*
#cgo CFLAGS: -I"${SRCDIR}/../../../cgo" -march=native -Ofast -std=c99
#include "audio.h"
*/
import "C"
import (
"bytes"
"errors"
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
"git.gammaspectra.live/S.O.N.G/Kirika/audio/format"
"git.gammaspectra.live/S.O.N.G/Kirika/cgo"
libtta "git.gammaspectra.live/S.O.N.G/go-tta"
"io"
"math"
@ -89,17 +85,17 @@ func (f Format) Open(r io.ReadSeekCloser) (audio.Source, error) {
bitDepth := int(info.Bps)
nsamples := len(bufferSlice) / (bitDepth / 8)
buf := make([]float32, nsamples)
var buf []float32
switch bitDepth {
case 32:
C.audio_int32_to_float32((*C.int32_t)(unsafe.Pointer(&bufferSlice[0])), C.size_t(nsamples), (*C.float)(&buf[0]), C.int(bitDepth))
buf = cgo.Int32ToFloat32(unsafe.Slice((*int32)(unsafe.Pointer(&bufferSlice[0])), nsamples), bitDepth)
case 24:
C.audio_int24_to_float32((*C.int8_t)(unsafe.Pointer(&bufferSlice[0])), C.size_t(nsamples*3), (*C.float)(&buf[0]), C.int(bitDepth))
buf = cgo.Int24ToFloat32(unsafe.Slice((*byte)(unsafe.Pointer(&bufferSlice[0])), nsamples*3), bitDepth)
case 16:
C.audio_int16_to_float32((*C.int16_t)(unsafe.Pointer(&bufferSlice[0])), C.size_t(nsamples), (*C.float)(&buf[0]), C.int(bitDepth))
buf = cgo.Int16ToFloat32(unsafe.Slice((*int16)(unsafe.Pointer(&bufferSlice[0])), nsamples), bitDepth)
case 8:
C.audio_int8_to_float32((*C.int8_t)(unsafe.Pointer(&bufferSlice[0])), C.size_t(nsamples), (*C.float)(&buf[0]), C.int(bitDepth))
buf = cgo.Int8ToFloat32(unsafe.Slice((*int8)(unsafe.Pointer(&bufferSlice[0])), nsamples), bitDepth)
}
newChannel <- buf
@ -139,20 +135,13 @@ func (f Format) OpenAnalyzer(r io.ReadSeekCloser) (audio.Source, format.Analyzer
break
}
bufferSlice := buffer[:writeLen]
bitDepth := int(info.Bps)
nsamples := len(bufferSlice) / (bitDepth / 8)
buf := make([]float32, nsamples)
intBuf := make([]int32, nsamples)
intSamples := cgo.BytesToInt32(buffer[:writeLen], bitDepth)
newChannel <- cgo.Int32ToFloat32(intSamples, bitDepth)
C.audio_bytes_to_int32((*C.int8_t)(unsafe.Pointer(&bufferSlice[0])), C.size_t(len(bufferSlice)), (*C.int32_t)(&intBuf[0]), C.int(bitDepth))
C.audio_int32_to_float32((*C.int32_t)(&intBuf[0]), C.size_t(len(intBuf)), (*C.float)(&buf[0]), C.int(bitDepth))
newChannel <- buf
analyzerChannel <- &format.AnalyzerPacket{
Samples: intBuf,
Samples: intSamples,
Channels: int(info.Nch),
BitDepth: bitDepth,
SampleRate: int(info.Sps),
@ -213,9 +202,8 @@ func (f Format) Encode(source audio.Source, writer io.WriteCloser, options map[s
}
for block := range source.Blocks {
samples := make([]int16, len(block))
C.audio_float32_to_int16((*C.float)(&block[0]), C.size_t(len(block)), (*C.int16_t)(&samples[0]))
samples := cgo.Float32ToInt16(block)
encoder.ProcessStream(unsafe.Slice((*byte)(unsafe.Pointer(&samples[0])), len(samples)*2), nil)
}

198
cgo/audio.c Normal file
View file

@ -0,0 +1,198 @@
#include "audio.h"
#include <math.h>
void audio_multiple_channels_to_mono(float* buffer, size_t buffer_len, int channels) {
float f;
switch(channels) {
case 1:
break;
case 2:
for (int i = 0; i < buffer_len; i += 2){
buffer[i/2] = buffer[i] + buffer[i+1];
}
break;
default:
for (int i = 0; i < buffer_len; i += channels){
f = buffer[i];
for (int j = 1; j < channels; ++j) {
f += buffer[i + j];
}
buffer[i/channels] = f / (float)channels;
}
}
}
void audio_multiple_channels_to_stereo(float* buffer, size_t buffer_len, float* out, int channels) {
float f;
int samples = 0;
float surroundMix = 1 / sqrt(2);
switch(channels) {
case 1: //mono, duplicate channels
for (int i = 0; i < buffer_len; i++){
out[i*2] = buffer[i];
out[i*2+1] = buffer[i];
}
break;
case 2: //copy
memcpy(out, buffer, sizeof(float) * buffer_len);
break;
case 3: //2.1, FL, FR, LFE
for (int i = 0; i < buffer_len; i += 3){
int FL = i;
int FR = i+1;
int LFE = i+2;
out[samples*2] = buffer[FL];
out[samples*2+1] = buffer[FR];
++samples;
}
case 5: //5.0, FL, FR, FC, RL, RR
for (int i = 0; i < buffer_len; i += 5){
int FL = i;
int FR = i+1;
int C = i+2;
int RL = i+3;
int RR = i+4;
out[samples*2] = buffer[FL] + surroundMix * buffer[C] + surroundMix * RL;
out[samples*2+1] = buffer[FR] + surroundMix * buffer[C] + surroundMix * RR;
++samples;
}
case 6: //5.1, FL, FR, FC, LFE, RL, RR
for (int i = 0; i < buffer_len; i += 6){
int FL = i;
int FR = i+1;
int C = i+2;
int LFE = i+3;
int RL = i+4;
int RR = i+5;
out[samples*2] = buffer[FL] + surroundMix * buffer[C] + surroundMix * RL;
out[samples*2+1] = buffer[FR] + surroundMix * buffer[C] + surroundMix * RR;
++samples;
}
break;
default: //no known formula, just take stereo out of it
for (int i = 0; i < buffer_len; i += channels){
out[samples*2] = buffer[i];
out[samples*2+1] = buffer[i+1];
++samples;
}
}
}
void audio_bytes_to_int32(int8_t* restrict data, size_t data_len, int32_t* restrict buffer, int bitDepth){
switch(bitDepth) {
case 8:
for (int i = 0; i < data_len; i++){
buffer[i] = data[i];
}
break;
case 16:
for (int i = 0; i < data_len/2; i++){
buffer[i] = ((int16_t*)data)[i];
}
break;
case 24:
{
uint32_t sample;
for (int i = 0; i < data_len; i += 3){
sample = data[i];
sample += ((uint32_t) data[i+1]) << 8;
sample += ((uint32_t) data[i+2]) << 16;
//sign extend
buffer[i/3] = (int32_t)(sample << 8) >> 8;
}
}
break;
case 32:
memcpy(buffer, data, data_len);
break;
}
}
void audio_int32_to_float32(int32_t* restrict data, size_t data_len, float* restrict buffer, int bitDepth){
switch(bitDepth) {
case 16:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(16);
}
break;
case 24:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(24);
}
break;
default:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(bitDepth);
}
}
}
//special case
void audio_int24_to_float32(int8_t* restrict data, size_t data_len, float* restrict buffer, int bitDepth){
uint32_t sample;
for (int i = 0; i < data_len; i += 3){
sample = data[i];
sample += ((uint32_t) data[i+1]) << 8;
sample += ((uint32_t) data[i+2]) << 16;
//sign extend
buffer[i/3] = ((float)((int32_t)(sample << 8) >> 8)) / BITS_TO_DIV(bitDepth);
}
}
void audio_int16_to_float32(int16_t* restrict data, size_t data_len, float* restrict buffer, int bitDepth){
switch(bitDepth) {
case 16:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(16);
}
break;
default:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(bitDepth);
}
}
}
void audio_int8_to_float32(int8_t* restrict data, size_t data_len, float* restrict buffer, int bitDepth){
switch(bitDepth) {
case 8:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(8);
}
break;
default:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(bitDepth);
}
}
}
void audio_float32_to_int32(float* restrict data, size_t data_len, int32_t* restrict buffer, int bitDepth){
for (int i = 0; i < data_len; ++i){
float f = data[i];
if (f < -1.0) {
f = -1.0;
}
if (f > 1.0) {
f = 1.0;
}
buffer[i] = (int32_t)(f * BITS_TO_DIV(bitDepth));
}
}
void audio_float32_to_int16(float* restrict data, size_t data_len, int16_t* restrict buffer){
for (int i = 0; i < data_len; ++i){
float f = data[i];
if (f < -1.0) {
f = -1.0;
}
if (f > 1.0) {
f = 1.0;
}
buffer[i] = (int16_t)(f * BITS_TO_DIV(16));
}
}

64
cgo/audio.go Normal file
View file

@ -0,0 +1,64 @@
package cgo
/*
#cgo CFLAGS: -march=native -Ofast -std=c99
#include "audio.h"
*/
import "C"
import "unsafe"
//MultipleChannelsToMono bring any number of channels to mono, equally weighted, reusing buffer backwards
func MultipleChannelsToMono(buffer []float32, channels int) []float32 {
C.audio_multiple_channels_to_mono((*C.float)(&buffer[0]), C.size_t(len(buffer)), C.int(channels))
return buffer[0:(len(buffer) / channels)]
}
//MultipleChannelsToStereo bring any number of channels to stereo, using downmix formulas when necessary
func MultipleChannelsToStereo(buffer []float32, channels int) (buf []float32) {
buf = make([]float32, (len(buffer)/channels)*2)
C.audio_multiple_channels_to_stereo((*C.float)(&buffer[0]), C.size_t(len(buffer)), (*C.float)(&buf[0]), C.int(channels))
return
}
func BytesToInt32(data []byte, bitDepth int) (buf []int32) {
buf = make([]int32, len(data)/(bitDepth/8))
C.audio_bytes_to_int32((*C.int8_t)(unsafe.Pointer(&data[0])), C.size_t(len(data)), (*C.int32_t)(&buf[0]), C.int(bitDepth))
return
}
func Int32ToFloat32(data []int32, bitDepth int) (buf []float32) {
buf = make([]float32, len(data))
C.audio_int32_to_float32((*C.int32_t)(&data[0]), C.size_t(len(data)), (*C.float)(&buf[0]), C.int(bitDepth))
return
}
//Int24ToFloat32 special case
func Int24ToFloat32(data []byte, bitDepth int) (buf []float32) {
buf = make([]float32, len(data)/3)
C.audio_int24_to_float32((*C.int8_t)(unsafe.Pointer(&data[0])), C.size_t(len(data)), (*C.float)(&buf[0]), C.int(bitDepth))
return
}
func Int16ToFloat32(data []int16, bitDepth int) (buf []float32) {
buf = make([]float32, len(data))
C.audio_int16_to_float32((*C.int16_t)(&data[0]), C.size_t(len(data)), (*C.float)(&buf[0]), C.int(bitDepth))
return
}
func Int8ToFloat32(data []int8, bitDepth int) (buf []float32) {
buf = make([]float32, len(data))
C.audio_int8_to_float32((*C.int8_t)(&data[0]), C.size_t(len(data)), (*C.float)(&buf[0]), C.int(bitDepth))
return
}
func Float32ToInt32(data []float32, bitDepth int) (buf []int32) {
buf = make([]int32, len(data))
C.audio_float32_to_int32((*C.float)(&data[0]), C.size_t(len(data)), (*C.int32_t)(&buf[0]), C.int(bitDepth))
return
}
func Float32ToInt16(data []float32) (buf []int16) {
buf = make([]int16, len(data))
C.audio_float32_to_int16((*C.float)(&data[0]), C.size_t(len(data)), (*C.int16_t)(&buf[0]))
return
}

View file

@ -1,201 +1,24 @@
#include <stdint.h>
#include <string.h>
#include <math.h>
#define BITS_TO_DIV(b) (float)((1 << (b - 1)) - 1)
__attribute__((weak)) void audio_multiple_channels_to_mono(float* buffer, size_t buffer_len, int channels) {
float f;
switch(channels) {
case 1:
break;
case 2:
for (int i = 0; i < buffer_len; i += 2){
buffer[i/2] = buffer[i] + buffer[i+1];
}
break;
default:
for (int i = 0; i < buffer_len; i += channels){
f = buffer[i];
for (int j = 1; j < channels; ++j) {
f += buffer[i + j];
}
buffer[i/channels] = f / (float)channels;
}
}
}
void audio_multiple_channels_to_mono(float* buffer, size_t buffer_len, int channels);
__attribute__((weak)) void audio_multiple_channels_to_stereo(float* buffer, size_t buffer_len, float* out, int channels) {
float f;
int samples = 0;
float surroundMix = 1 / sqrt(2);
switch(channels) {
case 1: //mono, duplicate channels
for (int i = 0; i < buffer_len; i++){
out[i*2] = buffer[i];
out[i*2+1] = buffer[i];
}
break;
case 2: //copy
memcpy(out, buffer, sizeof(float) * buffer_len);
break;
case 3: //2.1, FL, FR, LFE
for (int i = 0; i < buffer_len; i += 3){
int FL = i;
int FR = i+1;
int LFE = i+2;
out[samples*2] = buffer[FL];
out[samples*2+1] = buffer[FR];
++samples;
}
case 5: //5.0, FL, FR, FC, RL, RR
for (int i = 0; i < buffer_len; i += 5){
int FL = i;
int FR = i+1;
int C = i+2;
int RL = i+3;
int RR = i+4;
out[samples*2] = buffer[FL] + surroundMix * buffer[C] + surroundMix * RL;
out[samples*2+1] = buffer[FR] + surroundMix * buffer[C] + surroundMix * RR;
++samples;
}
case 6: //5.1, FL, FR, FC, LFE, RL, RR
for (int i = 0; i < buffer_len; i += 6){
int FL = i;
int FR = i+1;
int C = i+2;
int LFE = i+3;
int RL = i+4;
int RR = i+5;
out[samples*2] = buffer[FL] + surroundMix * buffer[C] + surroundMix * RL;
out[samples*2+1] = buffer[FR] + surroundMix * buffer[C] + surroundMix * RR;
++samples;
}
break;
default: //no known formula, just take stereo out of it
for (int i = 0; i < buffer_len; i += channels){
out[samples*2] = buffer[i];
out[samples*2+1] = buffer[i+1];
++samples;
}
}
}
void audio_multiple_channels_to_stereo(float* buffer, size_t buffer_len, float* out, int channels);
__attribute__((weak)) void audio_bytes_to_int32(int8_t* restrict data, size_t data_len, int32_t* restrict buffer, int bitDepth){
switch(bitDepth) {
case 8:
for (int i = 0; i < data_len; i++){
buffer[i] = data[i];
}
break;
case 16:
for (int i = 0; i < data_len/2; i++){
buffer[i] = ((int16_t*)data)[i];
}
break;
case 24:
{
uint32_t sample;
void audio_bytes_to_int32(int8_t* restrict data, size_t data_len, int32_t* restrict buffer, int bitDepth);
for (int i = 0; i < data_len; i += 3){
sample = data[i];
sample += ((uint32_t) data[i+1]) << 8;
sample += ((uint32_t) data[i+2]) << 16;
//sign extend
buffer[i/3] = (int32_t)(sample << 8) >> 8;
}
}
break;
case 32:
memcpy(buffer, data, data_len);
break;
}
}
__attribute__((weak)) void audio_int32_to_float32(int32_t* restrict data, size_t data_len, float* restrict buffer, int bitDepth){
switch(bitDepth) {
case 16:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(16);
}
break;
case 24:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(24);
}
break;
default:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(bitDepth);
}
}
}
void audio_int32_to_float32(int32_t* restrict data, size_t data_len, float* restrict buffer, int bitDepth);
//special case
__attribute__((weak)) void audio_int24_to_float32(int8_t* restrict data, size_t data_len, float* restrict buffer, int bitDepth){
uint32_t sample;
void audio_int24_to_float32(int8_t* restrict data, size_t data_len, float* restrict buffer, int bitDepth);
for (int i = 0; i < data_len; i += 3){
sample = data[i];
sample += ((uint32_t) data[i+1]) << 8;
sample += ((uint32_t) data[i+2]) << 16;
void audio_int16_to_float32(int16_t* restrict data, size_t data_len, float* restrict buffer, int bitDepth);
//sign extend
buffer[i/3] = ((float)((int32_t)(sample << 8) >> 8)) / BITS_TO_DIV(bitDepth);
}
}
void audio_int8_to_float32(int8_t* restrict data, size_t data_len, float* restrict buffer, int bitDepth);
__attribute__((weak)) void audio_int16_to_float32(int16_t* restrict data, size_t data_len, float* restrict buffer, int bitDepth){
switch(bitDepth) {
case 16:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(16);
}
break;
default:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(bitDepth);
}
}
}
void audio_float32_to_int32(float* restrict data, size_t data_len, int32_t* restrict buffer, int bitDepth);
__attribute__((weak)) void audio_int8_to_float32(int8_t* restrict data, size_t data_len, float* restrict buffer, int bitDepth){
switch(bitDepth) {
case 8:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(8);
}
break;
default:
for (int i = 0; i < data_len; ++i){
buffer[i] = ((float)data[i]) / BITS_TO_DIV(bitDepth);
}
}
}
__attribute__((weak)) void audio_float32_to_int32(float* restrict data, size_t data_len, int32_t* restrict buffer, int bitDepth){
for (int i = 0; i < data_len; ++i){
float f = data[i];
if (f < -1.0) {
f = -1.0;
}
if (f > 1.0) {
f = 1.0;
}
buffer[i] = (int32_t)(f * BITS_TO_DIV(bitDepth));
}
}
__attribute__((weak)) void audio_float32_to_int16(float* restrict data, size_t data_len, int16_t* restrict buffer){
for (int i = 0; i < data_len; ++i){
float f = data[i];
if (f < -1.0) {
f = -1.0;
}
if (f > 1.0) {
f = 1.0;
}
buffer[i] = (int16_t)(f * BITS_TO_DIV(16));
}
}
void audio_float32_to_int16(float* restrict data, size_t data_len, int16_t* restrict buffer);