mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 19:58:54 +01:00
98bfe5a692
This improves the result of examples/piano significantly. The issue of mutexes (#1652) is also resolved by this new implementation. Closes #1652 Closes #1653
275 lines
6.3 KiB
Go
275 lines
6.3 KiB
Go
// Copyright 2021 The Ebiten Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package readerdriver
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
var (
|
|
winmm = windows.NewLazySystemDLL("winmm")
|
|
)
|
|
|
|
var (
|
|
procWaveOutOpen = winmm.NewProc("waveOutOpen")
|
|
procWaveOutClose = winmm.NewProc("waveOutClose")
|
|
procWaveOutPause = winmm.NewProc("waveOutPause")
|
|
procWaveOutPrepareHeader = winmm.NewProc("waveOutPrepareHeader")
|
|
procWaveOutReset = winmm.NewProc("waveOutReset")
|
|
procWaveOutRestart = winmm.NewProc("waveOutRestart")
|
|
procWaveOutUnprepareHeader = winmm.NewProc("waveOutUnprepareHeader")
|
|
procWaveOutWrite = winmm.NewProc("waveOutWrite")
|
|
)
|
|
|
|
type wavehdr struct {
|
|
lpData uintptr
|
|
dwBufferLength uint32
|
|
dwBytesRecorded uint32
|
|
dwUser uintptr
|
|
dwFlags uint32
|
|
dwLoops uint32
|
|
lpNext uintptr
|
|
reserved uintptr
|
|
}
|
|
|
|
type waveformatex struct {
|
|
wFormatTag uint16
|
|
nChannels uint16
|
|
nSamplesPerSec uint32
|
|
nAvgBytesPerSec uint32
|
|
nBlockAlign uint16
|
|
wBitsPerSample uint16
|
|
cbSize uint16
|
|
}
|
|
|
|
const (
|
|
waveFormatPCM = 1
|
|
whdrInqueue = 16
|
|
)
|
|
|
|
type mmresult uint
|
|
|
|
const (
|
|
mmsyserrNoerror mmresult = 0
|
|
mmsyserrError mmresult = 1
|
|
mmsyserrBaddeviceid mmresult = 2
|
|
mmsyserrAllocated mmresult = 4
|
|
mmsyserrInvalidhandle mmresult = 5
|
|
mmsyserrNodriver mmresult = 6
|
|
mmsyserrNomem mmresult = 7
|
|
waverrBadformat mmresult = 32
|
|
waverrStillplaying mmresult = 33
|
|
waverrUnprepared mmresult = 34
|
|
waverrSync mmresult = 35
|
|
)
|
|
|
|
func (m mmresult) String() string {
|
|
switch m {
|
|
case mmsyserrNoerror:
|
|
return "MMSYSERR_NOERROR"
|
|
case mmsyserrError:
|
|
return "MMSYSERR_ERROR"
|
|
case mmsyserrBaddeviceid:
|
|
return "MMSYSERR_BADDEVICEID"
|
|
case mmsyserrAllocated:
|
|
return "MMSYSERR_ALLOCATED"
|
|
case mmsyserrInvalidhandle:
|
|
return "MMSYSERR_INVALIDHANDLE"
|
|
case mmsyserrNodriver:
|
|
return "MMSYSERR_NODRIVER"
|
|
case mmsyserrNomem:
|
|
return "MMSYSERR_NOMEM"
|
|
case waverrBadformat:
|
|
return "WAVERR_BADFORMAT"
|
|
case waverrStillplaying:
|
|
return "WAVERR_STILLPLAYING"
|
|
case waverrUnprepared:
|
|
return "WAVERR_UNPREPARED"
|
|
case waverrSync:
|
|
return "WAVERR_SYNC"
|
|
}
|
|
return fmt.Sprintf("MMRESULT (%d)", m)
|
|
}
|
|
|
|
type winmmError struct {
|
|
fname string
|
|
errno windows.Errno
|
|
mmresult mmresult
|
|
}
|
|
|
|
func (e *winmmError) Error() string {
|
|
if e.errno != 0 {
|
|
return fmt.Sprintf("winmm error at %s: Errno: %d", e.fname, e.errno)
|
|
}
|
|
if e.mmresult != mmsyserrNoerror {
|
|
return fmt.Sprintf("winmm error at %s: %s", e.fname, e.mmresult)
|
|
}
|
|
return fmt.Sprintf("winmm error at %s", e.fname)
|
|
}
|
|
|
|
func waveOutOpen(f *waveformatex, callback uintptr) (uintptr, error) {
|
|
const (
|
|
waveMapper = 0xffffffff
|
|
callbackFunction = 0x30000
|
|
)
|
|
var w uintptr
|
|
var fdwOpen uintptr
|
|
if callback != 0 {
|
|
fdwOpen |= callbackFunction
|
|
}
|
|
r, _, e := procWaveOutOpen.Call(uintptr(unsafe.Pointer(&w)), waveMapper, uintptr(unsafe.Pointer(f)),
|
|
callback, 0, fdwOpen)
|
|
runtime.KeepAlive(f)
|
|
if e.(windows.Errno) != 0 {
|
|
return 0, &winmmError{
|
|
fname: "waveOutOpen",
|
|
errno: e.(windows.Errno),
|
|
}
|
|
}
|
|
if mmresult(r) != mmsyserrNoerror {
|
|
return 0, &winmmError{
|
|
fname: "waveOutOpen",
|
|
mmresult: mmresult(r),
|
|
}
|
|
}
|
|
return w, nil
|
|
}
|
|
|
|
func waveOutClose(hwo uintptr) error {
|
|
r, _, e := procWaveOutClose.Call(hwo)
|
|
if e.(windows.Errno) != 0 {
|
|
return &winmmError{
|
|
fname: "waveOutClose",
|
|
errno: e.(windows.Errno),
|
|
}
|
|
}
|
|
if mmresult(r) != mmsyserrNoerror {
|
|
return &winmmError{
|
|
fname: "waveOutClose",
|
|
mmresult: mmresult(r),
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func waveOutPause(hwo uintptr) error {
|
|
r, _, e := procWaveOutPause.Call(hwo)
|
|
if e.(windows.Errno) != 0 {
|
|
return &winmmError{
|
|
fname: "waveOutPause",
|
|
errno: e.(windows.Errno),
|
|
}
|
|
}
|
|
if mmresult(r) != mmsyserrNoerror {
|
|
return &winmmError{
|
|
fname: "waveOutPause",
|
|
mmresult: mmresult(r),
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func waveOutPrepareHeader(hwo uintptr, pwh *wavehdr) error {
|
|
r, _, e := procWaveOutPrepareHeader.Call(hwo, uintptr(unsafe.Pointer(pwh)), unsafe.Sizeof(wavehdr{}))
|
|
runtime.KeepAlive(pwh)
|
|
if e.(windows.Errno) != 0 {
|
|
return &winmmError{
|
|
fname: "waveOutPrepareHeader",
|
|
errno: e.(windows.Errno),
|
|
}
|
|
}
|
|
if mmresult(r) != mmsyserrNoerror {
|
|
return &winmmError{
|
|
fname: "waveOutPrepareHeader",
|
|
mmresult: mmresult(r),
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func waveOutReset(hwo uintptr) error {
|
|
r, _, e := procWaveOutReset.Call(hwo)
|
|
if e.(windows.Errno) != 0 {
|
|
return &winmmError{
|
|
fname: "waveOutReset",
|
|
errno: e.(windows.Errno),
|
|
}
|
|
}
|
|
if mmresult(r) != mmsyserrNoerror {
|
|
return &winmmError{
|
|
fname: "waveOutReset",
|
|
mmresult: mmresult(r),
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func waveOutRestart(hwo uintptr) error {
|
|
r, _, e := procWaveOutRestart.Call(hwo)
|
|
if e.(windows.Errno) != 0 {
|
|
return &winmmError{
|
|
fname: "waveOutRestart",
|
|
errno: e.(windows.Errno),
|
|
}
|
|
}
|
|
if mmresult(r) != mmsyserrNoerror {
|
|
return &winmmError{
|
|
fname: "waveOutRestart",
|
|
mmresult: mmresult(r),
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func waveOutUnprepareHeader(hwo uintptr, pwh *wavehdr) error {
|
|
r, _, e := procWaveOutUnprepareHeader.Call(hwo, uintptr(unsafe.Pointer(pwh)), unsafe.Sizeof(wavehdr{}))
|
|
runtime.KeepAlive(pwh)
|
|
if e.(windows.Errno) != 0 {
|
|
return &winmmError{
|
|
fname: "waveOutUnprepareHeader",
|
|
errno: e.(windows.Errno),
|
|
}
|
|
}
|
|
if mmresult(r) != mmsyserrNoerror {
|
|
return &winmmError{
|
|
fname: "waveOutUnprepareHeader",
|
|
mmresult: mmresult(r),
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func waveOutWrite(hwo uintptr, pwh *wavehdr) error {
|
|
r, _, e := procWaveOutWrite.Call(hwo, uintptr(unsafe.Pointer(pwh)), unsafe.Sizeof(wavehdr{}))
|
|
runtime.KeepAlive(pwh)
|
|
if e.(windows.Errno) != 0 {
|
|
return &winmmError{
|
|
fname: "waveOutWrite",
|
|
errno: e.(windows.Errno),
|
|
}
|
|
}
|
|
if mmresult(r) != mmsyserrNoerror {
|
|
return &winmmError{
|
|
fname: "waveOutWrite",
|
|
mmresult: mmresult(r),
|
|
}
|
|
}
|
|
return nil
|
|
}
|