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

How to play 32 bit floating point audio #570

Open
svenskmand opened this issue May 11, 2023 · 1 comment
Open

How to play 32 bit floating point audio #570

svenskmand opened this issue May 11, 2023 · 1 comment

Comments

@svenskmand
Copy link

Go version: 1.20.4
Go-SDL2 version: v0.4.35
SDL2 version: 2.0.20+dfsg-2build1
OS: Ubuntu 22.04
Architecture: 64 Bit

I am trying to follow the example on how to play audio, and the example works fine, but I would really want to use another format than 8 bit sound. How do I use 32 bit floating point?:

package main

// void SineWave(void *userdata, float *stream, int len);
import "C"
import (
	"log"
	"math"
	"reflect"
	"unsafe"

	"github.com/veandco/go-sdl2/sdl"
)

const (
	toneHz   = 220
	sampleHz = 48000
	dPhase   = 2 * math.Pi * toneHz / sampleHz
)

//export SineWave
func SineWave(userdata unsafe.Pointer, stream *C.float, length C.int) {
	n := int(length)
	hdr := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(stream)), Len: n, Cap: n}
	buf := *(*[]C.float)(unsafe.Pointer(&hdr))

	var phase float64
	for i := 0; i < n; i += 2 {
		phase += dPhase
		sample := C.float((math.Sin(phase) + 0.999999) * 128)
		buf[i] = sample
		buf[i+1] = sample
	}
}

func playTone() {
	if err := sdl.Init(sdl.INIT_AUDIO); err != nil {
		log.Println(err)
		return
	}
	defer sdl.Quit()

	spec := &sdl.AudioSpec{
		Freq:     sampleHz,
		Format:   sdl.AUDIO_F32SYS,
		Channels: 2,
		Samples:  sampleHz,
		Callback: sdl.AudioCallback(C.SineWave),
	}
	if err := sdl.OpenAudio(spec, nil); err != nil {
		log.Println(err)
		return
	}
	sdl.PauseAudio(false)
	sdl.Delay(1000) // play audio for long enough to understand whether it works
	sdl.CloseAudio()
}

func main() {
	// foo := 2.12312
	// var bar C.float = 2.123
	// fmt.Println(foo, bar)
	playTone()
}

I tried simply changing all references to the type C.Uint8 with C.float as this should be the 32 bit floating point number in C, and then i changed the Format field in the AudioSpec to sdl.AUDIO_F32SYS, but unfortunately it does not work, then I just get this segfault when running the program:

unexpected fault address 0x7f9cc205b000
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x2 addr=0x7f9cc205b000 pc=0x4a6015]

goroutine 17 [running, locked to thread]:
runtime.throw({0x4cdc90?, 0x0?})
        /snap/go/current/src/runtime/panic.go:1047 +0x5d fp=0xc000064d58 sp=0xc000064d28 pc=0x447c5d
runtime.sigpanic()
        /snap/go/current/src/runtime/signal_unix.go:851 +0x28a fp=0xc000064db8 sp=0xc000064d58 pc=0x45c26a
main.SineWave(0xc00002a0c0?, 0x0?, 0x1?)
        /home/kejlberg/Documents/dawl/main.go:30 +0xb5 fp=0xc000064e10 sp=0xc000064db8 pc=0x4a6015
_cgoexp_9411f897d225_SineWave(0x4d6928?)
        _cgo_gotypes.go:48 +0x26 fp=0xc000064e38 sp=0xc000064e10 pc=0x4a6286
runtime.cgocallbackg1(0x4a6260, 0x0?, 0x0)
        /snap/go/current/src/runtime/cgocall.go:315 +0x2b1 fp=0xc000064f00 sp=0xc000064e38 pc=0x419911
runtime.cgocallbackg(0x0?, 0x0?, 0x0?)
        /snap/go/current/src/runtime/cgocall.go:234 +0x109 fp=0xc000064f90 sp=0xc000064f00 pc=0x4195c9
runtime.cgocallbackg(0x4a6260, 0x7f9cc1fccc60, 0x0)
        <autogenerated>:1 +0x2f fp=0xc000064fb8 sp=0xc000064f90 pc=0x47724f
runtime.cgocallback(0x0, 0x0, 0x0)
        /snap/go/current/src/runtime/asm_amd64.s:998 +0xb4 fp=0xc000064fe0 sp=0xc000064fb8 pc=0x474b54
runtime.goexit()
        /snap/go/current/src/runtime/asm_amd64.s:1598 +0x1 fp=0xc000064fe8 sp=0xc000064fe0 pc=0x474d81

goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x4acc80, 0xc000065f20)
        /snap/go/current/src/runtime/cgocall.go:157 +0x5c fp=0xc000065ef8 sp=0xc000065ec0 pc=0x41941c
github.com/veandco/go-sdl2/sdl._Cfunc_SDL_Delay(0x3e8)
        _cgo_gotypes.go:3009 +0x45 fp=0xc000065f20 sp=0xc000065ef8 pc=0x4a2d25
github.com/veandco/go-sdl2/sdl.Delay(...)
        /home/kejlberg/GOPATH/pkg/mod/github.com/veandco/go-sdl2@v0.4.35/sdl/timer.go:54
