wav icon indicating copy to clipboard operation
wav copied to clipboard

How to write G.711u (ulaw / mulaw) to wav?

Open grokify opened this issue 5 years ago • 0 comments

Issue

I have a 8Khz 8-bit PCM ulaw byte slice that I would like to convert to a WAV file. When I try to convert it using this library, I get audio that is loud and choppy, sounding a bit like the following issue.

https://github.com/go-audio/audio/issues/16

I'm using an Encoder as follows:

wav := NewEncoder(f, 8000, 8, 1, 1)

I'm not quite sure how to convert the raw byte slice into an audio.IntBuffer so I'm doing the following, which results in the poor quality audio.

func BytesToInts(bytes []byte) []int {
	ints := []int{}
	for _, b := range bytes {
		ints = append(ints, int(b))
	}
	return ints
}

func UlawByteSliceToIntBuffer(bytes []byte) *audio.IntBuffer {
	return &audio.IntBuffer{
		Format: &audio.Format{
			NumChannels: 1,
			SampleRate:  8000},
		SourceBitDepth: 8,
		Data:           BytesToInts(bytes)}
}

Any tips on how to get this library to work for this?

Alternative 1 - Works

As an alternative, the following raw approach results in good sounding audio where I can write out the bytes without transformation.

var wavHeaderThin = []byte{0x52, 0x49, 0x46, 0x46, 0x62, 0xb8, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20,
	0x12, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x40, 0x1f, 0x00, 0x00, 0x80, 0x3e, 0x00, 0x00,
	0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x66, 0x61, 0x63, 0x74, 0x04, 0x00, 0x00, 0x00, 0xc5, 0x5b,
	0x00, 0x00, 0x64, 0x61, 0x74, 0x61}

func WriteFileWavFromUlaw(filename string, ulawBytes []byte) error {
	f, err := os.Create(filename)
	if err != nil {
		return err
	}
        defer f.Close()
	_, err = WriteWavFromUlaw(f, ulawBytes)
	return err
}

func WriteWavFromUlaw(w io.Writer, ulawBytes []byte) (n int, err error) {
	n1, err := w.Write(wavHeaderThin)
	if err != nil {
		return n, err
	}
	n += n1
	count := len(ulawBytes)
	n2, err := w.Write([]byte{
		byte(count % 256),
		byte((count >> 8) % 256),
		byte((count >> 16) % 256),
		byte((count >> 24) % 256)})
	if err != nil {
		return n, err
	}
	n += n2
	n3, err := w.Write(ulawBytes)
	if err != nil {
		return n, err
	}
	return n + n3, nil
}

I've added this here for easy reuse:

https://github.com/grokify/simplego/blob/master/audio/ulaw/ulaw.go

Alternative 2 - Works

$ ffmpeg -f mulaw -ar 8000 -i input.ulaw output.wav

grokify avatar Jan 15 '21 01:01 grokify