gps/GPSResources/tcpmp 0.73/mikmod/libmikmod/drivers/drv_dart.c

319 lines
8.2 KiB
C
Executable File

/* 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: drv_dart.c,v 1.2 2004/01/31 22:39:40 raph Exp $
Driver for output on OS/2 MMPM/2 using direct audio (DART)
==============================================================================*/
/*
Written by Miodrag Vallat <miod@mikmod.org>
Lots of improvements (basically made usable...) by Andrew Zabolotny
<bit@eltech.ru>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
#ifdef DRV_DART
#define INCL_DOS
#define INCL_OS2MM
#include <os2.h>
/* Prevent a warning: PPFN redefined */
#define PPFN _PPFN
#include <os2me.h>
#undef PPFN
#include <stdlib.h>
#include <string.h>
#define MAX_BUFFERCOUNT 8
static MCI_MIX_BUFFER MixBuffers[MAX_BUFFERCOUNT];
static MCI_MIXSETUP_PARMS MixSetupParms;
static MCI_BUFFER_PARMS BufferParms;
static ULONG DeviceIndex = 0; /* use default waveaudio device */
static ULONG BufferSize = (ULONG)-1; /* autodetect buffer size */
static ULONG BufferCount = 2; /* use two buffers */
static ULONG DeviceID = 0;
static void Dart_CommandLine(CHAR *cmdline)
{
char *ptr;
int buf;
if ((ptr = MD_GetAtom("buffer", cmdline, 0))) {
buf = atoi(ptr);
if (buf >= 12 && buf <= 16)
BufferSize = 1 << buf;
free(ptr);
}
if ((ptr = MD_GetAtom("count", cmdline, 0))) {
buf = atoi(ptr);
if (buf >= 2 && buf <= MAX_BUFFERCOUNT)
BufferCount = buf;
free(ptr);
}
if ((ptr = MD_GetAtom("device", cmdline, 0))) {
buf = atoi(ptr);
if (buf >= 0 && buf <= 8)
DeviceIndex = buf;
free(ptr);
}
}
/* Buffer update thread (created and called by DART)
This is a high-priority thread used to compute and update the audio stream,
automatically created by the DART subsystem. We compute the next audio
buffer and feed it to the waveaudio device. */
static LONG APIENTRY Dart_UpdateBuffers(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
{
/* sanity check */
if (!pBuffer)
return TRUE;
/* if we have finished a buffer, we're ready to play a new one */
if ((ulFlags == MIX_WRITE_COMPLETE) ||
((ulFlags == (MIX_WRITE_COMPLETE | MIX_STREAM_ERROR)) &&
(ulStatus == ERROR_DEVICE_UNDERRUN))) {
/* refill this audio buffer and feed it again */
MUTEX_LOCK(vars);
if (Player_Paused_internal())
pBuffer->ulBufferLength =
VC_SilenceBytes(pBuffer->pBuffer, BufferSize);
else
pBuffer->ulBufferLength =
VC_WriteBytes(pBuffer->pBuffer, BufferSize);
MUTEX_UNLOCK(vars);
MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, pBuffer, 1);
}
return TRUE;
}
static BOOL Dart_IsPresent(void)
{
MCI_AMP_OPEN_PARMS AmpOpenParms;
MCI_GENERIC_PARMS GenericParms;
memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS));
AmpOpenParms.pszDeviceType = (PSZ) MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX,
(USHORT) DeviceIndex);
if (mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_SHAREABLE | MCI_OPEN_TYPE_ID,
(PVOID) &AmpOpenParms, 0) != MCIERR_SUCCESS)
return 0;
mciSendCommand(AmpOpenParms.usDeviceID, MCI_CLOSE, MCI_WAIT,
(PVOID) &GenericParms, 0);
return 1;
}
static BOOL Dart_Init(void)
{
MCI_AMP_OPEN_PARMS AmpOpenParms;
MCI_GENERIC_PARMS GenericParms;
MixBuffers[0].pBuffer = NULL; /* marker */
DeviceID = 0;
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) DeviceIndex);
if (mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_SHAREABLE | MCI_OPEN_TYPE_ID,
(PVOID) & AmpOpenParms, 0) != MCIERR_SUCCESS) {
_mm_errno = MMERR_OPENING_AUDIO;
return 1;
}
DeviceID = AmpOpenParms.usDeviceID;
/* setup playback parameters */
memset(&MixSetupParms, 0, sizeof(MCI_MIXSETUP_PARMS));
MixSetupParms.ulBitsPerSample = (md_mode & DMODE_16BITS) ? 16 : 8;
MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM;
MixSetupParms.ulSamplesPerSec = md_mixfreq;
MixSetupParms.ulChannels = (md_mode & DMODE_STEREO) ? 2 : 1;
MixSetupParms.ulFormatMode = MCI_PLAY;
MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
MixSetupParms.pmixEvent = Dart_UpdateBuffers;
if (mciSendCommand(DeviceID, MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_INIT,
(PVOID) & MixSetupParms, 0) != MCIERR_SUCCESS) {
_mm_errno = MMERR_OS2_MIXSETUP;
return 1;
}
/* Compute audio buffer size now if necessary */
if (BufferSize == (ULONG)-1) {
/* DART suggested buffer size is somewhat too big. We compute a size
for circa 1/4" of playback. */
int bit;
BufferSize = md_mixfreq >> 2;
if (md_mode & DMODE_STEREO)
BufferSize <<= 1;
if (md_mode & DMODE_16BITS)
BufferSize <<= 1;
for (bit = 15; bit >= 12; bit--)
if (BufferSize & (1 << bit))
break;
BufferSize = (1 << bit);
}
/* make sure buffer is not greater than 64 Kb, as DART can't handle this
situation. */
if (BufferSize > 65536)
BufferSize = 65536;
BufferParms.ulStructLength = sizeof(BufferParms);
BufferParms.ulNumBuffers = BufferCount;
BufferParms.ulBufferSize = BufferSize;
BufferParms.pBufList = MixBuffers;
if (mciSendCommand(DeviceID, MCI_BUFFER,
MCI_WAIT | MCI_ALLOCATE_MEMORY,
(PVOID) &BufferParms, 0) != MCIERR_SUCCESS) {
_mm_errno = MMERR_OUT_OF_MEMORY;
return 1;
}
return VC_Init();
}
static void Dart_Exit(void)
{
MCI_GENERIC_PARMS GenericParms;
VC_Exit();
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;
}
}
static BOOL Dart_PlayStart(void)
{
MCI_GENERIC_PARMS GenericParms;
int i;
if (VC_PlayStart())
return 1;
/* silence buffers */
for (i = 0; i < BufferCount; i++) {
VC_SilenceBytes(MixBuffers[i].pBuffer, BufferSize);
MixBuffers[i].ulBufferLength = BufferSize;
}
/* grab exclusive rights to device instance (not entire device) */
GenericParms.hwndCallback = 0; /* Not needed, so set to 0 */
if (mciSendCommand(DeviceID, MCI_ACQUIREDEVICE, MCI_EXCLUSIVE_INSTANCE,
(PVOID) &GenericParms, 0) != MCIERR_SUCCESS) {
mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, (PVOID) &GenericParms, 0);
_mm_errno = MMERR_OPENING_AUDIO;
return 1;
}
/* wake DART up */
MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, MixBuffers, BufferCount);
return 0;
}
static void Dart_Update(void)
{
/* Nothing to do: everything is done in DART_UpdateBuffers() */
}
static void Dart_PlayStop(void)
{
MCI_GENERIC_PARMS GenericParms;
GenericParms.hwndCallback = 0;
mciSendCommand(DeviceID, MCI_STOP, MCI_WAIT, (PVOID) &GenericParms, 0);
VC_PlayStop();
}
MIKMODAPI MDRIVER drv_dart = {
NULL,
"Direct audio (DART)",
"OS/2 DART driver v1.2",
0, 255,
"dart",
"device:r:0,8,0:Waveaudio device index to use (0 - default)\n"
"buffer:r:12,16:Audio buffer log2 size\n"
"count:r:2,8,2:Number of audio buffers\n",
Dart_CommandLine,
Dart_IsPresent,
VC_SampleLoad,
VC_SampleUnload,
VC_SampleSpace,
VC_SampleLength,
Dart_Init,
Dart_Exit,
NULL,
VC_SetNumVoices,
Dart_PlayStart,
Dart_PlayStop,
Dart_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_dart);
#endif
/* ex:set ts=4: */