Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

float32 buffer to int buffer conversation should be corrected #18

Open
chfanghr opened this issue Apr 29, 2019 · 7 comments
Open

float32 buffer to int buffer conversation should be corrected #18

chfanghr opened this issue Apr 29, 2019 · 7 comments

Comments

@chfanghr
Copy link

chfanghr commented Apr 29, 2019

  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
Copy link
Author

chfanghr commented Apr 29, 2019

  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

@egonelbre
Copy link

egonelbre commented Apr 29, 2019

@mattetti
Copy link
Member

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

@chfanghr
Copy link
Author

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

@chfanghr
Copy link
Author

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

@asciifaceman
Copy link

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.

@mattetti
Copy link
Member

mattetti commented May 4, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants