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.
261 lines
6.2 KiB
261 lines
6.2 KiB
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// |
|
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// |
|
/* |
|
This should work for OS/2 Dart |
|
|
|
History: |
|
1.0 - By Kevin Langman |
|
|
|
*/ |
|
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// |
|
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// |
|
|
|
#ifdef HAVE_CONFIG_H |
|
#include "config.h" |
|
#endif |
|
|
|
#include <stdlib.h> |
|
#include <unistd.h> |
|
#include <string.h> |
|
#include <sys/ioctl.h> |
|
#include <sys/types.h> |
|
#include <sys/stat.h> |
|
#include <fcntl.h> |
|
|
|
#define INCL_DOS |
|
#include <os2.h> |
|
#include <mcios2.h> |
|
#include <meerror.h> |
|
#include <os2medef.h> |
|
|
|
#include "common.h" |
|
#include "driver.h" |
|
#include "mixer.h" |
|
|
|
#define BUFFERCOUNT 4 |
|
#define BUF_MIN 8 |
|
#define BUF_MAX 32 |
|
|
|
static int init(struct context_data *); |
|
static int setaudio(struct xmp_options *); |
|
static void bufdump(struct context_data *, void *, int); |
|
static void shutdown(struct context_data *); |
|
|
|
static MCI_MIX_BUFFER MixBuffers[BUFFERCOUNT]; |
|
static MCI_MIXSETUP_PARMS MixSetupParms; |
|
static MCI_BUFFER_PARMS BufferParms; |
|
static MCI_GENERIC_PARMS GenericParms; |
|
|
|
static ULONG DeviceID = 0; |
|
static int bsize = 16; |
|
static short next = 2; |
|
static short ready = 1; |
|
|
|
static HMTX mutex; |
|
|
|
static void dummy() |
|
{ |
|
} |
|
|
|
static char *help[] = { |
|
"sharing={Y,N}", "Device Sharing (default is N)", |
|
"device=val", "OS/2 Audio Device (default is 0 auto-detect)", |
|
"buffer=val", "Audio buffer size (default is 16)", |
|
NULL |
|
}; |
|
|
|
struct xmp_drv_info drv_os2dart = { |
|
"dart", /* driver ID */ |
|
"OS/2 Direct Audio Realtime", /* driver description */ |
|
help, /* help */ |
|
init, /* init */ |
|
shutdown, /* shutdown */ |
|
dummy, /* starttimer */ |
|
dummy, /* flush */ |
|
bufdump, /* bufdump */ |
|
}; |
|
|
|
// Buffer update thread (created and called by DART) |
|
static LONG APIENTRY OS2_Dart_UpdateBuffers |
|
(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags) { |
|
|
|
if ((ulFlags == MIX_WRITE_COMPLETE) || |
|
((ulFlags == (MIX_WRITE_COMPLETE | MIX_STREAM_ERROR)) && |
|
(ulStatus == ERROR_DEVICE_UNDERRUN))) { |
|
DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT); |
|
ready++; |
|
DosReleaseMutexSem(mutex); |
|
} |
|
|
|
return (TRUE); |
|
} |
|
|
|
static int setaudio(struct xmp_options *o) |
|
{ |
|
char sharing = 0; |
|
int device = 0; |
|
int flags; |
|
int i; |
|
MCI_AMP_OPEN_PARMS AmpOpenParms; |
|
char *token, **parm; |
|
|
|
//printf( "In SetAudio...\n" ); |
|
|
|
parm_init(); |
|
chkparm1("sharing", sharing = *token); |
|
chkparm1("device", device = atoi(token)); |
|
chkparm1("buffer", bsize = strtoul(token, NULL, 0)); |
|
parm_end(); |
|
|
|
if ((bsize < BUF_MIN || bsize > BUF_MAX) && bsize != 0) { |
|
bsize = 16 * 1024; |
|
} else { |
|
bsize *= 1024; |
|
} |
|
|
|
//if( sharing < 1 || sharing > 0 ){ |
|
// sharing = 0; |
|
//} |
|
|
|
MixBuffers[0].pBuffer = NULL; /* marker */ |
|
memset(&GenericParms, 0, sizeof(MCI_GENERIC_PARMS)); |
|
|
|
/* open AMP device */ |
|
memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS)); |
|
AmpOpenParms.usDeviceID = 0; |
|
|
|
AmpOpenParms.pszDeviceType = |
|
(PSZ) MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX, (USHORT) device); |
|
|
|
flags = MCI_WAIT | MCI_OPEN_TYPE_ID; |
|
if (sharing == 'Y' || sharing == 'y') { |
|
flags = flags | MCI_OPEN_SHAREABLE; |
|
} |
|
|
|
if (mciSendCommand(0, MCI_OPEN, flags, |
|
(PVOID) & AmpOpenParms, 0) != MCIERR_SUCCESS) { |
|
return -1; |
|
} |
|
|
|
DeviceID = AmpOpenParms.usDeviceID; |
|
|
|
/* setup playback parameters */ |
|
memset(&MixSetupParms, 0, sizeof(MCI_MIXSETUP_PARMS)); |
|
|
|
MixSetupParms.ulBitsPerSample = o->resol; |
|
MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM; |
|
MixSetupParms.ulSamplesPerSec = o->freq; |
|
MixSetupParms.ulChannels = o->outfmt & XMP_FORMAT_MONO ? 1 : 2; |
|
MixSetupParms.ulFormatMode = MCI_PLAY; |
|
MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO; |
|
MixSetupParms.pmixEvent = OS2_Dart_UpdateBuffers; |
|
|
|
if (mciSendCommand(DeviceID, MCI_MIXSETUP, |
|
MCI_WAIT | MCI_MIXSETUP_INIT, |
|
(PVOID) & MixSetupParms, 0) != MCIERR_SUCCESS) { |
|
|
|
mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, |
|
(PVOID) & GenericParms, 0); |
|
return -1; |
|
} |
|
|
|
/* take in account the DART suggested buffer size... */ |
|
if (bsize == 0) { |
|
bsize = MixSetupParms.ulBufferSize; |
|
} |
|
//printf( "Dart Buffer Size = %d\n", bsize ); |
|
|
|
BufferParms.ulNumBuffers = BUFFERCOUNT; |
|
BufferParms.ulBufferSize = bsize; |
|
BufferParms.pBufList = MixBuffers; |
|
|
|
if (mciSendCommand(DeviceID, MCI_BUFFER, |
|
MCI_WAIT | MCI_ALLOCATE_MEMORY, |
|
(PVOID) & BufferParms, 0) != MCIERR_SUCCESS) { |
|
mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, |
|
(PVOID) & GenericParms, 0); |
|
return -1; |
|
} |
|
|
|
for (i = 0; i < BUFFERCOUNT; i++) { |
|
MixBuffers[i].ulBufferLength = bsize; |
|
} |
|
|
|
//MixBuffers[0].ulBufferLength = bsize; |
|
//MixBuffers[1].ulBufferLength = bsize; |
|
//MixBuffers[2].ulBufferLength = bsize; |
|
//MixBuffers[3].ulBufferLength = bsize; |
|
|
|
return 0; |
|
} |
|
|
|
static int init(struct context_data *ctx) |
|
{ |
|
//printf( "In Init...\n" ); |
|
|
|
if (setaudio(ctl) != 0) |
|
return XMP_ERR_DINIT; |
|
|
|
/* Start Playback */ |
|
//printf("Starting Playback!!\n"); |
|
memset(MixBuffers[0].pBuffer, /*32767 */ 0, bsize); |
|
memset(MixBuffers[1].pBuffer, /*32767 */ 0, bsize); |
|
MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, MixBuffers, 2); |
|
|
|
return 0; |
|
} |
|
|
|
/* Build and write one tick (one PAL frame or 1/50 s in standard vblank |
|
* timed mods) of audio data to the output device. |
|
*/ |
|
static void bufdump(struct context_data *ctx, void *b, int i) |
|
{ |
|
static int index = 0; |
|
|
|
//printf( "In BufDump...\n" ); |
|
|
|
if (index + i > bsize) { |
|
|
|
//printf("Next = %d, ready = %d\n", next, ready); |
|
|
|
do { |
|
DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT); |
|
if (ready != 0) { |
|
DosReleaseMutexSem(mutex); |
|
break; |
|
} |
|
DosReleaseMutexSem(mutex); |
|
DosSleep(20); |
|
} while (TRUE); |
|
|
|
MixBuffers[next].ulBufferLength = index; |
|
MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, |
|
&(MixBuffers[next]), 1); |
|
ready--; |
|
next++; |
|
index = 0; |
|
if (next == BUFFERCOUNT) { |
|
next = 0; |
|
} |
|
} |
|
memcpy(&((char *)MixBuffers[next].pBuffer)[index], b, i); |
|
index += i; |
|
|
|
} |
|
|
|
static void shutdown(struct context_data *ctx) |
|
{ |
|
//printf( "In ShutDown...\n" ); |
|
|
|
if (MixBuffers[0].pBuffer) { |
|
mciSendCommand(DeviceID, MCI_BUFFER, |
|
MCI_WAIT | MCI_DEALLOCATE_MEMORY, &BufferParms, |
|
0); |
|
MixBuffers[0].pBuffer = NULL; |
|
} |
|
if (DeviceID) { |
|
mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, |
|
(PVOID) & GenericParms, 0); |
|
DeviceID = 0; |
|
} |
|
}
|
|
|