You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
3.9 KiB
177 lines
3.9 KiB
/* Extended Module Player |
|
* Copyright (C) 1996-2012 Claudio Matsuoka and Hipolito Carraro Jr |
|
* |
|
* This file is part of the Extended Module Player and is distributed |
|
* under the terms of the GNU General Public License. See doc/COPYING |
|
* for more information. |
|
*/ |
|
|
|
/* |
|
* Based on Bjornar Henden's driver for Mikmod |
|
*/ |
|
#ifdef HAVE_CONFIG_H |
|
#include "config.h" |
|
#endif |
|
|
|
#include <windows.h> |
|
#include "common.h" |
|
#include "driver.h" |
|
#include "mixer.h" |
|
|
|
#define MAXBUFFERS 32 /* max number of buffers */ |
|
#define BUFFERSIZE 120 /* buffer size in ms */ |
|
|
|
static HWAVEOUT hwaveout; |
|
static WAVEHDR header[MAXBUFFERS]; |
|
static LPSTR buffer[MAXBUFFERS]; /* pointers to buffers */ |
|
static WORD freebuffer; /* */ |
|
static WORD nextbuffer; /* next buffer to be mixed */ |
|
static int num_buffers; |
|
|
|
static int init(struct context_data *); |
|
static void bufdump(struct context_data *, void *, int); |
|
static void deinit(struct context_data *); |
|
|
|
static void dummy() |
|
{ |
|
} |
|
|
|
static char *help[] = { |
|
"buffers=val", "Number of buffers (default 10)", |
|
NULL |
|
}; |
|
|
|
struct xmp_drv_info drv_win32 = { |
|
"win32", /* driver ID */ |
|
"Windows WinMM driver", /* driver description */ |
|
help, /* help */ |
|
init, /* init */ |
|
deinit, /* shutdown */ |
|
dummy, /* starttimer */ |
|
dummy, /* flush */ |
|
bufdump, /* bufdump */ |
|
}; |
|
|
|
static void show_error(int res) |
|
{ |
|
char *msg; |
|
|
|
switch (res) { |
|
case MMSYSERR_ALLOCATED: |
|
msg = "Device is already open"; |
|
break; |
|
case MMSYSERR_BADDEVICEID: |
|
msg = "Device is out of range"; |
|
break; |
|
case MMSYSERR_NODRIVER: |
|
msg = "No audio driver in this system"; |
|
break; |
|
case MMSYSERR_NOMEM: |
|
msg = "Unable to allocate sound memory"; |
|
break; |
|
case WAVERR_BADFORMAT: |
|
msg = "Audio format not supported"; |
|
break; |
|
case WAVERR_SYNC: |
|
msg = "The device is synchronous"; |
|
break; |
|
default: |
|
msg = "Unknown media error"; |
|
} |
|
|
|
fprintf(stderr, "Error: %s", msg); |
|
} |
|
|
|
static void CALLBACK wave_callback(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, |
|
DWORD dwParam1, DWORD dwParam2) |
|
{ |
|
if (uMsg == WOM_DONE) { |
|
freebuffer++; |
|
freebuffer %= num_buffers; |
|
} |
|
} |
|
|
|
static int init(struct context_data *ctx) |
|
{ |
|
struct xmp_options *o = &ctx->o; |
|
MMRESULT res; |
|
WAVEFORMATEX wfe; |
|
int i; |
|
char *token, **parm; |
|
|
|
num_buffers = 10; |
|
|
|
parm_init(); |
|
chkparm1("buffers", num_buffers = strtoul(token, NULL, 0)); |
|
parm_end(); |
|
|
|
if (num_buffers > MAXBUFFERS) |
|
num_buffers = MAXBUFFERS; |
|
|
|
if (!waveOutGetNumDevs()) |
|
return XMP_ERR_DINIT; |
|
|
|
wfe.wFormatTag = WAVE_FORMAT_PCM; |
|
wfe.wBitsPerSample = o->resol; |
|
wfe.nChannels = o->flags & XMP_FORMAT_MONO ? 1 : 2; |
|
wfe.nSamplesPerSec = o->freq; |
|
wfe.nAvgBytesPerSec = wfe.nSamplesPerSec * wfe.nChannels * |
|
wfe.wBitsPerSample / 8; |
|
wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample / 8; |
|
|
|
res = waveOutOpen(&hwaveout, WAVE_MAPPER, &wfe, (DWORD) wave_callback, |
|
0, CALLBACK_FUNCTION); |
|
|
|
if (res != MMSYSERR_NOERROR) { |
|
show_error(res); |
|
return XMP_ERR_DINIT; |
|
} |
|
|
|
waveOutReset(hwaveout); |
|
|
|
for (i = 0; i < num_buffers; i++) { |
|
buffer[i] = malloc(OUT_MAXLEN); |
|
header[i].lpData = buffer[i]; |
|
|
|
if (!buffer[i] || res != MMSYSERR_NOERROR) { |
|
show_error(res); |
|
return XMP_ERR_DINIT; |
|
} |
|
} |
|
|
|
freebuffer = nextbuffer = 0; |
|
|
|
return 0; |
|
} |
|
|
|
static void bufdump(struct context_data *ctx, void *b, int len) |
|
{ |
|
memcpy(buffer[nextbuffer], b, len); |
|
|
|
while ((nextbuffer + 1) % num_buffers == freebuffer) |
|
Sleep(10); |
|
|
|
header[nextbuffer].dwBufferLength = len; |
|
waveOutPrepareHeader(hwaveout, &header[nextbuffer], sizeof(WAVEHDR)); |
|
waveOutWrite(hwaveout, &header[nextbuffer], sizeof(WAVEHDR)); |
|
|
|
nextbuffer++; |
|
nextbuffer %= num_buffers; |
|
} |
|
|
|
static void deinit(struct context_data *ctx) |
|
{ |
|
int i; |
|
|
|
if (hwaveout) { |
|
for (i = 0; i < num_buffers; i++) { |
|
if (header[i].dwFlags & WHDR_PREPARED) |
|
waveOutUnprepareHeader(hwaveout, &header[i], |
|
sizeof(WAVEHDR)); |
|
free(buffer[i]); |
|
} |
|
while (waveOutClose(hwaveout) == WAVERR_STILLPLAYING) |
|
Sleep(10); |
|
hwaveout = NULL; |
|
} |
|
}
|
|
|