code.witches.io/go/sdl2@v0.1.1/audio.go (about) 1 package sdl 2 3 // #include <SDL2/SDL_audio.h> 4 // void callback(void *userdata, Uint8 *stream, int len); 5 import "C" 6 import ( 7 "io" 8 "reflect" 9 "sync" 10 "unsafe" 11 ) 12 13 type AudioCallback func(userData unsafe.Pointer, stream *byte, length int32) 14 15 type AudioSpec struct { 16 Frequency int32 17 Format AudioFormat 18 Channels uint8 19 Silence uint8 20 Samples uint16 21 Padding uint16 22 Size uint32 23 Callback AudioCallback 24 UserData unsafe.Pointer 25 } 26 27 type audioSpec struct { 28 Frequency int32 29 Format AudioFormat 30 Channels uint8 31 Silence uint8 32 Samples uint16 33 Padding uint16 34 Size uint32 35 Callback unsafe.Pointer 36 UserData uintptr 37 } 38 39 type AudioFormat uint16 40 41 const ( 42 AudioU8 AudioFormat = 0x0008 43 AudioS8 AudioFormat = 0x8008 44 AudioU16LSB AudioFormat = 0x0010 45 AudioS16LSB AudioFormat = 0x8010 46 AudioU16MSB AudioFormat = 0x1010 47 AudioS16MSB AudioFormat = 0x9010 48 AudioU16 = AudioU16LSB 49 AudioS16 = AudioS16LSB 50 AudioS32LSB AudioFormat = 0x8020 51 AudioS32MSB AudioFormat = 0x9020 52 AudioS32 = AudioS32LSB 53 AudioF32LSB AudioFormat = 0x8120 54 AudioF32MSB AudioFormat = 0x9120 55 AudioF32 = AudioF32LSB 56 ) 57 58 func GetNumAudioDevices(isCapture bool) int { 59 var capture int 60 if isCapture { 61 capture = 1 62 } 63 return int(C.SDL_GetNumAudioDevices(C.int(capture))) 64 } 65 66 func GetAudioDeviceName(device int, isCapture bool) (string, error) { 67 var capture int 68 if isCapture { 69 capture = 1 70 } 71 ptr := C.SDL_GetAudioDeviceName(C.int(device), C.int(capture)) 72 if ptr == nil { 73 return "", GetError() 74 } 75 return C.GoString(ptr), nil 76 } 77 78 func GetNumAudioDrivers() int { 79 return int(C.SDL_GetNumAudioDrivers()) 80 } 81 82 func GetAudioDriver(index int) (string, error) { 83 nativePtr := C.SDL_GetAudioDriver(C.int(index)) 84 if nativePtr == nil { 85 return "", GetError() 86 } 87 return C.GoString(nativePtr), nil 88 } 89 90 type AudioDeviceID int 91 92 var callbackMutex sync.Mutex 93 var callbackToken uintptr 94 var callbackFuncs = make(map[uintptr]callback) 95 96 type callback struct { 97 Callback AudioCallback 98 UserData unsafe.Pointer 99 } 100 101 //export audioSpecCallback 102 func audioSpecCallback(userData unsafe.Pointer, stream *uint8, len int32) { 103 callbackMutex.Lock() 104 f := callbackFuncs[uintptr(userData)] 105 callbackMutex.Unlock() 106 if f.Callback == nil { 107 panic("unknown callback func") 108 } 109 f.Callback(f.UserData, stream, len) 110 } 111 112 func OpenAudioDevice(device string, isCapture bool, desired, obtained *AudioSpec, allowedChanges int) (AudioDeviceID, error) { 113 nativePtr := C.CString(device) 114 defer C.free(unsafe.Pointer(nativePtr)) 115 var capture int 116 if isCapture { 117 capture = 1 118 } 119 _desired := audioSpec{ 120 Frequency: desired.Frequency, 121 Format: desired.Format, 122 Channels: desired.Channels, 123 Silence: desired.Silence, 124 Samples: desired.Samples, 125 Padding: desired.Padding, 126 Size: desired.Size, 127 } 128 var i uintptr 129 if desired.Callback != nil { 130 callbackMutex.Lock() 131 callbackToken++ 132 i = callbackToken 133 callbackFuncs[i] = struct { 134 Callback AudioCallback 135 UserData unsafe.Pointer 136 }{ 137 Callback: desired.Callback, 138 UserData: desired.UserData, 139 } 140 callbackMutex.Unlock() 141 _desired.Callback = C.callback 142 _desired.UserData = i 143 } 144 var _obtained audioSpec 145 result := AudioDeviceID(C.SDL_OpenAudioDevice( 146 nativePtr, 147 C.int(capture), 148 (*C.SDL_AudioSpec)(unsafe.Pointer(&_desired)), 149 (*C.SDL_AudioSpec)(unsafe.Pointer(&_obtained)), 150 C.int(allowedChanges), 151 )) 152 if result == 0 { 153 return 0, GetError() 154 } 155 *obtained = AudioSpec{ 156 Frequency: _obtained.Frequency, 157 Format: _obtained.Format, 158 Channels: _obtained.Channels, 159 Silence: _obtained.Silence, 160 Samples: _obtained.Samples, 161 Padding: _obtained.Padding, 162 Size: _obtained.Size, 163 } 164 if _obtained.Callback != nil { 165 if _obtained.Callback != C.callback { 166 panic("invalid callback") 167 } 168 f, ok := callbackFuncs[_obtained.UserData] 169 if !ok { 170 panic("unknown callback") 171 } 172 obtained.Callback = f.Callback 173 obtained.UserData = f.UserData 174 } 175 return result, nil 176 } 177 178 func CloseAudioDevice(device AudioDeviceID) { 179 C.SDL_CloseAudioDevice(C.SDL_AudioDeviceID(device)) 180 } 181 182 func PauseAudioDevice(device AudioDeviceID, pause bool) { 183 var pauseOn int 184 if pause { 185 pauseOn = 1 186 } 187 C.SDL_PauseAudioDevice(C.SDL_AudioDeviceID(device), C.int(pauseOn)) 188 } 189 190 func QueueAudio(device AudioDeviceID, data unsafe.Pointer, length int) error { 191 if C.SDL_QueueAudio( 192 C.SDL_AudioDeviceID(device), 193 data, 194 C.Uint32(length), 195 ) != 0 { 196 return GetError() 197 } 198 return nil 199 } 200 201 func LoadWAVRW(ops *RWOps, freeSrc bool, spec *AudioSpec) ([]byte, error) { 202 var local reflect.StringHeader 203 var free int 204 if freeSrc { 205 free = 1 206 } 207 ptr := (*AudioSpec)(unsafe.Pointer(C.SDL_LoadWAV_RW( 208 (*C.struct_SDL_RWops)(unsafe.Pointer(ops)), 209 C.int(free), 210 (*C.struct_SDL_AudioSpec)(unsafe.Pointer(spec)), 211 (**C.Uint8)(noescape(unsafe.Pointer(&local.Data))), 212 (*C.Uint32)(noescape(unsafe.Pointer(&local.Len))), 213 ))) 214 if ptr == nil { 215 return nil, GetError() 216 } 217 length := uint32(local.Len) 218 data := make([]byte, length) 219 copy(data, *(*string)(unsafe.Pointer(&local))) 220 C.SDL_FreeWAV(*(**C.Uint8)(unsafe.Pointer(&local.Data))) 221 return data, nil 222 } 223 224 type audioStream C.SDL_AudioStream 225 226 type AudioStream interface { 227 Put([]byte) error 228 Get([]byte) (int, error) 229 Available() int 230 Flush() error 231 Clear() 232 Free() 233 234 io.Writer 235 io.Reader 236 io.Closer 237 } 238 239 func (s *audioStream) Put(p []byte) error { 240 if C.SDL_AudioStreamPut( 241 (*C.SDL_AudioStream)(unsafe.Pointer(s)), 242 unsafe.Pointer(&p[0]), 243 C.int(len(p)), 244 ) != 0 { 245 return GetError() 246 } 247 return nil 248 } 249 250 func (s *audioStream) Get(p []byte) (n int, err error) { 251 result := int(C.SDL_AudioStreamGet( 252 (*C.SDL_AudioStream)(unsafe.Pointer(s)), 253 unsafe.Pointer(&p[0]), 254 C.int(len(p)), 255 )) 256 if result == -1 { 257 return 0, GetError() 258 } 259 return result, nil 260 } 261 262 func (s *audioStream) Available() int { 263 return int(C.SDL_AudioStreamAvailable((*C.SDL_AudioStream)(unsafe.Pointer(s)))) 264 } 265 266 func (s *audioStream) Flush() error { 267 if C.SDL_AudioStreamFlush((*C.SDL_AudioStream)(unsafe.Pointer(s))) != 0 { 268 return GetError() 269 } 270 return nil 271 } 272 273 func (s *audioStream) Clear() { 274 C.SDL_AudioStreamClear((*C.SDL_AudioStream)(unsafe.Pointer(s))) 275 } 276 277 func (s *audioStream) Free() { 278 C.SDL_FreeAudioStream((*C.SDL_AudioStream)(unsafe.Pointer(s))) 279 } 280 281 func (s *audioStream) Write(p []byte) (n int, err error) { 282 err = s.Put(p) 283 return len(p), err 284 } 285 286 func (s *audioStream) Read(p []byte) (n int, err error) { 287 if len(p) == 0 { 288 return 0, nil 289 } 290 if s.Available() == 0 { 291 return 0, io.EOF 292 } 293 return s.Get(p) 294 } 295 296 func (s *audioStream) Close() error { 297 s.Free() 298 return nil 299 } 300 301 func NewAudioStream(srcFormat AudioFormat, srcChannels, srcRate int, dstFormat AudioFormat, dstChannels, dstRate int) (AudioStream, error) { 302 ptr := (*audioStream)(unsafe.Pointer(C.SDL_NewAudioStream( 303 C.SDL_AudioFormat(srcFormat), 304 C.Uint8(srcChannels), 305 C.int(srcRate), 306 C.SDL_AudioFormat(dstFormat), 307 C.Uint8(dstChannels), 308 C.int(dstRate), 309 ))) 310 if ptr == nil { 311 return nil, GetError() 312 } 313 return ptr, nil 314 }