Split CGO audio utilities to its own file
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
16ee9d3e77
commit
578b3f3770
|
@ -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)
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)(¤tFrame.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)(¤tFrame.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 {
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
198
cgo/audio.c
Normal 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
64
cgo/audio.go
Normal 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
|
||||
}
|
195
cgo/audio.h
195
cgo/audio.h
|
@ -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);
|
Loading…
Reference in a new issue