mirror of
https://github.com/kbeckmann/game-and-watch-retro-go.git
synced 2025-12-16 13:15:55 +01:00
259 lines
6.4 KiB
C
259 lines
6.4 KiB
C
/* MikMod sound library
|
|
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
|
|
complete list.
|
|
|
|
This library is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Library General Public License as
|
|
published by the Free Software Foundation; either version 2 of
|
|
the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
02111-1307, USA.
|
|
*/
|
|
|
|
/*==============================================================================
|
|
|
|
$Id$
|
|
|
|
Driver for output on win32 platforms using the multimedia API
|
|
|
|
==============================================================================*/
|
|
|
|
/*
|
|
|
|
Written by Bjornar Henden <bhenden@online.no>
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "mikmod_internals.h"
|
|
|
|
#ifdef DRV_WIN
|
|
|
|
#include <windows.h>
|
|
|
|
#if defined(_MSC_VER)
|
|
#pragma comment(lib,"winmm.lib")
|
|
#if (_MSC_VER < 1300)
|
|
typedef DWORD DWORD_PTR;
|
|
#endif
|
|
#endif
|
|
|
|
/* PF_XMMI64_INSTRUCTIONS_AVAILABLE not in all SDKs. */
|
|
#ifndef PF_XMMI64_INSTRUCTIONS_AVAILABLE
|
|
#define PF_XMMI64_INSTRUCTIONS_AVAILABLE 10
|
|
#endif
|
|
|
|
#ifndef WAVE_FORMAT_IEEE_FLOAT
|
|
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
|
|
#endif
|
|
|
|
#define MINBUFFERS 2 /* min number of buffers */
|
|
#define MAXBUFFERS 16 /* max number of buffers */
|
|
#define MINBUFFERSIZE_MS 50 /* min buffer size in milliseconds */
|
|
#define MAXBUFFERSIZE_MS 1000 /* max buffer size in milliseconds */
|
|
|
|
#define DEFAULT_NUMBUFFERS 2
|
|
#define DEFAULT_BUFFERSIZE_MS 120
|
|
|
|
static HWAVEOUT hwaveout;
|
|
static WAVEHDR header[MAXBUFFERS];
|
|
static HPSTR buffer[MAXBUFFERS]; /* pointers to buffers */
|
|
static WORD buffersout; /* number of buffers playing/about to be played */
|
|
static WORD nextbuffer; /* next buffer to be mixed */
|
|
static ULONG buffersize; /* buffer size in bytes */
|
|
static ULONG buffersize_ms = DEFAULT_BUFFERSIZE_MS; /* configured buffer size in milliseconds */
|
|
static ULONG numbuffers = DEFAULT_NUMBUFFERS; /* configured number of buffers */
|
|
|
|
static void WIN_CommandLine(const CHAR *cmdline)
|
|
{
|
|
CHAR *ptr;
|
|
|
|
if((ptr = MD_GetAtom("buffer",cmdline,0)) != NULL) {
|
|
buffersize_ms = atoi(ptr);
|
|
if(buffersize_ms < MINBUFFERSIZE_MS || buffersize_ms > MAXBUFFERSIZE_MS)
|
|
buffersize_ms = DEFAULT_BUFFERSIZE_MS;
|
|
MikMod_free(ptr);
|
|
}
|
|
if((ptr = MD_GetAtom("count",cmdline,0)) != NULL) {
|
|
numbuffers = atoi(ptr);
|
|
if(numbuffers < MINBUFFERS || numbuffers > MAXBUFFERS)
|
|
numbuffers = DEFAULT_NUMBUFFERS;
|
|
MikMod_free(ptr);
|
|
}
|
|
}
|
|
|
|
/* converts Windows error to libmikmod error */
|
|
static int WIN_GetError(MMRESULT mmr)
|
|
{
|
|
switch (mmr) {
|
|
case MMSYSERR_INVALHANDLE:
|
|
return MMERR_WINMM_HANDLE;
|
|
case MMSYSERR_NODRIVER:
|
|
return MMERR_OPENING_AUDIO;
|
|
case MMSYSERR_NOMEM:
|
|
return MMERR_OUT_OF_MEMORY;
|
|
case MMSYSERR_ALLOCATED:
|
|
return MMERR_WINMM_ALLOCATED;
|
|
case MMSYSERR_BADDEVICEID:
|
|
return MMERR_WINMM_DEVICEID;
|
|
case WAVERR_BADFORMAT:
|
|
return MMERR_WINMM_FORMAT;
|
|
default:
|
|
return MMERR_WINMM_UNKNOWN; /* should hopefully not happen */
|
|
}
|
|
}
|
|
|
|
static BOOL WIN_IsThere(void)
|
|
{
|
|
return waveOutGetNumDevs()>0?1:0;
|
|
}
|
|
|
|
static void CALLBACK WIN_CallBack(HWAVEOUT hwo,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)
|
|
{
|
|
if (uMsg==WOM_DONE) --buffersout;
|
|
}
|
|
|
|
static int WIN_Init(void)
|
|
{
|
|
WAVEFORMATEX wfe;
|
|
WORD samplesize;
|
|
MMRESULT mmr;
|
|
int n;
|
|
|
|
samplesize=1;
|
|
if (md_mode&DMODE_STEREO) samplesize<<=1;
|
|
if (md_mode&DMODE_FLOAT) samplesize<<=2;
|
|
else if (md_mode&DMODE_16BITS) samplesize<<=1;
|
|
|
|
wfe.wFormatTag=(md_mode&DMODE_FLOAT)? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM;
|
|
wfe.nChannels=md_mode&DMODE_STEREO?2:1;
|
|
wfe.nSamplesPerSec=md_mixfreq;
|
|
wfe.nAvgBytesPerSec=md_mixfreq*samplesize;
|
|
wfe.nBlockAlign=samplesize;
|
|
wfe.wBitsPerSample=(md_mode&DMODE_FLOAT)?32:(md_mode&DMODE_16BITS)?16:8;
|
|
wfe.cbSize=sizeof(wfe);
|
|
|
|
mmr=waveOutOpen(&hwaveout,WAVE_MAPPER,&wfe,(DWORD_PTR)WIN_CallBack,0,CALLBACK_FUNCTION);
|
|
if (mmr!=MMSYSERR_NOERROR) {
|
|
_mm_errno=WIN_GetError(mmr);
|
|
return 1;
|
|
}
|
|
|
|
buffersize=md_mixfreq*samplesize*buffersize_ms/1000;
|
|
|
|
for (n=0;n<numbuffers;n++) {
|
|
buffer[n]=(HPSTR)MikMod_malloc(buffersize);
|
|
header[n].lpData=buffer[n];
|
|
header[n].dwBufferLength=buffersize;
|
|
mmr=waveOutPrepareHeader(hwaveout,&header[n],sizeof(WAVEHDR));
|
|
if (!buffer[n]||mmr!=MMSYSERR_NOERROR) {
|
|
if (!buffer[n])
|
|
_mm_errno=MMERR_OUT_OF_MEMORY;
|
|
else
|
|
_mm_errno=WIN_GetError(mmr);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
md_mode|=DMODE_SOFT_MUSIC|DMODE_SOFT_SNDFX;
|
|
#if defined HAVE_SSE2
|
|
/* This test only works on Windows XP or later */
|
|
if (IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
|
|
md_mode|=DMODE_SIMDMIXER;
|
|
}
|
|
#endif
|
|
buffersout=nextbuffer=0;
|
|
return VC_Init();
|
|
}
|
|
|
|
static void WIN_Exit(void)
|
|
{
|
|
int n;
|
|
|
|
VC_Exit();
|
|
if (hwaveout) {
|
|
for (n=0;n<numbuffers;n++) {
|
|
if (header[n].dwFlags&WHDR_PREPARED)
|
|
waveOutUnprepareHeader(hwaveout,&header[n],sizeof(WAVEHDR));
|
|
MikMod_free(buffer[n]);
|
|
buffer[n] = NULL;
|
|
}
|
|
while (waveOutClose(hwaveout)==WAVERR_STILLPLAYING) Sleep(10);
|
|
hwaveout=NULL;
|
|
}
|
|
}
|
|
|
|
static void WIN_Update(void)
|
|
{
|
|
ULONG done;
|
|
|
|
while (buffersout<numbuffers) {
|
|
done=VC_WriteBytes((SBYTE*)buffer[nextbuffer],buffersize);
|
|
if (!done) break;
|
|
header[nextbuffer].dwBufferLength=done;
|
|
waveOutWrite(hwaveout,&header[nextbuffer],sizeof(WAVEHDR));
|
|
if (++nextbuffer>=numbuffers) nextbuffer%=numbuffers;
|
|
++buffersout;
|
|
}
|
|
}
|
|
|
|
static void WIN_PlayStop(void)
|
|
{
|
|
if (hwaveout) waveOutReset(hwaveout);
|
|
VC_PlayStop();
|
|
}
|
|
|
|
MIKMODAPI MDRIVER drv_win={
|
|
NULL,
|
|
"Windows waveform-audio",
|
|
"Windows waveform-audio driver v0.2",
|
|
0,255,
|
|
"winmm",
|
|
"buffer:r:50,1000,120:Audio buffer size in milliseconds\n"
|
|
"count:r:2,16,2:Audio buffer count\n",
|
|
WIN_CommandLine,
|
|
WIN_IsThere,
|
|
VC_SampleLoad,
|
|
VC_SampleUnload,
|
|
VC_SampleSpace,
|
|
VC_SampleLength,
|
|
WIN_Init,
|
|
WIN_Exit,
|
|
NULL,
|
|
VC_SetNumVoices,
|
|
VC_PlayStart,
|
|
WIN_PlayStop,
|
|
WIN_Update,
|
|
NULL,
|
|
VC_VoiceSetVolume,
|
|
VC_VoiceGetVolume,
|
|
VC_VoiceSetFrequency,
|
|
VC_VoiceGetFrequency,
|
|
VC_VoiceSetPanning,
|
|
VC_VoiceGetPanning,
|
|
VC_VoicePlay,
|
|
VC_VoiceStop,
|
|
VC_VoiceStopped,
|
|
VC_VoiceGetPosition,
|
|
VC_VoiceRealVolume
|
|
};
|
|
|
|
#else
|
|
|
|
MISSING(drv_win);
|
|
|
|
#endif
|
|
|
|
/* ex:set ts=4: */
|