audio icon indicating copy to clipboard operation
audio copied to clipboard

float32 buffer to int buffer conversation should be corrected

Open chfanghr opened this issue 5 years ago • 7 comments

  I wnated to convert an ogg file to aiff format, so I used oggvorbis to decode an ogg audio file and the package give me a decoded float32 array, and then I used go-audio/aiff to encode float32 pcm data to aiff.Later I found that the encoder only accepts an IntBuffer, so I made a FloatBuffer and use its AsIntBuffer method to make a conversation, and this method didn't give me the proper result. I look into the code and found that inside the AsIntBuffer method the float value is simply converted to int using int(float_value). This is absolutly incorrect. After some researches, I wrote this to resolve the problem and lucikly it works fine.

//ignore the magical unsafe statement...
package main

import (
	"io/ioutil"
	"log"
	"reflect"
	"unsafe"
)

func main() {
	//test.raw is a pcm file,format float32
	data, err := ioutil.ReadFile("test.raw")
	if err != nil {
		log.Fatalln(err)
	}
	var f32Buf []float32
	for len(data) > 0 {
		buf := data[:4]
		data = data[4:]
		f := *(*float32)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&buf)).Data))
		f32Buf = append(f32Buf, f)
	}
	iBuf := convert(f32Buf)
	var oBuf []byte
	for _, v := range iBuf {
		header := &reflect.SliceHeader{
			Data: uintptr(unsafe.Pointer(&v)),
			Cap:  2,
			Len:  2,
		}
		oBuf = append(oBuf, *(*[]byte)(unsafe.Pointer(header))...)
	}

	//output is a pcm file,format int
	ioutil.WriteFile("output.raw", oBuf, 0600)
}

func convert(f32buf []float32) (i16Buf []int16) {
	for _, v := range f32buf {
		sample := v * 32767
		i16Buf = append(i16Buf, int16(sample))
	}
	return
}

  I wonder if we can tell that if the current implemation is a bug or not ,but at least the document should be more clear so that people won't be misleading.

chfanghr avatar Apr 29 '19 08:04 chfanghr

  Here is the result.On the left side is the generated one, and the expected one is on the right.

$ od output.raw
$ od expected.raw

image

chfanghr avatar Apr 29 '19 08:04 chfanghr

It's expected to use a transform prior to converting things. https://github.com/go-audio/audio/blob/master/float_buffer.go#L111 and https://godoc.org/github.com/go-audio/transforms#PCMScaleF32

egonelbre avatar Apr 29 '19 11:04 egonelbre

Egon is right and that's obviously confusing... I wonder if we can make the API more obvious or less complicated to use.

mattetti avatar Apr 30 '19 03:04 mattetti

My currnet solution is buggy which introduces too much noise. Actually, we need to do resample for a better result.

chfanghr avatar Apr 30 '19 11:04 chfanghr

I would like to try to implement this stuff these days.

chfanghr avatar Apr 30 '19 12:04 chfanghr

Out of curiosity is it expected that if you have an []int8{1, 2, 3} that it's float32 conversion would be []float32{2, 4, 6}?

Admittedly I simply don't know.

asciifaceman avatar May 04 '19 07:05 asciifaceman

No, the int scale values depend if the bit depth of the package and would be converted to the range -1, 1

mattetti avatar May 04 '19 13:05 mattetti