main.playTone()
        /home/kejlberg/Documents/dawl/main.go:54 +0x13f fp=0xc000065f70 sp=0xc000065f20 pc=0x4a61bf
main.main()
        /home/kejlberg/Documents/dawl/main.go:62 +0x17 fp=0xc000065f80 sp=0xc000065f70 pc=0x4a6237
runtime.main()
        /snap/go/current/src/runtime/proc.go:250 +0x207 fp=0xc000065fe0 sp=0xc000065f80 pc=0x44a547
runtime.goexit()
        /snap/go/current/src/runtime/asm_amd64.s:1598 +0x1 fp=0xc000065fe8 sp=0xc000065fe0 pc=0x474d81

goroutine 2 [force gc (idle)]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
        /snap/go/current/src/runtime/proc.go:381 +0xd6 fp=0xc000052fb0 sp=0xc000052f90 pc=0x44a976
runtime.goparkunlock(...)
        /snap/go/current/src/runtime/proc.go:387
runtime.forcegchelper()
        /snap/go/current/src/runtime/proc.go:305 +0xb0 fp=0xc000052fe0 sp=0xc000052fb0 pc=0x44a7b0
runtime.goexit()
        /snap/go/current/src/runtime/asm_amd64.s:1598 +0x1 fp=0xc000052fe8 sp=0xc000052fe0 pc=0x474d81
created by runtime.init.6
        /snap/go/current/src/runtime/proc.go:293 +0x25

goroutine 3 [GC sweep wait]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
        /snap/go/current/src/runtime/proc.go:381 +0xd6 fp=0xc000053780 sp=0xc000053760 pc=0x44a976
runtime.goparkunlock(...)
        /snap/go/current/src/runtime/proc.go:387
runtime.bgsweep(0x0?)
        /snap/go/current/src/runtime/mgcsweep.go:278 +0x8e fp=0xc0000537c8 sp=0xc000053780 pc=0x4376ce
runtime.gcenable.func1()
        /snap/go/current/src/runtime/mgc.go:178 +0x26 fp=0xc0000537e0 sp=0xc0000537c8 pc=0x42cb86
runtime.goexit()
        /snap/go/current/src/runtime/asm_amd64.s:1598 +0x1 fp=0xc0000537e8 sp=0xc0000537e0 pc=0x474d81
created by runtime.gcenable
        /snap/go/current/src/runtime/mgc.go:178 +0x6b

goroutine 4 [GC scavenge wait]:
runtime.gopark(0xc00001c0e0?, 0x4ec2e8?, 0x1?, 0x0?, 0x0?)
        /snap/go/current/src/runtime/proc.go:381 +0xd6 fp=0xc000053f70 sp=0xc000053f50 pc=0x44a976
runtime.goparkunlock(...)
        /snap/go/current/src/runtime/proc.go:387
runtime.(*scavengerState).park(0x579380)
        /snap/go/current/src/runtime/mgcscavenge.go:400 +0x53 fp=0xc000053fa0 sp=0xc000053f70 pc=0x4355f3
runtime.bgscavenge(0x0?)
        /snap/go/current/src/runtime/mgcscavenge.go:628 +0x45 fp=0xc000053fc8 sp=0xc000053fa0 pc=0x435bc5
runtime.gcenable.func2()
        /snap/go/current/src/runtime/mgc.go:179 +0x26 fp=0xc000053fe0 sp=0xc000053fc8 pc=0x42cb26
runtime.goexit()
        /snap/go/current/src/runtime/asm_amd64.s:1598 +0x1 fp=0xc000053fe8 sp=0xc000053fe0 pc=0x474d81
created by runtime.gcenable
        /snap/go/current/src/runtime/mgc.go:179 +0xaa

goroutine 5 [finalizer wait]:
runtime.gopark(0x1a0?, 0x5797c0?, 0x60?, 0x78?, 0xc000052770?)
        /snap/go/current/src/runtime/proc.go:381 +0xd6 fp=0xc000052628 sp=0xc000052608 pc=0x44a976
runtime.runfinq()
        /snap/go/current/src/runtime/mfinal.go:193 +0x107 fp=0xc0000527e0 sp=0xc000052628 pc=0x42bbc7
runtime.goexit()
        /snap/go/current/src/runtime/asm_amd64.s:1598 +0x1 fp=0xc0000527e8 sp=0xc0000527e0 pc=0x474d81
created by runtime.createfing
        /snap/go/current/src/runtime/mfinal.go:163 +0x45

I have not work with Cgo before so I might be missing something completely trivial. Any help here would be awesome :)

@veeableful
Copy link
Contributor

Hi @svenskmand, the function signature of SineWave should stay the same which is:

func SineWave(userdata unsafe.Pointer, stream *C.Uint8, length C.int)

However, you might need to divide the data length by four as C's float is usually four bytes:

n := int(length / 4)

The sample calculation might also need to be modified to:

sample := C.float(math.Sin(phase))

as I'm guessing float audio sample range is only between -1.0 and 1.0.

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

2 participants