audio
audio copied to clipboard
float32 buffer to int buffer conversation should be corrected
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.
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
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
Egon is right and that's obviously confusing... I wonder if we can make the API more obvious or less complicated to use.
My currnet solution is buggy which introduces too much noise. Actually, we need to do resample for a better result.
I would like to try to implement this stuff these days.
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.
No, the int scale values depend if the bit depth of the package and would be converted to the range -1, 1